From 082b6216b38dce3d7a60edeb9e5de7817dc22dc5 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Mon, 23 Jun 2025 04:59:22 +0300 Subject: [PATCH] Update home menu branch (#759) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix typo (#680) Co-authored-by: Noumi <139501014+noumidev@users.noreply.github.com> * More PTM stuff Co-Authored-By: Noumi <139501014+noumidev@users.noreply.github.com> * Make system language configurable * Fix building crypto++ for x64 target on Apple silicon MacOS * Attempt to switch to M1 runners again * Prevent selecting Vulkan renderer in Qt frontend and present a message * Libretro: Add system language option * Only enable audio by default on libretro for now * CMake: Bump version * Store configuration file in AppData root if not in working directory (#693) * Store configuration file in AppData root if not in working directory This fixes MacOS app bundles, as the emulator cannot write the config file into the app bundle. * Remove duplicate fs calls * I'm an idiot sandwich --------- Co-authored-by: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> * GL: Add usingGLES to driverInfo struct (#694) * Wayland fixes part 1 * Support GLES on desktop * Qt: Fix Wayland support Qt will only create a Wayland surface when show() is called on the main window and on the ScreenWidget. Thus, call the function before creating the GL context. Doesn't cause regressions on XWayland, untested in other platforms. Fixes #586 * No need to call screen->show() twice * Fix disabling Wayland & building on some distros (#700) * GLES: Properly stub out logic ops * Fix git versioning * Android_Build: Implement ccache (#703) * Android_Build: Implement ccache * Update Android_Build.yml * Update Android_Build.yml --------- Co-authored-by: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> * Removed dead Citra link in readme (#706) * CRO: Lighter icache flushes * Implement Luma icache SVCs * Add missing SVC logs * GPU: Add sw texture copies * Use vk::detail::DynamicLoader instead of vk::DynamicLoader (#710) * Use vk::detail::DynamicLoader instead of vk::DynamicLoader * Update renderer_vk.cpp * Vk: Fix typo * Vk: Lock CI runners to SDK version 1.3.301 temporarily * Vk: Fixing CI pt 2 * Vulkan: Fixing CI pt 3 * Vk: Fix typo * Temporarily give 80MB to all processes (#715) * Try to cross-compile Libretro core for arm64 (#717) * Try to cross-compile Libretro core for arm64 * Bonk * Update Hydra_Build.yml * [WIP] Libretro: Add audio support (#714) * Libretro: Add audio support * Adding audio interface part 1 * Audio device pt 2 * More audio device * More audio device * Morea uudi odevice * More audio device * More audio device * More audio device --------- Co-authored-by: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> * Libretro audio device: Fix frame count * Mark audio devices as final * Add toggle for libretro audio device (#719) * Very important work (#720) * Very important work * Most important fix * Add more HLE service calls for eshop (#721) * CI: Fix Vulkan SDK action (#723) * GPU registers: Fix writes to some registers ignoring the mask (#725) Co-authored-by: henry <23128103+atem2069@users.noreply.github.com> * OLED theme * OLED theme config fix (#736) Co-authored-by: smiRaphi * Adding Swedish translation * Fix Metal renderer compilation on iOS * [Core] Improve iOS compilation workflow * [Qt] Hook Swedish to UI * AppDataDocumentProvider: Typo (#740) * More iOS work * More iOS progress * More iOS work * AppDataDocumentProvider: Add missing ``COLUMN_FLAGS`` in the default document projectation (#741) Fixes unable to copy files from device to app's internal storage problem * More iOS work * ios: Simplify MTKView interface (still doesn't work though) * ios: Pass CAMetalLayer instead of void* to Obj-C++ bridging header * Fix bridging cast * FINALLY IOS GRAPHICS * ios: Remove printf spam * Metal: Reimplement some texture formats on iOS * metal: implement texture decoder * metal: check for format support * metal: implement texture swizzling * metal: remove unused texture functions * Shadergen types: Add Metal & MSL * Format * Undo submodule changes * Readme: Add Chonkystation 3 * Metal: Use std::unique_ptr for texture decode * AppDataDocumentProvider: Allow to remove documents (#744) * AppDataDocumentProvider: Allow to remove documents * Typo * Metal renderer fixes for iOS * iOS driver: Add doc comments * iOS: Add frontend & frontend build files (#746) * iOS: Add SwiftUI part to repo * Add iOS build script * Update SDL2 submodule * Fix iOS build script * CI: Update xcode tools for iOS * Update iOS_Build.yml * Update iOS build * Lower XCode version * A * Update project.pbxproj * Update iOS_Build.yml * Update iOS_Build.yml * Update build.sh * iOS: Fail on build error * iOS: Add file picker (#747) * iOS: Add file picker * Fix lock placement * Qt: Add runpog icon (#752) * Update discord-rpc submodule (#753) * Remove cryptoppwin submodule (#754) * Add optional texture hashing * Fix build on new Vk SDK (#757) Co-authored-by: Nadia Holmquist Pedersen <893884+nadiaholmquist@users.noreply.github.com> * CI: Use new Vulkan SDK --------- Co-authored-by: Noumi <139501014+noumidev@users.noreply.github.com> Co-authored-by: Thomas Co-authored-by: Thomas Co-authored-by: Daniel López Guimaraes Co-authored-by: Jonian Guveli Co-authored-by: Ishan09811 <156402647+Ishan09811@users.noreply.github.com> Co-authored-by: Auxy6858 <71662994+Auxy6858@users.noreply.github.com> Co-authored-by: Paris Oplopoios Co-authored-by: henry <23128103+atem2069@users.noreply.github.com> Co-authored-by: smiRaphi Co-authored-by: smiRaphi <87574679+smiRaphi@users.noreply.github.com> Co-authored-by: Daniel Nylander Co-authored-by: Samuliak Co-authored-by: Albert <45282415+ggrtk@users.noreply.github.com> Co-authored-by: Nadia Holmquist Pedersen <893884+nadiaholmquist@users.noreply.github.com> --- .github/gles.patch | 22 - .github/workflows/Android_Build.yml | 14 +- .github/workflows/HTTP_Build.yml | 2 +- .github/workflows/Hydra_Build.yml | 43 +- .github/workflows/Linux_AppImage_Build.yml | 2 +- .github/workflows/Linux_Build.yml | 2 +- .github/workflows/MacOS_Build.yml | 6 +- .github/workflows/Qt_Build.yml | 10 +- .github/workflows/Windows_Build.yml | 2 +- .github/workflows/iOS_Build.yml | 39 + .gitmodules | 10 +- CMakeLists.txt | 130 +- docs/img/runpog_icon.png | Bin 0 -> 16804 bytes docs/translations/sv.ts | 774 ++++ include/PICA/shader_gen_types.hpp | 8 +- include/audio/audio_device.hpp | 9 + include/audio/audio_device_interface.hpp | 36 + include/audio/libretro_audio_device.hpp | 61 + include/audio/miniaudio_device.hpp | 24 +- include/config.hpp | 27 +- include/cpu_dynarmic.hpp | 2 + include/emulator.hpp | 8 +- include/frontend_settings.hpp | 2 + include/ios_driver.h | 7 + include/ipc.hpp | 2 +- include/kernel/handles.hpp | 8 +- include/kernel/kernel.hpp | 4 + include/kernel/resource_limits.hpp | 4 +- include/memory.hpp | 2 +- include/renderer.hpp | 13 + include/renderer_gl/gl_driver.hpp | 1 + include/renderer_gl/renderer_gl.hpp | 8 +- include/renderer_gl/textures.hpp | 84 +- include/renderer_mtl/mtl_render_target.hpp | 2 +- include/renderer_mtl/mtl_texture.hpp | 29 +- include/renderer_mtl/pica_to_mtl.hpp | 37 +- include/renderer_mtl/renderer_mtl.hpp | 11 +- include/renderer_mtl/texture_decoder.hpp | 24 + include/renderer_vk/vk_debug.hpp | 4 +- include/services/cfg.hpp | 13 +- include/services/gsp_gpu.hpp | 2 +- include/services/gsp_lcd.hpp | 3 - include/services/ns.hpp | 22 +- readme.md | 7 +- src/config.cpp | 46 +- src/core/PICA/regs.cpp | 12 +- src/core/audio/miniaudio_device.cpp | 7 +- src/core/kernel/kernel.cpp | 21 + src/core/kernel/memory_management.cpp | 10 +- src/core/renderer_gl/renderer_gl.cpp | 79 +- src/core/renderer_mtl/mtl_etc1.cpp | 116 - src/core/renderer_mtl/mtl_texture.cpp | 223 +- src/core/renderer_mtl/pica_to_mtl.cpp | 62 + src/core/renderer_mtl/renderer_mtl.cpp | 36 +- src/core/renderer_mtl/texture_decoder.cpp | 334 ++ src/core/renderer_vk/renderer_vk.cpp | 11 +- src/core/renderer_vk/vk_debug.cpp | 6 +- src/core/services/ac.cpp | 6 +- src/core/services/apt.cpp | 2 +- src/core/services/boss.cpp | 22 +- src/core/services/cfg.cpp | 148 +- src/core/services/gsp_gpu.cpp | 83 +- src/core/services/gsp_lcd.cpp | 1 + src/core/services/http.cpp | 6 +- src/core/services/ldr_ro.cpp | 17 +- src/core/services/ptm.cpp | 3 +- src/core/services/service_manager.cpp | 4 + src/emulator.cpp | 21 +- src/frontend_settings.cpp | 6 +- src/host_shaders/metal_shaders.metal | 29 +- src/host_shaders/opengl_es_display.frag | 10 + src/host_shaders/opengl_es_display.vert | 25 + src/hydra_core.cpp | 1 + src/ios_driver.mm | 38 + src/jni_driver.cpp | 2 +- src/libretro_core.cpp | 33 +- src/{ => miniaudio}/miniaudio.cpp | 4 +- src/miniaudio/miniaudio.m | 8 + src/panda_qt/config_window.cpp | 77 +- src/panda_qt/main.cpp | 1 - src/panda_qt/main_window.cpp | 9 +- src/panda_qt/screen.cpp | 12 +- src/panda_qt/translations.cpp | 5 +- src/panda_sdl/frontend_sdl.cpp | 24 +- src/pandios/.gitignore | 2 + src/pandios/Alber/Headers/ios_driver.h | 7 + src/pandios/Alber/module.map | 5 + src/pandios/Pandios.xcodeproj/project.pbxproj | 587 +++ .../contents.xcworkspacedata | 7 + .../UserInterfaceState.xcuserstate | Bin 0 -> 763693 bytes .../xcschemes/xcschememanagement.plist | 14 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 35 + .../Pandios/Assets.xcassets/Contents.json | 6 + src/pandios/Pandios/ContentView.swift | 95 + src/pandios/Pandios/DocumentPicker.swift | 75 + src/pandios/Pandios/PandiosApp.swift | 11 + .../Preview Assets.xcassets/Contents.json | 6 + src/pandios/build.sh | 37 + .../app/provider/AppDataDocumentProvider.java | 10 +- src/renderer.cpp | 38 + third_party/SDL2 | 2 +- third_party/cryptopp/CMakeLists.txt | 5 +- third_party/cryptoppwin | 1 - third_party/cryptoppwin/CMakeLists.txt | 7 + third_party/cryptoppwin/README.md | 7 + .../cryptoppwin/include/cryptopp/3way.h | 63 + .../cryptoppwin/include/cryptopp/adler32.h | 33 + .../cryptoppwin/include/cryptopp/adv_simd.h | 1281 +++++++ .../cryptoppwin/include/cryptopp/aes.h | 30 + .../cryptoppwin/include/cryptopp/aes_armv4.h | 30 + .../cryptoppwin/include/cryptopp/algebra.h | 453 +++ .../cryptoppwin/include/cryptopp/algparam.h | 520 +++ .../cryptoppwin/include/cryptopp/allocate.h | 74 + .../cryptoppwin/include/cryptopp/arc4.h | 89 + .../cryptoppwin/include/cryptopp/argnames.h | 99 + .../cryptoppwin/include/cryptopp/aria.h | 71 + .../cryptoppwin/include/cryptopp/arm_simd.h | 427 +++ .../cryptoppwin/include/cryptopp/asn.h | 974 +++++ .../cryptoppwin/include/cryptopp/authenc.h | 87 + .../cryptoppwin/include/cryptopp/base32.h | 158 + .../cryptoppwin/include/cryptopp/base64.h | 158 + .../cryptoppwin/include/cryptopp/basecode.h | 146 + .../cryptoppwin/include/cryptopp/bench.h | 105 + .../cryptoppwin/include/cryptopp/blake2.h | 444 +++ .../cryptoppwin/include/cryptopp/blowfish.h | 54 + .../cryptoppwin/include/cryptopp/blumshub.h | 70 + .../cryptoppwin/include/cryptopp/camellia.h | 49 + .../cryptoppwin/include/cryptopp/cast.h | 109 + .../cryptoppwin/include/cryptopp/cbcmac.h | 63 + .../cryptoppwin/include/cryptopp/ccm.h | 123 + .../cryptoppwin/include/cryptopp/chacha.h | 223 ++ .../cryptoppwin/include/cryptopp/chachapoly.h | 322 ++ .../cryptoppwin/include/cryptopp/cham.h | 179 + .../cryptoppwin/include/cryptopp/channels.h | 142 + .../cryptoppwin/include/cryptopp/cmac.h | 76 + .../cryptoppwin/include/cryptopp/config.h | 33 + .../include/cryptopp/config_align.h | 72 + .../cryptoppwin/include/cryptopp/config_asm.h | 492 +++ .../cryptoppwin/include/cryptopp/config_cpu.h | 212 ++ .../cryptoppwin/include/cryptopp/config_cxx.h | 250 ++ .../cryptoppwin/include/cryptopp/config_dll.h | 178 + .../cryptoppwin/include/cryptopp/config_int.h | 268 ++ .../include/cryptopp/config_misc.h | 199 + .../cryptoppwin/include/cryptopp/config_ns.h | 76 + .../cryptoppwin/include/cryptopp/config_os.h | 168 + .../cryptoppwin/include/cryptopp/config_ver.h | 98 + .../cryptoppwin/include/cryptopp/cpu.h | 1089 ++++++ .../cryptoppwin/include/cryptopp/crc.h | 90 + .../cryptoppwin/include/cryptopp/cryptlib.h | 3384 +++++++++++++++++ .../cryptoppwin/include/cryptopp/darn.h | 95 + .../cryptoppwin/include/cryptopp/default.h | 310 ++ .../cryptoppwin/include/cryptopp/des.h | 163 + third_party/cryptoppwin/include/cryptopp/dh.h | 275 ++ .../cryptoppwin/include/cryptopp/dh2.h | 70 + .../cryptoppwin/include/cryptopp/dll.h | 71 + .../cryptoppwin/include/cryptopp/dmac.h | 114 + .../cryptoppwin/include/cryptopp/donna.h | 179 + .../cryptoppwin/include/cryptopp/donna_32.h | 411 ++ .../cryptoppwin/include/cryptopp/donna_64.h | 457 +++ .../cryptoppwin/include/cryptopp/donna_sse.h | 86 + .../cryptoppwin/include/cryptopp/drbg.h | 718 ++++ .../cryptoppwin/include/cryptopp/dsa.h | 53 + .../cryptoppwin/include/cryptopp/eax.h | 112 + .../cryptoppwin/include/cryptopp/ec2n.h | 136 + .../cryptoppwin/include/cryptopp/eccrypto.h | 686 ++++ .../cryptoppwin/include/cryptopp/ecp.h | 167 + .../cryptoppwin/include/cryptopp/ecpoint.h | 146 + .../cryptoppwin/include/cryptopp/elgamal.h | 308 ++ .../cryptoppwin/include/cryptopp/emsa2.h | 101 + .../cryptoppwin/include/cryptopp/eprecomp.h | 162 + .../cryptoppwin/include/cryptopp/esign.h | 169 + .../cryptoppwin/include/cryptopp/factory.h | 179 + .../cryptoppwin/include/cryptopp/fhmqv.h | 408 ++ .../cryptoppwin/include/cryptopp/files.h | 181 + .../cryptoppwin/include/cryptopp/filters.h | 1529 ++++++++ .../cryptoppwin/include/cryptopp/fips140.h | 112 + .../cryptoppwin/include/cryptopp/fltrimpl.h | 69 + .../cryptoppwin/include/cryptopp/gcm.h | 139 + .../cryptoppwin/include/cryptopp/gf256.h | 72 + .../cryptoppwin/include/cryptopp/gf2_32.h | 73 + .../cryptoppwin/include/cryptopp/gf2n.h | 406 ++ .../cryptoppwin/include/cryptopp/gfpcrypt.h | 1036 +++++ .../cryptoppwin/include/cryptopp/gost.h | 66 + .../cryptoppwin/include/cryptopp/gzip.h | 144 + .../cryptoppwin/include/cryptopp/hashfwd.h | 38 + .../cryptoppwin/include/cryptopp/hc128.h | 67 + .../cryptoppwin/include/cryptopp/hc256.h | 69 + .../cryptoppwin/include/cryptopp/hex.h | 50 + .../cryptoppwin/include/cryptopp/hight.h | 81 + .../cryptoppwin/include/cryptopp/hkdf.h | 179 + .../cryptoppwin/include/cryptopp/hmac.h | 80 + .../cryptoppwin/include/cryptopp/hmqv.h | 417 ++ .../cryptoppwin/include/cryptopp/hrtimer.h | 134 + .../cryptoppwin/include/cryptopp/ida.h | 182 + .../cryptoppwin/include/cryptopp/idea.h | 66 + .../cryptoppwin/include/cryptopp/integer.h | 840 ++++ .../cryptoppwin/include/cryptopp/iterhash.h | 218 ++ .../cryptoppwin/include/cryptopp/kalyna.h | 218 ++ .../cryptoppwin/include/cryptopp/keccak.h | 118 + .../cryptoppwin/include/cryptopp/lea.h | 108 + .../cryptoppwin/include/cryptopp/lsh.h | 262 ++ .../cryptoppwin/include/cryptopp/lubyrack.h | 137 + .../cryptoppwin/include/cryptopp/luc.h | 338 ++ .../cryptoppwin/include/cryptopp/mars.h | 60 + .../cryptoppwin/include/cryptopp/md2.h | 56 + .../cryptoppwin/include/cryptopp/md4.h | 35 + .../cryptoppwin/include/cryptopp/md5.h | 35 + .../cryptoppwin/include/cryptopp/mdc.h | 84 + .../cryptoppwin/include/cryptopp/mersenne.h | 231 ++ .../cryptoppwin/include/cryptopp/misc.h | 3222 ++++++++++++++++ .../cryptoppwin/include/cryptopp/modarith.h | 344 ++ .../cryptoppwin/include/cryptopp/modes.h | 609 +++ .../cryptoppwin/include/cryptopp/modexppc.h | 48 + .../cryptoppwin/include/cryptopp/mqueue.h | 145 + .../cryptoppwin/include/cryptopp/mqv.h | 268 ++ .../cryptoppwin/include/cryptopp/naclite.h | 438 +++ .../cryptoppwin/include/cryptopp/nbtheory.h | 320 ++ third_party/cryptoppwin/include/cryptopp/nr.h | 11 + .../cryptoppwin/include/cryptopp/oaep.h | 54 + .../cryptoppwin/include/cryptopp/oids.h | 197 + .../cryptoppwin/include/cryptopp/osrng.h | 304 ++ .../cryptoppwin/include/cryptopp/ossig.h | 128 + .../cryptoppwin/include/cryptopp/padlkrng.h | 138 + .../cryptoppwin/include/cryptopp/panama.h | 169 + .../cryptoppwin/include/cryptopp/pch.h | 31 + .../cryptoppwin/include/cryptopp/pkcspad.h | 123 + .../cryptoppwin/include/cryptopp/poly1305.h | 241 ++ .../cryptoppwin/include/cryptopp/polynomi.h | 463 +++ .../cryptoppwin/include/cryptopp/ppc_simd.h | 2764 ++++++++++++++ .../cryptoppwin/include/cryptopp/pssr.h | 105 + .../cryptoppwin/include/cryptopp/pubkey.h | 2378 ++++++++++++ .../cryptoppwin/include/cryptopp/pwdbased.h | 481 +++ .../cryptoppwin/include/cryptopp/queue.h | 272 ++ .../cryptoppwin/include/cryptopp/rabbit.h | 112 + .../cryptoppwin/include/cryptopp/rabin.h | 135 + .../cryptoppwin/include/cryptopp/randpool.h | 104 + .../cryptoppwin/include/cryptopp/rc2.h | 90 + .../cryptoppwin/include/cryptopp/rc5.h | 59 + .../cryptoppwin/include/cryptopp/rc6.h | 60 + .../cryptoppwin/include/cryptopp/rdrand.h | 145 + .../cryptoppwin/include/cryptopp/resource.h | 15 + .../cryptoppwin/include/cryptopp/rijndael.h | 109 + .../cryptoppwin/include/cryptopp/ripemd.h | 65 + .../cryptoppwin/include/cryptopp/rng.h | 111 + .../cryptoppwin/include/cryptopp/rsa.h | 288 ++ third_party/cryptoppwin/include/cryptopp/rw.h | 146 + .../cryptoppwin/include/cryptopp/safer.h | 98 + .../cryptoppwin/include/cryptopp/salsa.h | 104 + .../cryptoppwin/include/cryptopp/scrypt.h | 103 + .../cryptoppwin/include/cryptopp/seal.h | 59 + .../cryptoppwin/include/cryptopp/secblock.h | 1310 +++++++ .../include/cryptopp/secblockfwd.h | 29 + .../cryptoppwin/include/cryptopp/seckey.h | 444 +++ .../cryptoppwin/include/cryptopp/seed.h | 44 + .../cryptoppwin/include/cryptopp/serpent.h | 72 + .../cryptoppwin/include/cryptopp/serpentp.h | 439 +++ .../cryptoppwin/include/cryptopp/sha.h | 210 + .../cryptoppwin/include/cryptopp/sha1_armv4.h | 23 + .../include/cryptopp/sha256_armv4.h | 23 + .../cryptoppwin/include/cryptopp/sha3.h | 106 + .../include/cryptopp/sha512_armv4.h | 23 + .../cryptoppwin/include/cryptopp/shacal2.h | 66 + .../cryptoppwin/include/cryptopp/shake.h | 161 + .../cryptoppwin/include/cryptopp/shark.h | 77 + .../cryptoppwin/include/cryptopp/simeck.h | 162 + .../cryptoppwin/include/cryptopp/simon.h | 206 + .../cryptoppwin/include/cryptopp/simple.h | 506 +++ .../cryptoppwin/include/cryptopp/siphash.h | 314 ++ .../cryptoppwin/include/cryptopp/skipjack.h | 80 + .../cryptoppwin/include/cryptopp/sm3.h | 61 + .../cryptoppwin/include/cryptopp/sm4.h | 96 + .../cryptoppwin/include/cryptopp/smartptr.h | 257 ++ .../cryptoppwin/include/cryptopp/sosemanuk.h | 62 + .../cryptoppwin/include/cryptopp/speck.h | 206 + .../cryptoppwin/include/cryptopp/square.h | 63 + .../cryptoppwin/include/cryptopp/stdcpp.h | 101 + .../cryptoppwin/include/cryptopp/strciphr.h | 737 ++++ .../cryptoppwin/include/cryptopp/tea.h | 161 + .../cryptoppwin/include/cryptopp/threefish.h | 201 + .../cryptoppwin/include/cryptopp/tiger.h | 61 + .../cryptoppwin/include/cryptopp/trap.h | 163 + .../cryptoppwin/include/cryptopp/trunhash.h | 63 + .../cryptoppwin/include/cryptopp/ttmac.h | 44 + .../cryptoppwin/include/cryptopp/tweetnacl.h | 281 ++ .../cryptoppwin/include/cryptopp/twofish.h | 64 + .../cryptoppwin/include/cryptopp/validate.h | 395 ++ .../cryptoppwin/include/cryptopp/vmac.h | 91 + .../cryptoppwin/include/cryptopp/wake.h | 59 + .../cryptoppwin/include/cryptopp/whrlpool.h | 42 + .../cryptoppwin/include/cryptopp/words.h | 225 ++ .../cryptoppwin/include/cryptopp/xed25519.h | 825 ++++ .../cryptoppwin/include/cryptopp/xtr.h | 219 ++ .../cryptoppwin/include/cryptopp/xtrcrypt.h | 55 + .../cryptoppwin/include/cryptopp/xts.h | 224 ++ .../cryptoppwin/include/cryptopp/zdeflate.h | 174 + .../cryptoppwin/include/cryptopp/zinflate.h | 164 + .../cryptoppwin/include/cryptopp/zlib.h | 65 + third_party/cryptoppwin/lib/cryptlib.lib | Bin 0 -> 17818586 bytes third_party/cryptoppwin/lib/cryptlibd.lib | Bin 0 -> 45142580 bytes third_party/discord-rpc | 2 +- third_party/ios_toolchain/ios.toolchain.cmake | 945 +++++ 302 files changed, 55525 insertions(+), 747 deletions(-) create mode 100644 .github/workflows/iOS_Build.yml create mode 100644 docs/img/runpog_icon.png create mode 100644 docs/translations/sv.ts create mode 100644 include/audio/audio_device.hpp create mode 100644 include/audio/audio_device_interface.hpp create mode 100644 include/audio/libretro_audio_device.hpp create mode 100644 include/ios_driver.h create mode 100644 include/renderer_mtl/texture_decoder.hpp delete mode 100644 src/core/renderer_mtl/mtl_etc1.cpp create mode 100644 src/core/renderer_mtl/pica_to_mtl.cpp create mode 100644 src/core/renderer_mtl/texture_decoder.cpp create mode 100644 src/host_shaders/opengl_es_display.frag create mode 100644 src/host_shaders/opengl_es_display.vert create mode 100644 src/ios_driver.mm rename src/{ => miniaudio}/miniaudio.cpp (82%) create mode 100644 src/miniaudio/miniaudio.m create mode 100644 src/pandios/.gitignore create mode 100644 src/pandios/Alber/Headers/ios_driver.h create mode 100644 src/pandios/Alber/module.map create mode 100644 src/pandios/Pandios.xcodeproj/project.pbxproj create mode 100644 src/pandios/Pandios.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 src/pandios/Pandios.xcodeproj/project.xcworkspace/xcuserdata/giorgos.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 src/pandios/Pandios.xcodeproj/xcuserdata/giorgos.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 src/pandios/Pandios/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 src/pandios/Pandios/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 src/pandios/Pandios/Assets.xcassets/Contents.json create mode 100644 src/pandios/Pandios/ContentView.swift create mode 100644 src/pandios/Pandios/DocumentPicker.swift create mode 100644 src/pandios/Pandios/PandiosApp.swift create mode 100644 src/pandios/Pandios/Preview Content/Preview Assets.xcassets/Contents.json create mode 100755 src/pandios/build.sh delete mode 160000 third_party/cryptoppwin create mode 100644 third_party/cryptoppwin/CMakeLists.txt create mode 100644 third_party/cryptoppwin/README.md create mode 100644 third_party/cryptoppwin/include/cryptopp/3way.h create mode 100644 third_party/cryptoppwin/include/cryptopp/adler32.h create mode 100644 third_party/cryptoppwin/include/cryptopp/adv_simd.h create mode 100644 third_party/cryptoppwin/include/cryptopp/aes.h create mode 100644 third_party/cryptoppwin/include/cryptopp/aes_armv4.h create mode 100644 third_party/cryptoppwin/include/cryptopp/algebra.h create mode 100644 third_party/cryptoppwin/include/cryptopp/algparam.h create mode 100644 third_party/cryptoppwin/include/cryptopp/allocate.h create mode 100644 third_party/cryptoppwin/include/cryptopp/arc4.h create mode 100644 third_party/cryptoppwin/include/cryptopp/argnames.h create mode 100644 third_party/cryptoppwin/include/cryptopp/aria.h create mode 100644 third_party/cryptoppwin/include/cryptopp/arm_simd.h create mode 100644 third_party/cryptoppwin/include/cryptopp/asn.h create mode 100644 third_party/cryptoppwin/include/cryptopp/authenc.h create mode 100644 third_party/cryptoppwin/include/cryptopp/base32.h create mode 100644 third_party/cryptoppwin/include/cryptopp/base64.h create mode 100644 third_party/cryptoppwin/include/cryptopp/basecode.h create mode 100644 third_party/cryptoppwin/include/cryptopp/bench.h create mode 100644 third_party/cryptoppwin/include/cryptopp/blake2.h create mode 100644 third_party/cryptoppwin/include/cryptopp/blowfish.h create mode 100644 third_party/cryptoppwin/include/cryptopp/blumshub.h create mode 100644 third_party/cryptoppwin/include/cryptopp/camellia.h create mode 100644 third_party/cryptoppwin/include/cryptopp/cast.h create mode 100644 third_party/cryptoppwin/include/cryptopp/cbcmac.h create mode 100644 third_party/cryptoppwin/include/cryptopp/ccm.h create mode 100644 third_party/cryptoppwin/include/cryptopp/chacha.h create mode 100644 third_party/cryptoppwin/include/cryptopp/chachapoly.h create mode 100644 third_party/cryptoppwin/include/cryptopp/cham.h create mode 100644 third_party/cryptoppwin/include/cryptopp/channels.h create mode 100644 third_party/cryptoppwin/include/cryptopp/cmac.h create mode 100644 third_party/cryptoppwin/include/cryptopp/config.h create mode 100644 third_party/cryptoppwin/include/cryptopp/config_align.h create mode 100644 third_party/cryptoppwin/include/cryptopp/config_asm.h create mode 100644 third_party/cryptoppwin/include/cryptopp/config_cpu.h create mode 100644 third_party/cryptoppwin/include/cryptopp/config_cxx.h create mode 100644 third_party/cryptoppwin/include/cryptopp/config_dll.h create mode 100644 third_party/cryptoppwin/include/cryptopp/config_int.h create mode 100644 third_party/cryptoppwin/include/cryptopp/config_misc.h create mode 100644 third_party/cryptoppwin/include/cryptopp/config_ns.h create mode 100644 third_party/cryptoppwin/include/cryptopp/config_os.h create mode 100644 third_party/cryptoppwin/include/cryptopp/config_ver.h create mode 100644 third_party/cryptoppwin/include/cryptopp/cpu.h create mode 100644 third_party/cryptoppwin/include/cryptopp/crc.h create mode 100644 third_party/cryptoppwin/include/cryptopp/cryptlib.h create mode 100644 third_party/cryptoppwin/include/cryptopp/darn.h create mode 100644 third_party/cryptoppwin/include/cryptopp/default.h create mode 100644 third_party/cryptoppwin/include/cryptopp/des.h create mode 100644 third_party/cryptoppwin/include/cryptopp/dh.h create mode 100644 third_party/cryptoppwin/include/cryptopp/dh2.h create mode 100644 third_party/cryptoppwin/include/cryptopp/dll.h create mode 100644 third_party/cryptoppwin/include/cryptopp/dmac.h create mode 100644 third_party/cryptoppwin/include/cryptopp/donna.h create mode 100644 third_party/cryptoppwin/include/cryptopp/donna_32.h create mode 100644 third_party/cryptoppwin/include/cryptopp/donna_64.h create mode 100644 third_party/cryptoppwin/include/cryptopp/donna_sse.h create mode 100644 third_party/cryptoppwin/include/cryptopp/drbg.h create mode 100644 third_party/cryptoppwin/include/cryptopp/dsa.h create mode 100644 third_party/cryptoppwin/include/cryptopp/eax.h create mode 100644 third_party/cryptoppwin/include/cryptopp/ec2n.h create mode 100644 third_party/cryptoppwin/include/cryptopp/eccrypto.h create mode 100644 third_party/cryptoppwin/include/cryptopp/ecp.h create mode 100644 third_party/cryptoppwin/include/cryptopp/ecpoint.h create mode 100644 third_party/cryptoppwin/include/cryptopp/elgamal.h create mode 100644 third_party/cryptoppwin/include/cryptopp/emsa2.h create mode 100644 third_party/cryptoppwin/include/cryptopp/eprecomp.h create mode 100644 third_party/cryptoppwin/include/cryptopp/esign.h create mode 100644 third_party/cryptoppwin/include/cryptopp/factory.h create mode 100644 third_party/cryptoppwin/include/cryptopp/fhmqv.h create mode 100644 third_party/cryptoppwin/include/cryptopp/files.h create mode 100644 third_party/cryptoppwin/include/cryptopp/filters.h create mode 100644 third_party/cryptoppwin/include/cryptopp/fips140.h create mode 100644 third_party/cryptoppwin/include/cryptopp/fltrimpl.h create mode 100644 third_party/cryptoppwin/include/cryptopp/gcm.h create mode 100644 third_party/cryptoppwin/include/cryptopp/gf256.h create mode 100644 third_party/cryptoppwin/include/cryptopp/gf2_32.h create mode 100644 third_party/cryptoppwin/include/cryptopp/gf2n.h create mode 100644 third_party/cryptoppwin/include/cryptopp/gfpcrypt.h create mode 100644 third_party/cryptoppwin/include/cryptopp/gost.h create mode 100644 third_party/cryptoppwin/include/cryptopp/gzip.h create mode 100644 third_party/cryptoppwin/include/cryptopp/hashfwd.h create mode 100644 third_party/cryptoppwin/include/cryptopp/hc128.h create mode 100644 third_party/cryptoppwin/include/cryptopp/hc256.h create mode 100644 third_party/cryptoppwin/include/cryptopp/hex.h create mode 100644 third_party/cryptoppwin/include/cryptopp/hight.h create mode 100644 third_party/cryptoppwin/include/cryptopp/hkdf.h create mode 100644 third_party/cryptoppwin/include/cryptopp/hmac.h create mode 100644 third_party/cryptoppwin/include/cryptopp/hmqv.h create mode 100644 third_party/cryptoppwin/include/cryptopp/hrtimer.h create mode 100644 third_party/cryptoppwin/include/cryptopp/ida.h create mode 100644 third_party/cryptoppwin/include/cryptopp/idea.h create mode 100644 third_party/cryptoppwin/include/cryptopp/integer.h create mode 100644 third_party/cryptoppwin/include/cryptopp/iterhash.h create mode 100644 third_party/cryptoppwin/include/cryptopp/kalyna.h create mode 100644 third_party/cryptoppwin/include/cryptopp/keccak.h create mode 100644 third_party/cryptoppwin/include/cryptopp/lea.h create mode 100644 third_party/cryptoppwin/include/cryptopp/lsh.h create mode 100644 third_party/cryptoppwin/include/cryptopp/lubyrack.h create mode 100644 third_party/cryptoppwin/include/cryptopp/luc.h create mode 100644 third_party/cryptoppwin/include/cryptopp/mars.h create mode 100644 third_party/cryptoppwin/include/cryptopp/md2.h create mode 100644 third_party/cryptoppwin/include/cryptopp/md4.h create mode 100644 third_party/cryptoppwin/include/cryptopp/md5.h create mode 100644 third_party/cryptoppwin/include/cryptopp/mdc.h create mode 100644 third_party/cryptoppwin/include/cryptopp/mersenne.h create mode 100644 third_party/cryptoppwin/include/cryptopp/misc.h create mode 100644 third_party/cryptoppwin/include/cryptopp/modarith.h create mode 100644 third_party/cryptoppwin/include/cryptopp/modes.h create mode 100644 third_party/cryptoppwin/include/cryptopp/modexppc.h create mode 100644 third_party/cryptoppwin/include/cryptopp/mqueue.h create mode 100644 third_party/cryptoppwin/include/cryptopp/mqv.h create mode 100644 third_party/cryptoppwin/include/cryptopp/naclite.h create mode 100644 third_party/cryptoppwin/include/cryptopp/nbtheory.h create mode 100644 third_party/cryptoppwin/include/cryptopp/nr.h create mode 100644 third_party/cryptoppwin/include/cryptopp/oaep.h create mode 100644 third_party/cryptoppwin/include/cryptopp/oids.h create mode 100644 third_party/cryptoppwin/include/cryptopp/osrng.h create mode 100644 third_party/cryptoppwin/include/cryptopp/ossig.h create mode 100644 third_party/cryptoppwin/include/cryptopp/padlkrng.h create mode 100644 third_party/cryptoppwin/include/cryptopp/panama.h create mode 100644 third_party/cryptoppwin/include/cryptopp/pch.h create mode 100644 third_party/cryptoppwin/include/cryptopp/pkcspad.h create mode 100644 third_party/cryptoppwin/include/cryptopp/poly1305.h create mode 100644 third_party/cryptoppwin/include/cryptopp/polynomi.h create mode 100644 third_party/cryptoppwin/include/cryptopp/ppc_simd.h create mode 100644 third_party/cryptoppwin/include/cryptopp/pssr.h create mode 100644 third_party/cryptoppwin/include/cryptopp/pubkey.h create mode 100644 third_party/cryptoppwin/include/cryptopp/pwdbased.h create mode 100644 third_party/cryptoppwin/include/cryptopp/queue.h create mode 100644 third_party/cryptoppwin/include/cryptopp/rabbit.h create mode 100644 third_party/cryptoppwin/include/cryptopp/rabin.h create mode 100644 third_party/cryptoppwin/include/cryptopp/randpool.h create mode 100644 third_party/cryptoppwin/include/cryptopp/rc2.h create mode 100644 third_party/cryptoppwin/include/cryptopp/rc5.h create mode 100644 third_party/cryptoppwin/include/cryptopp/rc6.h create mode 100644 third_party/cryptoppwin/include/cryptopp/rdrand.h create mode 100644 third_party/cryptoppwin/include/cryptopp/resource.h create mode 100644 third_party/cryptoppwin/include/cryptopp/rijndael.h create mode 100644 third_party/cryptoppwin/include/cryptopp/ripemd.h create mode 100644 third_party/cryptoppwin/include/cryptopp/rng.h create mode 100644 third_party/cryptoppwin/include/cryptopp/rsa.h create mode 100644 third_party/cryptoppwin/include/cryptopp/rw.h create mode 100644 third_party/cryptoppwin/include/cryptopp/safer.h create mode 100644 third_party/cryptoppwin/include/cryptopp/salsa.h create mode 100644 third_party/cryptoppwin/include/cryptopp/scrypt.h create mode 100644 third_party/cryptoppwin/include/cryptopp/seal.h create mode 100644 third_party/cryptoppwin/include/cryptopp/secblock.h create mode 100644 third_party/cryptoppwin/include/cryptopp/secblockfwd.h create mode 100644 third_party/cryptoppwin/include/cryptopp/seckey.h create mode 100644 third_party/cryptoppwin/include/cryptopp/seed.h create mode 100644 third_party/cryptoppwin/include/cryptopp/serpent.h create mode 100644 third_party/cryptoppwin/include/cryptopp/serpentp.h create mode 100644 third_party/cryptoppwin/include/cryptopp/sha.h create mode 100644 third_party/cryptoppwin/include/cryptopp/sha1_armv4.h create mode 100644 third_party/cryptoppwin/include/cryptopp/sha256_armv4.h create mode 100644 third_party/cryptoppwin/include/cryptopp/sha3.h create mode 100644 third_party/cryptoppwin/include/cryptopp/sha512_armv4.h create mode 100644 third_party/cryptoppwin/include/cryptopp/shacal2.h create mode 100644 third_party/cryptoppwin/include/cryptopp/shake.h create mode 100644 third_party/cryptoppwin/include/cryptopp/shark.h create mode 100644 third_party/cryptoppwin/include/cryptopp/simeck.h create mode 100644 third_party/cryptoppwin/include/cryptopp/simon.h create mode 100644 third_party/cryptoppwin/include/cryptopp/simple.h create mode 100644 third_party/cryptoppwin/include/cryptopp/siphash.h create mode 100644 third_party/cryptoppwin/include/cryptopp/skipjack.h create mode 100644 third_party/cryptoppwin/include/cryptopp/sm3.h create mode 100644 third_party/cryptoppwin/include/cryptopp/sm4.h create mode 100644 third_party/cryptoppwin/include/cryptopp/smartptr.h create mode 100644 third_party/cryptoppwin/include/cryptopp/sosemanuk.h create mode 100644 third_party/cryptoppwin/include/cryptopp/speck.h create mode 100644 third_party/cryptoppwin/include/cryptopp/square.h create mode 100644 third_party/cryptoppwin/include/cryptopp/stdcpp.h create mode 100644 third_party/cryptoppwin/include/cryptopp/strciphr.h create mode 100644 third_party/cryptoppwin/include/cryptopp/tea.h create mode 100644 third_party/cryptoppwin/include/cryptopp/threefish.h create mode 100644 third_party/cryptoppwin/include/cryptopp/tiger.h create mode 100644 third_party/cryptoppwin/include/cryptopp/trap.h create mode 100644 third_party/cryptoppwin/include/cryptopp/trunhash.h create mode 100644 third_party/cryptoppwin/include/cryptopp/ttmac.h create mode 100644 third_party/cryptoppwin/include/cryptopp/tweetnacl.h create mode 100644 third_party/cryptoppwin/include/cryptopp/twofish.h create mode 100644 third_party/cryptoppwin/include/cryptopp/validate.h create mode 100644 third_party/cryptoppwin/include/cryptopp/vmac.h create mode 100644 third_party/cryptoppwin/include/cryptopp/wake.h create mode 100644 third_party/cryptoppwin/include/cryptopp/whrlpool.h create mode 100644 third_party/cryptoppwin/include/cryptopp/words.h create mode 100644 third_party/cryptoppwin/include/cryptopp/xed25519.h create mode 100644 third_party/cryptoppwin/include/cryptopp/xtr.h create mode 100644 third_party/cryptoppwin/include/cryptopp/xtrcrypt.h create mode 100644 third_party/cryptoppwin/include/cryptopp/xts.h create mode 100644 third_party/cryptoppwin/include/cryptopp/zdeflate.h create mode 100644 third_party/cryptoppwin/include/cryptopp/zinflate.h create mode 100644 third_party/cryptoppwin/include/cryptopp/zlib.h create mode 100644 third_party/cryptoppwin/lib/cryptlib.lib create mode 100644 third_party/cryptoppwin/lib/cryptlibd.lib create mode 100644 third_party/ios_toolchain/ios.toolchain.cmake diff --git a/.github/gles.patch b/.github/gles.patch index 548b243d..b16733b5 100644 --- a/.github/gles.patch +++ b/.github/gles.patch @@ -1,25 +1,3 @@ -diff --git a/src/host_shaders/opengl_display.frag b/src/host_shaders/opengl_display.frag -index 612671c8..1937f711 100644 ---- a/src/host_shaders/opengl_display.frag -+++ b/src/host_shaders/opengl_display.frag -@@ -1,4 +1,5 @@ --#version 410 core -+#version 300 es -+precision mediump float; - in vec2 UV; - out vec4 FragColor; - -diff --git a/src/host_shaders/opengl_display.vert b/src/host_shaders/opengl_display.vert -index 990e2f80..2e7842ac 100644 ---- a/src/host_shaders/opengl_display.vert -+++ b/src/host_shaders/opengl_display.vert -@@ -1,4 +1,5 @@ --#version 410 core -+#version 300 es -+precision mediump float; - out vec2 UV; - - void main() { diff --git a/src/host_shaders/opengl_fragment_shader.frag b/src/host_shaders/opengl_fragment_shader.frag index 9f07df0b..96a35afa 100644 --- a/src/host_shaders/opengl_fragment_shader.frag diff --git a/.github/workflows/Android_Build.yml b/.github/workflows/Android_Build.yml index b7e64f5f..37a5eb45 100644 --- a/.github/workflows/Android_Build.yml +++ b/.github/workflows/Android_Build.yml @@ -23,6 +23,9 @@ jobs: - name: Fetch submodules run: git submodule update --init --recursive + - name: Setup CCache + uses: hendrikmuhs/ccache-action@v1.2 + - name: Set up gradle caches uses: actions/cache@v4 with: @@ -34,7 +37,7 @@ jobs: ${{ runner.os }}-pandroid-x86_64- - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true @@ -47,7 +50,7 @@ jobs: java-version: '17' - name: Configure CMake - run: cmake -B ${{github.workspace}}/build -DBUILD_HYDRA_CORE=1 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DANDROID_ABI=x86_64 -DENABLE_VULKAN=0 -DENABLE_USER_BUILD=ON + run: cmake -B ${{github.workspace}}/build -DBUILD_HYDRA_CORE=1 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DANDROID_ABI=x86_64 -DENABLE_VULKAN=0 -DENABLE_USER_BUILD=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - name: Build run: | @@ -88,6 +91,9 @@ jobs: - name: Fetch submodules run: git submodule update --init --recursive + - name: Setup CCache + uses: hendrikmuhs/ccache-action@v1.2 + - name: Set up gradle caches uses: actions/cache@v4 with: @@ -99,7 +105,7 @@ jobs: ${{ runner.os }}-pandroid-arm64- - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true @@ -112,7 +118,7 @@ jobs: java-version: '17' - name: Configure CMake - run: cmake -B ${{github.workspace}}/build -DBUILD_HYDRA_CORE=1 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a -DENABLE_VULKAN=0 -DENABLE_USER_BUILD=ON -DCMAKE_CXX_FLAGS="-march=armv8-a+crypto" + run: cmake -B ${{github.workspace}}/build -DBUILD_HYDRA_CORE=1 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a -DENABLE_VULKAN=0 -DENABLE_USER_BUILD=ON -DCMAKE_CXX_FLAGS="-march=armv8-a+crypto" -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - name: Build run: | diff --git a/.github/workflows/HTTP_Build.yml b/.github/workflows/HTTP_Build.yml index c4f7cfee..11bf27eb 100644 --- a/.github/workflows/HTTP_Build.yml +++ b/.github/workflows/HTTP_Build.yml @@ -30,7 +30,7 @@ jobs: sudo ./llvm.sh 17 - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true diff --git a/.github/workflows/Hydra_Build.yml b/.github/workflows/Hydra_Build.yml index 6827fffe..dbdfbf1b 100644 --- a/.github/workflows/Hydra_Build.yml +++ b/.github/workflows/Hydra_Build.yml @@ -20,7 +20,7 @@ jobs: run: git submodule update --init --recursive - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true @@ -55,7 +55,7 @@ jobs: ${{github.workspace}}/docs/libretro/panda3ds_libretro.info MacOS: - runs-on: macos-13 + runs-on: macos-latest steps: - uses: actions/checkout@v4 @@ -63,7 +63,7 @@ jobs: run: git submodule update --init --recursive - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true @@ -116,7 +116,7 @@ jobs: sudo ./llvm.sh 17 - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true @@ -163,7 +163,7 @@ jobs: sudo apt-get update && sudo apt install libx11-dev libgl1 libglx-mesa0 mesa-common-dev libfuse2 libwayland-dev - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true @@ -180,3 +180,36 @@ jobs: with: name: Android Hydra core path: '${{github.workspace}}/build/libAlber.so' + + ARM-Libretro: + runs-on: ubuntu-24.04-arm + + steps: + - uses: actions/checkout@v4 + - name: Fetch submodules + run: git submodule update --init --recursive + + - name: Install misc packages + run: | + sudo apt-get update && sudo apt install libx11-dev libxext-dev libgl1 libglx-mesa0 mesa-common-dev libfuse2 libwayland-dev + + - name: Install newer Clang + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x ./llvm.sh + sudo ./llvm.sh 17 + + - name: Configure CMake + run: | + cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17 -DENABLE_USER_BUILD=ON -DBUILD_LIBRETRO_CORE=ON -DENABLE_VULKAN=OFF -DCRYPTOPP_OPT_DISABLE_ASM=ON + + - name: Build + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Upload Libretro core + uses: actions/upload-artifact@v4 + with: + name: Linux arm64 Libretro core + path: | + ${{github.workspace}}/build/panda3ds_libretro.so + ${{github.workspace}}/docs/libretro/panda3ds_libretro.info diff --git a/.github/workflows/Linux_AppImage_Build.yml b/.github/workflows/Linux_AppImage_Build.yml index 3c5af88a..9e46072f 100644 --- a/.github/workflows/Linux_AppImage_Build.yml +++ b/.github/workflows/Linux_AppImage_Build.yml @@ -33,7 +33,7 @@ jobs: sudo ./llvm.sh 17 - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true diff --git a/.github/workflows/Linux_Build.yml b/.github/workflows/Linux_Build.yml index 61f7eafa..d0ddfecf 100644 --- a/.github/workflows/Linux_Build.yml +++ b/.github/workflows/Linux_Build.yml @@ -33,7 +33,7 @@ jobs: sudo ./llvm.sh 17 - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true diff --git a/.github/workflows/MacOS_Build.yml b/.github/workflows/MacOS_Build.yml index a0c09bbf..a405e788 100644 --- a/.github/workflows/MacOS_Build.yml +++ b/.github/workflows/MacOS_Build.yml @@ -17,7 +17,7 @@ jobs: arch: [x86_64, arm64] name: MacOS-${{ matrix.arch }} - runs-on: macos-13 + runs-on: macos-latest steps: - uses: actions/checkout@v4 @@ -25,7 +25,7 @@ jobs: run: git submodule update --init --recursive - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true @@ -61,7 +61,7 @@ jobs: MacOS-Universal: name: MacOS-Universal needs: [build] - runs-on: macos-13 + runs-on: macos-latest steps: - name: Download x86_64 diff --git a/.github/workflows/Qt_Build.yml b/.github/workflows/Qt_Build.yml index ebd856c6..3db1e4f3 100644 --- a/.github/workflows/Qt_Build.yml +++ b/.github/workflows/Qt_Build.yml @@ -26,7 +26,7 @@ jobs: version: 6.2.0 - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true @@ -56,7 +56,7 @@ jobs: arch: [x86_64, arm64] name: MacOS-${{ matrix.arch }} - runs-on: macos-13 + runs-on: macos-latest steps: - uses: actions/checkout@v4 @@ -64,7 +64,7 @@ jobs: run: git submodule update --init --recursive - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true @@ -109,7 +109,7 @@ jobs: MacOS-Universal: name: MacOS-Universal needs: [MacOS] - runs-on: macos-13 + runs-on: macos-latest steps: - name: Download x86_64 @@ -162,7 +162,7 @@ jobs: sudo ./llvm.sh 17 - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true diff --git a/.github/workflows/Windows_Build.yml b/.github/workflows/Windows_Build.yml index 5497c3ef..caa3d806 100644 --- a/.github/workflows/Windows_Build.yml +++ b/.github/workflows/Windows_Build.yml @@ -24,7 +24,7 @@ jobs: run: git submodule update --init --recursive - name: Setup Vulkan SDK - uses: humbletim/setup-vulkan-sdk@v1.2.0 + uses: humbletim/setup-vulkan-sdk@main with: vulkan-query-version: latest vulkan-use-cache: true diff --git a/.github/workflows/iOS_Build.yml b/.github/workflows/iOS_Build.yml new file mode 100644 index 00000000..7d7e604b --- /dev/null +++ b/.github/workflows/iOS_Build.yml @@ -0,0 +1,39 @@ +name: iOS Simulator Build + +on: + push: + branches: + - master + pull_request: + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally + # well on Windows or Mac. You can convert this to a matrix build if you need + # cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: macos-latest + + steps: + - uses: actions/checkout@v4 + - name: Fetch submodules + run: git submodule update --init --recursive + + - name: Update Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest + + - name: Setup Vulkan SDK + uses: humbletim/setup-vulkan-sdk@main + with: + vulkan-query-version: latest + vulkan-use-cache: true + vulkan-components: Vulkan-Headers, Vulkan-Loader, SPIRV-Tools, Glslang + + - name: Build core and frontend + run: cd src/pandios && ./build.sh diff --git a/.gitmodules b/.gitmodules index 9fcd8d60..c8ced6e4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "third_party/elfio"] path = third_party/elfio url = https://github.com/serge1/ELFIO -[submodule "third_party/SDL2"] - path = third_party/SDL2 - url = https://github.com/libsdl-org/SDL [submodule "third_party/cryptopp/cryptopp"] path = third_party/cryptopp/cryptopp url = https://github.com/weidai11/cryptopp @@ -79,9 +76,10 @@ [submodule "third_party/fdk-aac"] path = third_party/fdk-aac url = https://github.com/Panda3DS-emu/fdk-aac/ -[submodule "third_party/cryptoppwin"] - path = third_party/cryptoppwin - url = https://github.com/shadps4-emu/ext-cryptoppwin [submodule "third_party/oaknut"] path = third_party/oaknut url = https://github.com/panda3ds-emu/oaknut +[submodule "third_party/SDL2"] + path = third_party/SDL2 + url = https://github.com/libsdl-org/SDL + branch = SDL2 diff --git a/CMakeLists.txt b/CMakeLists.txt index dc529482..9c8571ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,7 @@ option(GPU_DEBUG_INFO "Enable additional GPU debugging info" OFF) option(ENABLE_OPENGL "Enable OpenGL rendering backend" ON) option(ENABLE_VULKAN "Enable Vulkan rendering backend" ON) option(ENABLE_METAL "Enable Metal rendering backend (if available)" ON) +option(ENABLE_WAYLAND "Enable Wayland support on Linux platforms" ON) option(ENABLE_LTO "Enable link-time optimization" OFF) option(ENABLE_TESTS "Compile unit-tests" OFF) option(ENABLE_USER_BUILD "Make a user-facing build. These builds have various assertions disabled, LTO, and more" OFF) @@ -63,6 +64,14 @@ option(BUILD_HYDRA_CORE "Build a Hydra core" OFF) option(BUILD_LIBRETRO_CORE "Build a Libretro core" OFF) option(ENABLE_RENDERDOC_API "Build with support for Renderdoc's capture API for graphics debugging" ON) option(DISABLE_SSE4 "Build with SSE4 instructions disabled, may reduce performance" OFF) +option(USE_LIBRETRO_AUDIO "Enable to use the LR audio device with the LR core. Otherwise our own device is used" OFF) +option(IOS_SIMULATOR_BUILD "Compiling for IOS simulator (Set to off if compiling for a real iPhone)" ON) + +# Discord RPC & LuaJIT are currently not supported on iOS +if(IOS) + set(ENABLE_DISCORD_RPC OFF) + set(ENABLE_LUAJIT OFF) +endif() set(OPENGL_PROFILE ${DEFAULT_OPENGL_PROFILE} CACHE STRING "OpenGL profile to use if OpenGL is enabled. Valid values are 'OpenGL' and 'OpenGLES'.") set_property(CACHE OPENGL_PROFILE PROPERTY STRINGS OpenGL OpenGLES) @@ -79,6 +88,10 @@ endif() if(BUILD_LIBRETRO_CORE) set(CMAKE_POSITION_INDEPENDENT_CODE ON) add_compile_definitions(__LIBRETRO__) + + if(USE_LIBRETRO_AUDIO) + add_compile_definitions(USE_LIBRETRO_AUDIO_DEVICE) + endif() endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND ENABLE_USER_BUILD) @@ -88,7 +101,7 @@ endif() # Generate versioning files find_package(Git) -set(PANDA3DS_VERSION "0.8") +set(PANDA3DS_VERSION "0.9") if(NOT EXISTS ${CMAKE_BINARY_DIR}/include/version.hpp.in) file(WRITE ${CMAKE_BINARY_DIR}/include/version.hpp.in "#define PANDA3DS_VERSION \"\${PANDA3DS_VERSION}\"") @@ -97,22 +110,29 @@ endif() if(GIT_FOUND AND ENABLE_GIT_VERSIONING) execute_process( WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0 - OUTPUT_VARIABLE PANDA3DS_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE - ) - execute_process( - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} describe --tags OUTPUT_VARIABLE git_version_tag OUTPUT_STRIP_TRAILING_WHITESPACE ) - if(NOT PANDA3DS_VERSION STREQUAL git_version_tag) - execute_process( - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} describe --always --abbrev=7 - OUTPUT_VARIABLE git_version_rev OUTPUT_STRIP_TRAILING_WHITESPACE - ) - set(PANDA3DS_VERSION "${PANDA3DS_VERSION}.${git_version_rev}") - unset(git_version_rev) + execute_process( + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} rev-parse --short=7 HEAD + OUTPUT_VARIABLE git_version_rev OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(NOT git_version_tag STREQUAL "") + set(PANDA3DS_VERSION "${git_version_tag}") + execute_process( + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} describe --tags + OUTPUT_VARIABLE git_version_desc OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(git_version_tag STREQUAL git_version_desc) + set(git_version_rev "") + endif() + unset(git_version_desc) + endif() + if(NOT git_version_rev STREQUAL "") + set(PANDA3DS_VERSION "${PANDA3DS_VERSION}.${git_version_rev}") endif() string(REGEX REPLACE "^v" "" PANDA3DS_VERSION "${PANDA3DS_VERSION}") unset(git_version_tag) + unset(git_version_rev) endif() configure_file(${CMAKE_BINARY_DIR}/include/version.hpp.in ${CMAKE_BINARY_DIR}/include/version.hpp) include_directories(${CMAKE_BINARY_DIR}/include/) @@ -140,12 +160,15 @@ add_compile_definitions(NOMINMAX) # Make windows.h not define min/ma add_compile_definitions(WIN32_LEAN_AND_MEAN) # Make windows.h not include literally everything add_compile_definitions(SDL_MAIN_HANDLED) +if(ENABLE_WAYLAND) + add_compile_definitions(WAYLAND_ENABLED) +endif() + if(ENABLE_DISCORD_RPC AND NOT ANDROID) add_subdirectory(third_party/discord-rpc) include_directories(third_party/discord-rpc/include) endif() - if (NOT ANDROID) if (USE_SYSTEM_SDL2) find_package(SDL2 CONFIG REQUIRED) @@ -304,8 +327,8 @@ set(SOURCE_FILES src/emulator.cpp src/io_file.cpp src/config.cpp src/core/CPU/cpu_dynarmic.cpp src/core/CPU/dynarmic_cycles.cpp src/core/memory.cpp src/renderer.cpp src/core/renderer_null/renderer_null.cpp src/http_server.cpp src/stb_image_write.c src/core/cheats.cpp src/core/action_replay.cpp - src/discord_rpc.cpp src/lua.cpp src/memory_mapped_file.cpp src/miniaudio.cpp src/renderdoc.cpp - src/frontend_settings.cpp + src/discord_rpc.cpp src/lua.cpp src/memory_mapped_file.cpp src/renderdoc.cpp + src/frontend_settings.cpp src/miniaudio/miniaudio.cpp ) set(CRYPTO_SOURCE_FILES src/core/crypto/aes_engine.cpp) set(KERNEL_SOURCE_FILES src/core/kernel/kernel.cpp src/core/kernel/resource_limits.cpp @@ -390,9 +413,19 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp include/align.hpp include/audio/aac_decoder.hpp include/PICA/pica_simd.hpp include/services/fonts.hpp include/audio/audio_interpolation.hpp include/audio/hle_mixer.hpp include/audio/dsp_simd.hpp include/services/dsp_firmware_db.hpp include/frontend_settings.hpp include/fs/archive_twl_photo.hpp - include/fs/archive_twl_sound.hpp include/fs/archive_card_spi.hpp include/services/ns.hpp include/services/news_s.hpp + include/fs/archive_twl_sound.hpp include/fs/archive_card_spi.hpp include/services/ns.hpp include/audio/audio_device.hpp + include/audio/audio_device_interface.hpp include/audio/libretro_audio_device.hpp include/services/news_s.hpp ) +if(IOS) + set(SOURCE_FILES ${SOURCE_FILES} src/miniaudio/miniaudio.m) + target_compile_definitions(AlberCore PUBLIC "PANDA3DS_IOS=1") + + if (IOS_SIMULATOR_BUILD) + target_compile_definitions(AlberCore PUBLIC "PANDA3DS_IOS_SIMULATOR=1") + endif() +endif() + cmrc_add_resource_library( resources_console_fonts NAMESPACE ConsoleFonts @@ -422,16 +455,22 @@ if(ENABLE_LUAJIT AND NOT ANDROID) target_link_libraries(AlberCore PRIVATE uv_a) endif() +set(GL_CONTEXT_SOURCE_FILES "") + if(ENABLE_QT_GUI) - set(THIRD_PARTY_SOURCE_FILES ${THIRD_PARTY_SOURCE_FILES} third_party/duckstation/window_info.cpp third_party/duckstation/gl/context.cpp) + set(GL_CONTEXT_SOURCE_FILES ${GL_CONTEXT_SOURCE_FILES} third_party/duckstation/window_info.cpp third_party/duckstation/gl/context.cpp) if(APPLE) - set(THIRD_PARTY_SOURCE_FILES ${THIRD_PARTY_SOURCE_FILES} third_party/duckstation/gl/context_agl.mm) + set(GL_CONTEXT_SOURCE_FILES ${GL_CONTEXT_SOURCE_FILES} third_party/duckstation/gl/context_agl.mm) elseif(WIN32) - set(THIRD_PARTY_SOURCE_FILES ${THIRD_PARTY_SOURCE_FILES} third_party/duckstation/gl/context_wgl.cpp) + set(GL_CONTEXT_SOURCE_FILES ${GL_CONTEXT_SOURCE_FILES} third_party/duckstation/gl/context_wgl.cpp) else() - set(THIRD_PARTY_SOURCE_FILES ${THIRD_PARTY_SOURCE_FILES} third_party/duckstation/gl/context_egl.cpp third_party/duckstation/gl/context_egl_wayland.cpp - third_party/duckstation/gl/context_egl_x11.cpp third_party/duckstation/gl/context_glx.cpp third_party/duckstation/gl/x11_window.cpp) + set(GL_CONTEXT_SOURCE_FILES ${GL_CONTEXT_SOURCE_FILES} third_party/duckstation/gl/context_egl.cpp third_party/duckstation/gl/context_egl_x11.cpp + third_party/duckstation/gl/context_glx.cpp third_party/duckstation/gl/x11_window.cpp) + + if(ENABLE_WAYLAND) + set(GL_CONTEXT_SOURCE_FILES ${GL_CONTEXT_SOURCE_FILES} third_party/duckstation/gl/context_egl_wayland.cpp) + endif() endif() endif() @@ -445,7 +484,7 @@ source_group("Source Files\\Core\\Applets" FILES ${APPLET_SOURCE_FILES}) source_group("Source Files\\Core\\PICA" FILES ${PICA_SOURCE_FILES}) source_group("Source Files\\Core\\Audio" FILES ${AUDIO_SOURCE_FILES}) source_group("Source Files\\Core\\Software Renderer" FILES ${RENDERER_SW_SOURCE_FILES}) -source_group("Source Files\\Third Party" FILES ${THIRD_PARTY_SOURCE_FILES}) +source_group("Source Files\\Third Party" FILES ${THIRD_PARTY_SOURCE_FILES} ${GL_CONTEXT_SOURCE_FILES}) set(RENDERER_GL_SOURCE_FILES "") # Empty by default unless we are compiling with the GL renderer set(RENDERER_VK_SOURCE_FILES "") # Empty by default unless we are compiling with the VK renderer @@ -460,8 +499,9 @@ if(ENABLE_OPENGL) set(RENDERER_GL_SOURCE_FILES src/core/renderer_gl/renderer_gl.cpp src/core/renderer_gl/textures.cpp src/core/renderer_gl/etc1.cpp - src/core/renderer_gl/gl_state.cpp src/host_shaders/opengl_display.frag - src/host_shaders/opengl_display.vert src/host_shaders/opengl_vertex_shader.vert + src/core/renderer_gl/gl_state.cpp src/host_shaders/opengl_display.vert + src/host_shaders/opengl_display.frag src/host_shaders/opengl_es_display.vert + src/host_shaders/opengl_es_display.frag src/host_shaders/opengl_vertex_shader.vert src/host_shaders/opengl_fragment_shader.frag ) @@ -474,8 +514,10 @@ if(ENABLE_OPENGL) resources_renderer_gl NAMESPACE RendererGL WHENCE "src/host_shaders/" - "src/host_shaders/opengl_display.frag" "src/host_shaders/opengl_display.vert" + "src/host_shaders/opengl_display.frag" + "src/host_shaders/opengl_es_display.vert" + "src/host_shaders/opengl_es_display.frag" "src/host_shaders/opengl_vertex_shader.vert" "src/host_shaders/opengl_fragment_shader.frag" ) @@ -562,14 +604,16 @@ if(ENABLE_METAL AND APPLE) include/renderer_mtl/mtl_common.hpp include/renderer_mtl/pica_to_mtl.hpp include/renderer_mtl/objc_helper.hpp + include/renderer_mtl/texture_decoder.hpp ) set(RENDERER_MTL_SOURCE_FILES src/core/renderer_mtl/metal_cpp_impl.cpp src/core/renderer_mtl/renderer_mtl.cpp src/core/renderer_mtl/mtl_texture.cpp - src/core/renderer_mtl/mtl_etc1.cpp src/core/renderer_mtl/mtl_lut_texture.cpp + src/core/renderer_mtl/pica_to_mtl.cpp src/core/renderer_mtl/objc_helper.mm + src/core/renderer_mtl/texture_decoder.cpp src/host_shaders/metal_shaders.metal src/host_shaders/metal_blit.metal #src/host_shaders/metal_copy_to_lut_texture.metal @@ -583,15 +627,26 @@ if(ENABLE_METAL AND APPLE) set(SHADER_SOURCE "${CMAKE_SOURCE_DIR}/src/host_shaders/${SHADER}.metal") set(SHADER_IR "${CMAKE_SOURCE_DIR}/src/host_shaders/${SHADER}.ir") set(SHADER_METALLIB "${CMAKE_SOURCE_DIR}/src/host_shaders/${SHADER}.metallib") + + # MacOS, iOS and the iOS simulator all use different compilation options for shaders + set(MetalSDK "macosx") + if(IOS) + if (IOS_SIMULATOR_BUILD) + set(MetalSDK "iphonesimulator") + else() + set(MetalSDK "iphoneos") + endif() + endif() + # TODO: only include sources in debug builds add_custom_command( OUTPUT ${SHADER_IR} - COMMAND xcrun -sdk macosx metal -gline-tables-only -frecord-sources -o ${SHADER_IR} -c ${SHADER_SOURCE} + COMMAND xcrun -sdk ${MetalSDK} metal -gline-tables-only -frecord-sources -o ${SHADER_IR} -c ${SHADER_SOURCE} DEPENDS ${SHADER_SOURCE} VERBATIM) add_custom_command( OUTPUT ${SHADER_METALLIB} - COMMAND xcrun -sdk macosx metallib -o ${SHADER_METALLIB} ${SHADER_IR} + COMMAND xcrun -sdk ${MetalSDK} metallib -o ${SHADER_METALLIB} ${SHADER_IR} DEPENDS ${SHADER_IR} VERBATIM) set(RENDERER_MTL_HOST_SHADERS_SOURCES ${RENDERER_MTL_HOST_SHADERS_SOURCES} ${SHADER_METALLIB}) @@ -620,7 +675,7 @@ if(ENABLE_METAL AND APPLE) target_compile_definitions(AlberCore PUBLIC "PANDA3DS_ENABLE_METAL=1") target_include_directories(AlberCore PRIVATE third_party/metal-cpp) # TODO: check if all of them are needed - target_link_libraries(AlberCore PRIVATE "-framework Metal" "-framework Foundation" "-framework QuartzCore" resources_renderer_mtl) + target_link_libraries(AlberCore PUBLIC "-framework Metal" "-framework Foundation" "-framework QuartzCore" resources_renderer_mtl) endif() source_group("Header Files\\Core" FILES ${HEADER_FILES}) @@ -726,11 +781,14 @@ if(NOT BUILD_HYDRA_CORE AND NOT BUILD_LIBRETRO_CORE) docs/img/rsob_icon.png docs/img/rstarstruck_icon.png docs/img/rpog_icon.png docs/img/rsyn_icon.png docs/img/settings_icon.png docs/img/display_icon.png docs/img/speaker_icon.png docs/img/sparkling_icon.png docs/img/battery_icon.png docs/img/sdcard_icon.png - docs/img/rnap_icon.png docs/img/rcow_icon.png docs/img/skyemu_icon.png + docs/img/rnap_icon.png docs/img/rcow_icon.png docs/img/skyemu_icon.png docs/img/runpog_icon.png ) # Translation files in Qt's .ts format. Will be converted into binary files and embedded into the executable - set(TRANSLATIONS_TS docs/translations/en.ts docs/translations/el.ts docs/translations/es.ts docs/translations/pt_br.ts docs/translations/nl.ts) + set(TRANSLATIONS_TS docs/translations/en.ts docs/translations/el.ts docs/translations/es.ts docs/translations/pt_br.ts docs/translations/nl.ts + docs/translations/sv.ts + ) + set_source_files_properties(${TRANSLATIONS_TS} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations") qt_add_translation(TRANSLATIONS_QM ${TRANSLATIONS_TS}) @@ -751,11 +809,17 @@ if(NOT BUILD_HYDRA_CORE AND NOT BUILD_LIBRETRO_CORE) endif() target_link_libraries(Alber PRIVATE AlberCore) - target_sources(Alber PRIVATE ${FRONTEND_SOURCE_FILES} ${FRONTEND_HEADER_FILES} ${APP_RESOURCES}) + target_sources(Alber PRIVATE ${FRONTEND_SOURCE_FILES} ${FRONTEND_HEADER_FILES} ${GL_CONTEXT_SOURCE_FILES} ${APP_RESOURCES}) elseif(BUILD_HYDRA_CORE) target_compile_definitions(AlberCore PRIVATE PANDA3DS_HYDRA_CORE=1) include_directories(third_party/hydra_core/include) - add_library(Alber SHARED src/hydra_core.cpp) + + set(SHARED_SOURCE_FILES src/hydra_core.cpp) + if(IOS) + set(SHARED_SOURCE_FILES ${SHARED_SOURCE_FILES} src/ios_driver.mm) + endif() + + add_library(Alber SHARED ${SHARED_SOURCE_FILES}) target_link_libraries(Alber PUBLIC AlberCore) elseif(BUILD_LIBRETRO_CORE) include_directories(third_party/libretro/include) diff --git a/docs/img/runpog_icon.png b/docs/img/runpog_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6ef33f4af7513ab42aead6f8295b35a8ee9f853b GIT binary patch literal 16804 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 + + + sv + + Daniel Nylander <github@danielnylander.se> + + + + Poedit 3.5 + Project-Id-Version,POT-Creation-Date,PO-Revision-Date,Last-Translator,Language-Team,Language,MIME-Version,Content-Type,Content-Transfer-Encoding,X-Qt-Contexts,X-Generator + + AboutWindow + + + About Panda3DS + Om Panda3DS + + + + Panda3DS is a free and open source Nintendo 3DS emulator, for Windows, MacOS and Linux + Panda3DS är en Nintendo 3DS-emulator med fri och öppen källkod för Windows, MacOS och Linux + + + + Visit panda3ds.com for help with Panda3DS and links to our official support sites. + Besök panda3ds.com för att få hjälp med Panda3DS och länkar till våra officiella supportwebbplatser. + + + + Panda3DS is developed by volunteers in their spare time. Below is a list of some of these volunteers who've agreed to be listed here, in no particular order.<br>If you think you should be listed here too, please inform us<br><br>- Peach (wheremyfoodat)<br>- noumidev<br>- liuk707<br>- Wunk<br>- marysaka<br>- Sky<br>- merryhime<br>- TGP17<br>- Shadow<br> + Panda3DS utvecklas av volontärer på deras fritid. Nedan finns en lista över några av dessa volontärer som har gått med på att listas här, utan någon särskild ordning.<br>Om du tycker att du också borde listas här, informera oss<br><br>- Peach (wheremyfoodat)<br>- noumidev<br>- liuk707<br>- Wunk<br>- marysaka<br>- Sky<br>- merryhime<br>- TGP17<br>- Shadow<br> + + + + CheatEditDialog + + + Edit Cheat + Redigera fusk + + + + Cheat name + Fusknamn + + + + CheatEntryWidget + + + Edit + Redigera + + + + CheatsWindow + + + Cheats + Fusk + + + + Add + Lägg till + + + + Remove + Ta bort + + + + ConfigWindow + + + Configuration + Konfiguration + + + + Interface Settings + Inställningar för gränssnitt + + + + System + System + + + + Light + Ljus + + + + Dark + Mörk + + + + Greetings Cat + Hälsningskatt + + + + Cream + Grädde + + + + Color theme + Färgtema + + + + Happy panda + Glad panda + + + + Happy panda (colourful) + Glad panda (färgglad) + + + + Sleepy panda + Sömnig panda + + + + Cow panda + Ko-panda + + + + The penguin from SkyEmu + Pingvinen från SkyEmu + + + + Window icon + Fönsterikon + + + + Language + Språk + + + + Show version on window title + Visa version på fönstertitel + + + + + Alber v%1 + Alber v%1 + + + + Alber + Alber + + + + Remember window position + Kom ihåg fönstrets position + + + + General Settings + Allmänna inställningar + + + + Browse... + Bläddra... + + + + Select Directory + Välj katalog + + + + Default ROMs path + Standardsökväg för ROMar + + + + Enable Discord RPC + Aktivera Discord RPC + + + + Use portable build + Använd portabelt bygge + + + + Print version in console output + Skriv ut versionen i konsolutmatningen + + + + Graphics Settings + Grafikinställningar + + + + + Null + Null + + + + OpenGL + OpenGL + + + + Vulkan + Vulkan + + + + GPU renderer + GPU-rendering + + + + Enable Renderdoc + Aktivera Renderdoc + + + + Enable shader JIT + Aktivera shader JIT + + + + Enable VSync + Aktivera VSync + + + + Use ubershaders (No stutter, maybe slower) + Använda ubershaders (inga hackningar, kanske långsammare) + + + + Accurate shader multiplication + Korrekt multiplicering av shaders + + + + Accelerate shaders + Snabbare shaders + + + + Force shadergen when rendering lights + Tvinga fram shadergen vid rendering av ljus + + + + Light threshold for forcing shadergen + Ljuströskel för att tvinga shadergen + + + + Audio Settings + Ljudinställningar + + + + LLE + LLE + + + + HLE + HLE + + + + DSP emulation + DSP-emulering + + + + Enable audio + Aktivera ljud + + + + Enable AAC audio + Aktivera AAC-ljud + + + + Print DSP firmware + Skriv ut firmware för DSP + + + + Mute audio device + Stäng av ljudet på audioenheten + + + + Cubic + Kubisk + + + + Linear + Linjär + + + + Volume curve + Volymkurva + + + + Audio device volume + Ljudenhetens volym + + + + Battery Settings + Batteriinställningar + + + + Battery percentage + Batteriprocent + + + + Charger plugged + Laddaren är ansluten + + + + SD Card Settings + Inställningar för SD-kort + + + + Enable virtual SD card + Aktivera virtuellt SD-kort + + + + Write protect virtual SD card + Skrivskydd för virtuellt SD-kort + + + + Interface + Gränssnitt + + + + User Interface settings + Inställningar för användargränssnitt + + + + General + Allmänt + + + + General emulator settings + Allmänna inställningar för emulatorn + + + + Graphics + Grafik + + + + Graphics emulation and output settings + Inställningar för grafikemulering och utdata + + + + Audio + Ljud + + + + Audio emulation and output settings + Inställningar för ljudemulering och utdata + + + + Battery + Batteri + + + + Battery emulation settings + Inställningar för batteriemulering + + + + SD Card + SD-kort + + + + SD Card emulation settings + Inställningar för emulering av SD-kort + + + + Language change successful + Språkändringen lyckades + + + + Restart Panda3DS for the new language to be used. + Starta om Panda3DS för att det nya språket ska kunna användas. + + + + Language change failed + Språkändringen misslyckades + + + + The language you selected is not included in Panda3DS. If you're seeing this, someone messed up the language UI code... + Det språk du valde ingår inte i Panda3DS. Om du ser detta, har någon rört till koden för språkgränssnittet... + + + + MainWindow + + + Alber + Alber + + + + File + Arkiv + + + + Emulation + Emulering + + + + Tools + Verktyg + + + + About + Om + + + + Load game + Läs in spel + + + + Load Lua script + Läs in Lua-skript + + + + Open Panda3DS folder + Öppna Panda3DS-mappen + + + + Pause + Pausa + + + + Resume + Återuppta + + + + Reset + Starta om + + + + Configure + Konfigurera + + + + Dump RomFS + Dumpa RomFS + + + + Open Lua Editor + Öppna Lua-redigeraren + + + + Open Cheats Editor + Öppna fuskredigeraren + + + + Open Patch Window + Öppna patchfönstret + + + + Open Shader Editor + Öppna shader-redigeraren + + + + Dump loaded DSP firmware + Dumpa inläst DSP-firmware + + + + About Panda3DS + Om Panda3DS + + + + Select 3DS ROM to load + Välj 3DS ROM att läsa in + + + + Nintendo 3DS ROMs (*.3ds *.cci *.cxi *.app *.ncch *.3dsx *.elf *.axf) + Nintendo 3DS ROM (*.3ds *.cci *.cxi *.app *.ncch *.3dsx *.elf *.axf) + + + + Select Lua script to load + Välj Lua-skript som ska läsas in + + + + Lua scripts (*.lua *.txt) + Lua-skript (*.lua *.txt) + + + + Select folder to dump RomFS files to + Välj mapp för att dumpa RomFS-filer till + + + + Invalid format for RomFS dumping + Ogiltigt format för RomFS-dumpning + + + + The currently loaded app is not in a format that supports RomFS + Den aktuella appen är inte i ett format som stöder RomFS + + + + + + OK + Ok + + + + No RomFS found + Ingen RomFS hittades + + + + No RomFS partition was found in the loaded app + Ingen RomFS-partition hittades i den inlästa appen + + + + Select file + Välj fil + + + + DSP firmware file (*.cdc) + DSP firmware-fil (*.cdc) + + + + No DSP firmware loaded + Ingen firmware för DSP inläst + + + + The currently loaded app has not uploaded a firmware to the DSP + Den aktuella appen har inte skickat upp någon firmware till DSP:n + + + + Failed to open output file + Misslyckades med att öppna utdatafilen + + + + The currently loaded DSP firmware could not be written to the selected file. Please make sure you have permission to access this file + Den aktuella DSP-firmware som lästes in kunde inte skrivas till den valda filen. Kontrollera att du har behörighet att komma åt den här filen + + + + PatchWindow + + + ROM patcher + ROM-patchare + + + + Select input file + Välj inmatningsfil + + + + + Select + Välj + + + + + Select patch file + Välj patchfil + + + + Apply patch + Applicera patch + + + + Select file to patch + Välj fil som ska patchas + + + + + All files (*.*) + Alla filer (*.*) + + + + Patch files (*.ips *.ups *.bps) + Patch-filer (*.ips *.ups *.bps) + + + + Paths not provided correctly + Sökvägar anges inte korrekt + + + + Please provide paths for both the input file and the patch file + Ange sökvägar för både indatafilen och patchfilen + + + + Select file + Välj fil + + + + No output path + Ingen sökväg för utmatning + + + + No path was provided for the output file, no patching was done + Ingen sökväg angavs för utdatafilen, ingen patchning gjordes + + + + Unknown patch format + Okänt patchformat + + + + Unknown format for patch file. Currently IPS, UPS and BPS are supported + Okänt format för patchfil. För närvarande stöds IPS, UPS och BPS + + + + Failed to open input files + Misslyckades med att öppna indatafiler + + + + Make sure they're in a directory Panda3DS has access to + Se till att de finns i en katalog som Panda3DS har tillgång till + + + + Patching Success + Patchning lyckades + + + + Your file was patched successfully. + Din fil patchades. + + + + Checksum mismatch + Kontrollsumman stämmer inte överens + + + + Patch was applied successfully but a checksum mismatch was detected. The input or output files might not be correct + Patchen applicerades men en avvikelse i kontrollsumman upptäcktes. Inmatnings- eller utdatafilerna kanske inte är korrekta + + + + Patching error + Fel vid patchning + + + + An error occured while patching + Ett fel uppstod vid patchning + + + + PatchWindow::PatchWindow + + + OK + Ok + + + + ShaderEditorWindow + + + Reload shader + Läs om shader + + + + TextEditorWindow + + + Lua Editor + Lua-redigerare + + + + Load script + Läs in skript + + + diff --git a/include/PICA/shader_gen_types.hpp b/include/PICA/shader_gen_types.hpp index 1877227f..b069f71f 100644 --- a/include/PICA/shader_gen_types.hpp +++ b/include/PICA/shader_gen_types.hpp @@ -2,8 +2,8 @@ namespace PICA::ShaderGen { // Graphics API this shader is targetting - enum class API { GL, GLES, Vulkan }; + enum class API { GL, GLES, Vulkan, Metal }; - // Shading language to use (Only GLSL for the time being) - enum class Language { GLSL }; -} // namespace PICA::ShaderGen \ No newline at end of file + // Shading language to use + enum class Language { GLSL, MSL }; +} // namespace PICA::ShaderGen diff --git a/include/audio/audio_device.hpp b/include/audio/audio_device.hpp new file mode 100644 index 00000000..966fd667 --- /dev/null +++ b/include/audio/audio_device.hpp @@ -0,0 +1,9 @@ +#pragma once + +#if defined(__LIBRETRO__) && defined(USE_LIBRETRO_AUDIO_DEVICE) +#include "audio/libretro_audio_device.hpp" +using AudioDevice = LibretroAudioDevice; +#else +#include "audio/miniaudio_device.hpp" +using AudioDevice = MiniAudioDevice; +#endif \ No newline at end of file diff --git a/include/audio/audio_device_interface.hpp b/include/audio/audio_device_interface.hpp new file mode 100644 index 00000000..de70c77a --- /dev/null +++ b/include/audio/audio_device_interface.hpp @@ -0,0 +1,36 @@ +#pragma once +#include + +#include "config.hpp" +#include "helpers.hpp" +#include "ring_buffer.hpp" + +class AudioDeviceInterface { + protected: + static constexpr usize maxFrameCount = 0x2000; + + using Samples = Common::RingBuffer; + using RenderBatchCallback = usize (*)(const s16*, usize); + + Samples* samples = nullptr; + + const AudioDeviceConfig& audioSettings; + // Store the last stereo sample we output. We play this when underruning to avoid pops. + std::array lastStereoSample{}; + + public: + AudioDeviceInterface(Samples* samples, const AudioDeviceConfig& audioSettings) : samples(samples), audioSettings(audioSettings) {} + + bool running = false; + Samples* getSamples() { return samples; } + + // If safe is on, we create a null audio device + virtual void init(Samples& samples, bool safe = false) = 0; + virtual void close() = 0; + + virtual void start() = 0; + virtual void stop() = 0; + + // Only used for audio devices that render multiple audio frames in one go, eg the libretro audio device. + virtual void renderBatch(RenderBatchCallback callback) {} +}; \ No newline at end of file diff --git a/include/audio/libretro_audio_device.hpp b/include/audio/libretro_audio_device.hpp new file mode 100644 index 00000000..9c6d19f8 --- /dev/null +++ b/include/audio/libretro_audio_device.hpp @@ -0,0 +1,61 @@ +#pragma once +#include + +#include "audio/audio_device_interface.hpp" + +class LibretroAudioDevice final : public AudioDeviceInterface { + bool initialized = false; + + public: + LibretroAudioDevice(const AudioDeviceConfig& audioSettings) : AudioDeviceInterface(nullptr, audioSettings), initialized(false) { + running = false; + } + + void init(Samples& samples, bool safe = false) override { + this->samples = &samples; + + initialized = true; + running = false; + } + + void close() override { + initialized = false; + running = false; + }; + + void start() override { running = true; } + void stop() override { running = false; }; + + void renderBatch(RenderBatchCallback callback) override { + if (running) { + static constexpr usize sampleRate = 32768; // 3DS samples per second + static constexpr usize frameCount = sampleRate / 60; // 3DS samples per video frame + static constexpr usize channelCount = 2; + static s16 audioBuffer[frameCount * channelCount]; + + usize samplesWritten = 0; + samplesWritten += samples->pop(audioBuffer, frameCount * channelCount); + + // Get the last sample for underrun handling + if (samplesWritten != 0) { + std::memcpy(&lastStereoSample[0], &audioBuffer[(samplesWritten - 1) * 2], sizeof(lastStereoSample)); + } + + // If underruning, copy the last output sample + { + s16* pointer = &audioBuffer[samplesWritten * 2]; + s16 l = lastStereoSample[0]; + s16 r = lastStereoSample[1]; + + for (usize i = samplesWritten; i < frameCount; i++) { + *pointer++ = l; + *pointer++ = r; + } + } + + callback(audioBuffer, sizeof(audioBuffer) / (channelCount * sizeof(s16))); + } + } + + bool isInitialized() const { return initialized; } +}; diff --git a/include/audio/miniaudio_device.hpp b/include/audio/miniaudio_device.hpp index 0363aa44..5cf7c801 100644 --- a/include/audio/miniaudio_device.hpp +++ b/include/audio/miniaudio_device.hpp @@ -3,39 +3,31 @@ #include #include -#include "config.hpp" -#include "helpers.hpp" +#include "audio/audio_device_interface.hpp" #include "miniaudio.h" -#include "ring_buffer.hpp" -class MiniAudioDevice { - using Samples = Common::RingBuffer; +class MiniAudioDevice final : public AudioDeviceInterface { static constexpr ma_uint32 sampleRate = 32768; // 3DS sample rate static constexpr ma_uint32 channelCount = 2; // Audio output is stereo + bool initialized = false; + ma_device device; ma_context context; ma_device_config deviceConfig; - Samples* samples = nullptr; - - const AudioDeviceConfig& audioSettings; - - bool initialized = false; - bool running = false; // Store the last stereo sample we output. We play this when underruning to avoid pops. - std::array lastStereoSample; std::vector audioDevices; public: MiniAudioDevice(const AudioDeviceConfig& audioSettings); // If safe is on, we create a null audio device - void init(Samples& samples, bool safe = false); - void close(); + void init(Samples& samples, bool safe = false) override; + void close() override; - void start(); - void stop(); + void start() override; + void stop() override; bool isInitialized() const { return initialized; } }; \ No newline at end of file diff --git a/include/config.hpp b/include/config.hpp index 6041286d..5e1bd8a7 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -5,6 +5,7 @@ #include "audio/dsp_core.hpp" #include "frontend_settings.hpp" #include "renderer.hpp" +#include "services/region_codes.hpp" struct AudioDeviceConfig { // Audio curve to use for volumes between 0-100 @@ -48,9 +49,26 @@ struct EmulatorConfig { #endif static constexpr bool accelerateShadersDefault = true; +#if defined(__LIBRETRO__) + static constexpr bool audioEnabledDefault = true; +#else + static constexpr bool audioEnabledDefault = false; +#endif + + // We default to OpenGL on all platforms other than iOS +#if defined(PANDA3DS_IOS) + static constexpr RendererType rendererDefault = RendererType::Metal; +#else + static constexpr RendererType rendererDefault = RendererType::OpenGL; +#endif + + static constexpr bool hashTexturesDefault = true; + bool shaderJitEnabled = shaderJitDefault; bool useUbershaders = ubershaderDefault; bool accelerateShaders = accelerateShadersDefault; + bool hashTextures = hashTexturesDefault; + bool accurateShaderMul = false; bool discordRpcEnabled = false; @@ -58,14 +76,14 @@ struct EmulatorConfig { bool forceShadergenForLights = true; int lightShadergenThreshold = 1; - RendererType rendererType = RendererType::OpenGL; + RendererType rendererType = rendererDefault; Audio::DSPCore::Type dspType = Audio::DSPCore::Type::HLE; bool sdCardInserted = true; bool sdWriteProtected = false; bool usePortableBuild = false; - bool audioEnabled = false; + bool audioEnabled = audioEnabledDefault; bool vsyncEnabled = true; bool aacEnabled = true; // Enable AAC audio? @@ -77,6 +95,8 @@ struct EmulatorConfig { // Default to 3% battery to make users suffer int batteryPercentage = 3; + LanguageCodes systemLanguage = LanguageCodes::English; + // Default ROM path to open in Qt and misc frontends std::filesystem::path defaultRomPath = ""; std::filesystem::path filePath; @@ -104,4 +124,7 @@ struct EmulatorConfig { EmulatorConfig(const std::filesystem::path& path); void load(); void save(); + + static LanguageCodes languageCodeFromString(std::string inString); + static const char* languageCodeToString(LanguageCodes code); }; \ No newline at end of file diff --git a/include/cpu_dynarmic.hpp b/include/cpu_dynarmic.hpp index 43f31d30..24358533 100644 --- a/include/cpu_dynarmic.hpp +++ b/include/cpu_dynarmic.hpp @@ -181,5 +181,7 @@ class CPU { void addTicks(u64 ticks) { env.AddTicks(ticks); } void clearCache() { jit->ClearCache(); } + void clearCacheRange(u32 start, u32 size) { jit->InvalidateCacheRange(start, size); } + void runFrame(); }; \ No newline at end of file diff --git a/include/emulator.hpp b/include/emulator.hpp index cf231328..326eb232 100644 --- a/include/emulator.hpp +++ b/include/emulator.hpp @@ -7,8 +7,8 @@ #include #include "PICA/gpu.hpp" +#include "audio/audio_device.hpp" #include "audio/dsp_core.hpp" -#include "audio/miniaudio_device.hpp" #include "cheats.hpp" #include "config.hpp" #include "cpu.hpp" @@ -48,14 +48,14 @@ class Emulator { Scheduler scheduler; Crypto::AESEngine aesEngine; - MiniAudioDevice audioDevice; + AudioDevice audioDevice; Cheats cheats; public: static constexpr u32 width = 400; static constexpr u32 height = 240 * 2; // * 2 because 2 screens ROMType romType = ROMType::None; - bool running = false; // Is the emulator running a game? + bool running = false; // Is the emulator running a game? private: #ifdef PANDA3DS_ENABLE_HTTP_SERVER @@ -89,7 +89,6 @@ class Emulator { ~Emulator(); void step(); - void render(); void reset(ReloadOption reload); void runFrame(); // Poll the scheduler for events @@ -127,6 +126,7 @@ class Emulator { LuaManager& getLua() { return lua; } Scheduler& getScheduler() { return scheduler; } Memory& getMemory() { return memory; } + AudioDeviceInterface& getAudioDevice() { return audioDevice; } RendererType getRendererType() const { return config.rendererType; } Renderer* getRenderer() { return gpu.getRenderer(); } diff --git a/include/frontend_settings.hpp b/include/frontend_settings.hpp index ae967879..083b8c7d 100644 --- a/include/frontend_settings.hpp +++ b/include/frontend_settings.hpp @@ -11,6 +11,7 @@ struct FrontendSettings { Dark = 2, GreetingsCat = 3, Cream = 4, + Oled = 5, }; // Different panda-themed window icons @@ -20,6 +21,7 @@ struct FrontendSettings { Rnap = 2, Rcow = 3, SkyEmu = 4, + Runpog = 5, }; Theme theme = Theme::Dark; diff --git a/include/ios_driver.h b/include/ios_driver.h new file mode 100644 index 00000000..7f783970 --- /dev/null +++ b/include/ios_driver.h @@ -0,0 +1,7 @@ +#pragma once +#include +#include + +void iosCreateEmulator(); +void iosLoadROM(NSString* pathNS); +void iosRunFrame(CAMetalLayer* layer); \ No newline at end of file diff --git a/include/ipc.hpp b/include/ipc.hpp index 204b2e9c..07a77f02 100644 --- a/include/ipc.hpp +++ b/include/ipc.hpp @@ -5,7 +5,7 @@ namespace IPC { namespace BufferType { enum : std::uint32_t { Send = 1, - Receive, + Receive = 2, }; } diff --git a/include/kernel/handles.hpp b/include/kernel/handles.hpp index 5cb7d8a4..58b8beff 100644 --- a/include/kernel/handles.hpp +++ b/include/kernel/handles.hpp @@ -20,6 +20,7 @@ namespace KernelHandles { CFG_U, // CFG service (Console & region info) CFG_I, CFG_S, // Used by most system apps in lieu of cfg:u + CFG_NOR, // Used by system settings app CSND, // Plays audio directly from PCM samples DLP_SRVR, // Download Play: Server. Used for network play. DSP, // DSP service (Used for audio decoding and output) @@ -39,9 +40,10 @@ namespace KernelHandles { NIM_U, // Updates NDM, // ????? NS_S, // Nintendo Shell service + NWM_EXT, // ????? NWM_UDS, // Local multiplayer NEWS_S, // news:u on steroids - NEWS_U, // This service literally has 1 command (AddNotification) and I don't even understand what it does + NEWS_U, // This service literally has 1 command (AddNotification) PTM_U, // PTM service (Used for accessing various console info, such as battery, shell and pedometer state) PTM_SYSM, // PTM system service PTM_PLAY, // PTM Play service, used for retrieving play history @@ -85,6 +87,8 @@ namespace KernelHandles { case CECD: return "CECD"; case CFG_U: return "CFG:U"; case CFG_I: return "CFG:I"; + case CFG_S: return "CFG:S"; + case CFG_NOR: return "CFG:NOR"; case CSND: return "CSND"; case DSP: return "DSP"; case DLP_SRVR: return "DLP::SRVR"; @@ -102,6 +106,7 @@ namespace KernelHandles { case NDM: return "NDM"; case NEWS_S: return "NEWS_S"; case NEWS_U: return "NEWS_U"; + case NWM_EXT: return "nwm::EXT"; case NWM_UDS: return "nwm::UDS"; case NFC: return "NFC"; case NIM_AOC: return "NIM:AOC"; @@ -109,6 +114,7 @@ namespace KernelHandles { case PTM_U: return "PTM:U"; case PTM_SYSM: return "PTM:SYSM"; case PTM_PLAY: return "PTM:PLAY"; + case PTM_GETS: return "PTM:GETS"; case SOC: return "SOC"; case SSL: return "SSL"; case Y2R: return "Y2R"; diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index abc508ac..3f20b5e1 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -175,6 +175,8 @@ public: void svcSignalEvent(); void svcSetTimer(); void svcSleepThread(); + void svcInvalidateInstructionCacheRange(); + void svcInvalidateEntireInstructionCache(); void connectToPort(); void outputDebugString(); void waitSynchronization1(); @@ -250,4 +252,6 @@ public: void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); } void clearInstructionCache(); + void clearInstructionCacheRange(u32 start, u32 size); + u32 getSharedFontVaddr(); }; \ No newline at end of file diff --git a/include/kernel/resource_limits.hpp b/include/kernel/resource_limits.hpp index 85f1a59b..fe1154ff 100644 --- a/include/kernel/resource_limits.hpp +++ b/include/kernel/resource_limits.hpp @@ -19,7 +19,7 @@ struct ResourceLimitValues { // APPLICATION resource limit static constexpr ResourceLimitValues appResourceLimits = { .maxPriority = 0x18, - .maxCommit = 0x4000000, + .maxCommit = 64_MB + 16_MB, // We're currently giving 80MB to all apps. TODO: Implement extended memory properly .maxThreads = 0x20, .maxEvents = 0x20, .maxMutexes = 0x20, @@ -33,7 +33,7 @@ static constexpr ResourceLimitValues appResourceLimits = { // SYS_APPLET resource limit static constexpr ResourceLimitValues sysAppletResourceLimits = { .maxPriority = 0x4, - .maxCommit = 0x5E00000, + .maxCommit = 0x5E00000 - 16_MB, .maxThreads = 0x1D, .maxEvents = 0xB, .maxMutexes = 0x8, diff --git a/include/memory.hpp b/include/memory.hpp index bd002c54..b1dd09de 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -132,7 +132,7 @@ public: static constexpr u32 totalPageCount = 1 << (32 - pageShift); static constexpr u32 FCRAM_SIZE = u32(128_MB); - static constexpr u32 FCRAM_APPLICATION_SIZE = u32(64_MB); + static constexpr u32 FCRAM_APPLICATION_SIZE = u32(80_MB); static constexpr u32 FCRAM_PAGE_COUNT = FCRAM_SIZE / pageSize; static constexpr u32 FCRAM_APPLICATION_PAGE_COUNT = FCRAM_APPLICATION_SIZE / pageSize; diff --git a/include/renderer.hpp b/include/renderer.hpp index bc5dfac6..0798184d 100644 --- a/include/renderer.hpp +++ b/include/renderer.hpp @@ -51,8 +51,12 @@ class Renderer { u32 outputWindowWidth = 400; u32 outputWindowHeight = 240 * 2; + // Should hw renderers hash textures? Stored separately from emulatorConfig because we'll be accessing it constantly, might be merged eventually + bool hashTextures = false; + EmulatorConfig* emulatorConfig = nullptr; + void doSoftwareTextureCopy(u32 inputAddr, u32 outputAddr, u32 copySize, u32 inputWidth, u32 inputGap, u32 outputWidth, u32 outputGap); public: Renderer(GPU& gpu, const std::array& internalRegs, const std::array& externalRegs); virtual ~Renderer(); @@ -81,6 +85,14 @@ class Renderer { virtual std::string getUbershader() { return ""; } virtual void setUbershader(const std::string& shader) {} + // Only relevant for OpenGL renderer and other OpenGL-based backends (eg software) + // Called to notify the core to use OpenGL ES and not desktop GL + virtual void setupGLES() {} + + // Only relevant for Metal renderer on iOS + // Passes a SwiftUI MTKView's layer (CAMetalLayer) to the renderer + virtual void setMTKLayer(void* layer) {}; + // This function is called on every draw call before parsing vertex data. // It is responsible for things like looking up which vertex/fragment shaders to use, recompiling them if they don't exist, choosing between // ubershaders and shadergen, and so on. @@ -114,4 +126,5 @@ class Renderer { } void setConfig(EmulatorConfig* config) { emulatorConfig = config; } + void setHashTextures(bool setting) { hashTextures = setting; } }; diff --git a/include/renderer_gl/gl_driver.hpp b/include/renderer_gl/gl_driver.hpp index a15c061f..4a0b3727 100644 --- a/include/renderer_gl/gl_driver.hpp +++ b/include/renderer_gl/gl_driver.hpp @@ -4,6 +4,7 @@ // Stuff like whether specific extensions are supported, and potentially things like OpenGL context information namespace OpenGL { struct Driver { + bool usingGLES = false; bool supportsExtFbFetch = false; bool supportsArmFbFetch = false; diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index fab239f2..a862cd26 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -40,7 +40,7 @@ class RendererGL final : public Renderer { OpenGL::VertexArray hwShaderVAO; OpenGL::VertexBuffer vbo; - // Data + // Data struct { // TEV configuration uniform locations GLint textureEnvSourceLoc = -1; @@ -157,6 +157,7 @@ class RendererGL final : public Renderer { void initGraphicsContextInternal(); void accelerateVertexUpload(ShaderUnit& shaderUnit, PICA::DrawAcceleration* accel); + void compileDisplayShader(); public: RendererGL(GPU& gpu, const std::array& internalRegs, const std::array& externalRegs) @@ -169,14 +170,15 @@ class RendererGL final : public Renderer { void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) override; // Clear a GPU buffer in VRAM void displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags) override; // Perform display transfer void textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 inputSize, u32 outputSize, u32 flags) override; - void drawVertices(PICA::PrimType primType, std::span vertices) override; // Draw the given vertices + void drawVertices(PICA::PrimType primType, std::span vertices) override; // Draw the given vertices void deinitGraphicsContext() override; virtual bool supportsShaderReload() override { return true; } virtual std::string getUbershader() override; virtual void setUbershader(const std::string& shader) override; virtual bool prepareForDraw(ShaderUnit& shaderUnit, PICA::DrawAcceleration* accel) override; - + virtual void setupGLES() override; + std::optional getColourBuffer(u32 addr, PICA::ColorFmt format, u32 width, u32 height, bool createIfnotFound = true); // Note: The caller is responsible for deleting the currently bound FBO before calling this diff --git a/include/renderer_gl/textures.hpp b/include/renderer_gl/textures.hpp index 4c6ca2dd..9663c2b4 100644 --- a/include/renderer_gl/textures.hpp +++ b/include/renderer_gl/textures.hpp @@ -1,6 +1,8 @@ #pragma once #include #include + +#include "PICA/pica_hash.hpp" #include "PICA/regs.hpp" #include "boost/icl/interval.hpp" #include "helpers.hpp" @@ -11,55 +13,55 @@ template using Interval = boost::icl::right_open_interval; struct Texture { - u32 location; - u32 config; // Magnification/minification filter, wrapping configs, etc - PICA::TextureFmt format; - OpenGL::uvec2 size; - bool valid; + using Hash = PICAHash::HashType; - // Range of VRAM taken up by buffer - Interval range; - // OpenGL resources allocated to buffer - OpenGL::Texture texture; + u32 location; + u32 config; // Magnification/minification filter, wrapping configs, etc + Hash hash = Hash(0); - Texture() : valid(false) {} + PICA::TextureFmt format; + OpenGL::uvec2 size; + bool valid; - Texture(u32 loc, PICA::TextureFmt format, u32 x, u32 y, u32 config, bool valid = true) - : location(loc), format(format), size({x, y}), config(config), valid(valid) { + // Range of VRAM taken up by buffer + Interval range; + // OpenGL resources allocated to buffer + OpenGL::Texture texture; - u64 endLoc = (u64)loc + sizeInBytes(); - // Check if start and end are valid here - range = Interval(loc, (u32)endLoc); - } + Texture() : valid(false) {} - // For 2 textures to "match" we only care about their locations, formats, and dimensions to match - // For other things, such as filtering mode, etc, we can just switch the attributes of the cached texture - bool matches(Texture& other) { - return location == other.location && format == other.format && - size.x() == other.size.x() && size.y() == other.size.y(); - } + Texture(u32 loc, PICA::TextureFmt format, u32 x, u32 y, u32 config, bool valid = true) + : location(loc), format(format), size({x, y}), config(config), valid(valid) { + u64 endLoc = (u64)loc + sizeInBytes(); + // Check if start and end are valid here + range = Interval(loc, (u32)endLoc); + } - void allocate(); - void setNewConfig(u32 newConfig); - void decodeTexture(std::span data); - void free(); - u64 sizeInBytes(); + // For 2 textures to "match" we only care about their locations, formats, and dimensions to match + // For other things, such as filtering mode, etc, we can just switch the attributes of the cached texture + bool matches(Texture& other) { + return location == other.location && hash == other.hash && format == other.format && size.x() == other.size.x() && size.y() == other.size.y(); + } - u32 decodeTexel(u32 u, u32 v, PICA::TextureFmt fmt, std::span data); + void allocate(); + void setNewConfig(u32 newConfig); + void decodeTexture(std::span data); + void free(); + u64 sizeInBytes(); - // Get the morton interleave offset of a texel based on its U and V values - static u32 mortonInterleave(u32 u, u32 v); - // Get the byte offset of texel (u, v) in the texture - static u32 getSwizzledOffset(u32 u, u32 v, u32 width, u32 bytesPerPixel); - static u32 getSwizzledOffset_4bpp(u32 u, u32 v, u32 width); + u32 decodeTexel(u32 u, u32 v, PICA::TextureFmt fmt, std::span data); - // Returns the format of this texture as a string - std::string_view formatToString() { - return PICA::textureFormatToString(format); - } + // Get the morton interleave offset of a texel based on its U and V values + static u32 mortonInterleave(u32 u, u32 v); + // Get the byte offset of texel (u, v) in the texture + static u32 getSwizzledOffset(u32 u, u32 v, u32 width, u32 bytesPerPixel); + static u32 getSwizzledOffset_4bpp(u32 u, u32 v, u32 width); - // Returns the texel at coordinates (u, v) of an ETC1(A4) texture - // TODO: Make hasAlpha a template parameter - u32 getTexelETC(bool hasAlpha, u32 u, u32 v, u32 width, std::span data); - u32 decodeETC(u32 alpha, u32 u, u32 v, u64 colourData); + // Returns the format of this texture as a string + std::string_view formatToString() { return PICA::textureFormatToString(format); } + + // Returns the texel at coordinates (u, v) of an ETC1(A4) texture + // TODO: Make hasAlpha a template parameter + u32 getTexelETC(bool hasAlpha, u32 u, u32 v, u32 width, std::span data); + u32 decodeETC(u32 alpha, u32 u, u32 v, u64 colourData); }; diff --git a/include/renderer_mtl/mtl_render_target.hpp b/include/renderer_mtl/mtl_render_target.hpp index 8f80ea64..65f921da 100644 --- a/include/renderer_mtl/mtl_render_target.hpp +++ b/include/renderer_mtl/mtl_render_target.hpp @@ -57,7 +57,7 @@ namespace Metal { } else if (std::is_same::value) { pixelFormat = PICA::toMTLPixelFormatDepth((PICA::DepthFmt)format); } else { - panic("Invalid format type"); + Helpers::panic("Invalid format type"); } MTL::TextureDescriptor* descriptor = MTL::TextureDescriptor::alloc()->init(); diff --git a/include/renderer_mtl/mtl_texture.hpp b/include/renderer_mtl/mtl_texture.hpp index 93103091..b6989434 100644 --- a/include/renderer_mtl/mtl_texture.hpp +++ b/include/renderer_mtl/mtl_texture.hpp @@ -4,22 +4,28 @@ #include #include +#include "PICA/pica_hash.hpp" #include "PICA/regs.hpp" #include "boost/icl/interval.hpp" #include "helpers.hpp" #include "math_util.hpp" -#include "opengl.hpp" #include "renderer_mtl/pica_to_mtl.hpp" +// TODO: remove dependency on OpenGL +#include "opengl.hpp" template using Interval = boost::icl::right_open_interval; namespace Metal { struct Texture { + using Hash = PICAHash::HashType; + MTL::Device* device; u32 location; u32 config; // Magnification/minification filter, wrapping configs, etc + Hash hash = Hash(0); + PICA::TextureFmt format; OpenGL::uvec2 size; bool valid; @@ -27,7 +33,8 @@ namespace Metal { // Range of VRAM taken up by buffer Interval range; - PICA::PixelFormatInfo formatInfo; + PICA::MTLPixelFormatInfo formatInfo; + MTL::Texture* base = nullptr; MTL::Texture* texture = nullptr; MTL::SamplerState* sampler = nullptr; @@ -43,7 +50,8 @@ namespace Metal { // For 2 textures to "match" we only care about their locations, formats, and dimensions to match // For other things, such as filtering mode, etc, we can just switch the attributes of the cached texture bool matches(Texture& other) { - return location == other.location && format == other.format && size.x() == other.size.x() && size.y() == other.size.y(); + return location == other.location && hash == other.hash && format == other.format && size.x() == other.size.x() && + size.y() == other.size.y(); } void allocate(); @@ -52,22 +60,7 @@ namespace Metal { void free(); u64 sizeInBytes(); - u8 decodeTexelU8(u32 u, u32 v, PICA::TextureFmt fmt, std::span data); - u16 decodeTexelU16(u32 u, u32 v, PICA::TextureFmt fmt, std::span data); - u32 decodeTexelU32(u32 u, u32 v, PICA::TextureFmt fmt, std::span data); - - // Get the morton interleave offset of a texel based on its U and V values - static u32 mortonInterleave(u32 u, u32 v); - // Get the byte offset of texel (u, v) in the texture - static u32 getSwizzledOffset(u32 u, u32 v, u32 width, u32 bytesPerPixel); - static u32 getSwizzledOffset_4bpp(u32 u, u32 v, u32 width); - // Returns the format of this texture as a string std::string_view formatToString() { return PICA::textureFormatToString(format); } - - // Returns the texel at coordinates (u, v) of an ETC1(A4) texture - // TODO: Make hasAlpha a template parameter - u32 getTexelETC(bool hasAlpha, u32 u, u32 v, u32 width, std::span data); - u32 decodeETC(u32 alpha, u32 u, u32 v, u64 colourData); }; } // namespace Metal diff --git a/include/renderer_mtl/pica_to_mtl.hpp b/include/renderer_mtl/pica_to_mtl.hpp index 715088b4..d4c6dc7c 100644 --- a/include/renderer_mtl/pica_to_mtl.hpp +++ b/include/renderer_mtl/pica_to_mtl.hpp @@ -3,31 +3,28 @@ #include #include "PICA/regs.hpp" +// TODO: remove dependency on OpenGL +#include "opengl.hpp" namespace PICA { - struct PixelFormatInfo { + struct MTLPixelFormatInfo { MTL::PixelFormat pixelFormat; size_t bytesPerTexel; + void (*decoder)(OpenGL::uvec2, u32, u32, std::span, u8*); + + bool needsSwizzle = false; + MTL::TextureSwizzleChannels swizzle{ + .red = MTL::TextureSwizzleRed, + .green = MTL::TextureSwizzleGreen, + .blue = MTL::TextureSwizzleBlue, + .alpha = MTL::TextureSwizzleAlpha, + }; }; - constexpr PixelFormatInfo pixelFormatInfos[14] = { - {MTL::PixelFormatRGBA8Unorm, 4}, // RGBA8 - {MTL::PixelFormatRGBA8Unorm, 4}, // RGB8 - {MTL::PixelFormatBGR5A1Unorm, 2}, // RGBA5551 - {MTL::PixelFormatB5G6R5Unorm, 2}, // RGB565 - {MTL::PixelFormatABGR4Unorm, 2}, // RGBA4 - {MTL::PixelFormatRGBA8Unorm, 4}, // IA8 - {MTL::PixelFormatRG8Unorm, 2}, // RG8 - {MTL::PixelFormatRGBA8Unorm, 4}, // I8 - {MTL::PixelFormatA8Unorm, 1}, // A8 - {MTL::PixelFormatABGR4Unorm, 2}, // IA4 - {MTL::PixelFormatABGR4Unorm, 2}, // I4 - {MTL::PixelFormatA8Unorm, 1}, // A4 - {MTL::PixelFormatRGBA8Unorm, 4}, // ETC1 - {MTL::PixelFormatRGBA8Unorm, 4}, // ETC1A4 - }; + extern MTLPixelFormatInfo mtlPixelFormatInfos[14]; - inline PixelFormatInfo getPixelFormatInfo(TextureFmt format) { return pixelFormatInfos[static_cast(format)]; } + void checkForMTLPixelFormatSupport(MTL::Device* device); + inline MTLPixelFormatInfo getMTLPixelFormatInfo(TextureFmt format) { return mtlPixelFormatInfos[static_cast(format)]; } inline MTL::PixelFormat toMTLPixelFormatColor(ColorFmt format) { switch (format) { @@ -35,7 +32,11 @@ namespace PICA { case ColorFmt::RGB8: return MTL::PixelFormatRGBA8Unorm; case ColorFmt::RGBA5551: return MTL::PixelFormatRGBA8Unorm; // TODO: use MTL::PixelFormatBGR5A1Unorm? case ColorFmt::RGB565: return MTL::PixelFormatRGBA8Unorm; // TODO: use MTL::PixelFormatB5G6R5Unorm? +#ifdef PANDA3DS_IOS + case ColorFmt::RGBA4: return MTL::PixelFormatRGBA8Unorm; // IOS + Metal doesn't support AGBR4 properly, at least on simulator +#else case ColorFmt::RGBA4: return MTL::PixelFormatABGR4Unorm; +#endif } } diff --git a/include/renderer_mtl/renderer_mtl.hpp b/include/renderer_mtl/renderer_mtl.hpp index bd5c3bf1..10fac7cd 100644 --- a/include/renderer_mtl/renderer_mtl.hpp +++ b/include/renderer_mtl/renderer_mtl.hpp @@ -42,11 +42,13 @@ class RendererMTL final : public Renderer { virtual void initGraphicsContext([[maybe_unused]] GL::Context* context) override {} #endif - private: - CA::MetalLayer* metalLayer; + virtual void setMTKLayer(void* layer) override; - MTL::Device* device; - MTL::CommandQueue* commandQueue; + private: + CA::MetalLayer* metalLayer = nullptr; + + MTL::Device* device = nullptr; + MTL::CommandQueue* commandQueue = nullptr; Metal::CommandEncoder commandEncoder; @@ -98,6 +100,7 @@ class RendererMTL final : public Renderer { void endRenderPass() { if (renderCommandEncoder) { renderCommandEncoder->endEncoding(); + renderCommandEncoder->release(); renderCommandEncoder = nullptr; } } diff --git a/include/renderer_mtl/texture_decoder.hpp b/include/renderer_mtl/texture_decoder.hpp new file mode 100644 index 00000000..376231c0 --- /dev/null +++ b/include/renderer_mtl/texture_decoder.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "helpers.hpp" +// TODO: remove dependency on OpenGL +#include "opengl.hpp" + +void decodeTexelABGR8ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelBGR8ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelA1BGR5ToBGR5A1(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelA1BGR5ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelB5G6R5ToB5G6R5(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelB5G6R5ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelABGR4ToABGR4(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelABGR4ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelAI8ToRG8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelGR8ToRG8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelI8ToR8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelA8ToA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelAI4ToABGR4(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelAI4ToRG8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelI4ToR8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelA4ToA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelETC1ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); +void decodeTexelETC1A4ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData); diff --git a/include/renderer_vk/vk_debug.hpp b/include/renderer_vk/vk_debug.hpp index ed712269..0cf3f938 100644 --- a/include/renderer_vk/vk_debug.hpp +++ b/include/renderer_vk/vk_debug.hpp @@ -9,8 +9,8 @@ namespace Vulkan { VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData + vk::DebugUtilsMessageSeverityFlagBitsEXT messageSeverity, vk::DebugUtilsMessageTypeFlagsEXT messageType, + const vk::DebugUtilsMessengerCallbackDataEXT* callbackData, void* userData ); void setObjectName(vk::Device device, vk::ObjectType objectType, const void* objectHandle, const char* format, ...); diff --git a/include/services/cfg.hpp b/include/services/cfg.hpp index 0feb6db3..bac2cd87 100644 --- a/include/services/cfg.hpp +++ b/include/services/cfg.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include "config.hpp" #include "helpers.hpp" #include "logger.hpp" #include "memory.hpp" @@ -11,6 +12,8 @@ class CFGService { using Handle = HorizonHandle; Memory& mem; + const EmulatorConfig& settings; + CountryCodes country = CountryCodes::US; // Default to USA MAKE_LOG_FUNCTION(log, cfgLogger) @@ -18,8 +21,9 @@ class CFGService { // Service functions void getConfigInfoBlk2(u32 messagePointer); - void getConfigInfoBlk8(u32 messagePointer); + void getConfigInfoBlk8(u32 messagePointer, u32 commandWord); void getCountryCodeID(u32 messagePointer); + void getCountryCodeString(u32 messagePointer); void getLocalFriendCodeSeed(u32 messagePointer); void getRegionCanadaUSA(u32 messagePointer); void getSystemModel(u32 messagePointer); @@ -29,6 +33,11 @@ class CFGService { void setConfigInfoBlk4(u32 messagePointer); void updateConfigNANDSavegame(u32 messagePointer); void translateCountryInfo(u32 messagePointer); + void isFangateSupported(u32 messagePointer); + + // cfg:nor functions + void norInitialize(u32 messagePointer); + void norReadData(u32 messagePointer); void getConfigInfo(u32 output, u32 blockID, u32 size, u32 permissionMask); @@ -40,7 +49,7 @@ class CFGService { NOR, // cfg:nor }; - CFGService(Memory& mem) : mem(mem) {} + CFGService(Memory& mem, const EmulatorConfig& settings) : mem(mem), settings(settings) {} void reset(); void handleSyncRequest(u32 messagePointer, Type type); }; \ No newline at end of file diff --git a/include/services/gsp_gpu.hpp b/include/services/gsp_gpu.hpp index 8294565b..4ac8e747 100644 --- a/include/services/gsp_gpu.hpp +++ b/include/services/gsp_gpu.hpp @@ -121,4 +121,4 @@ class GPUService { std::memset(ptr, 0, 0x1000); } } -}; +}; \ No newline at end of file diff --git a/include/services/gsp_lcd.hpp b/include/services/gsp_lcd.hpp index 302771ff..7dbdae8f 100644 --- a/include/services/gsp_lcd.hpp +++ b/include/services/gsp_lcd.hpp @@ -6,9 +6,6 @@ #include "result/result.hpp" class LCDService { - using Handle = HorizonHandle; - - Handle handle = KernelHandles::LCD; Memory& mem; MAKE_LOG_FUNCTION(log, gspLCDLogger) diff --git a/include/services/ns.hpp b/include/services/ns.hpp index 3acf87a0..cb00e49b 100644 --- a/include/services/ns.hpp +++ b/include/services/ns.hpp @@ -6,20 +6,20 @@ #include "result/result.hpp" class NSService { - Memory& mem; + Memory& mem; MAKE_LOG_FUNCTION(log, nsLogger) - // Service commands - void launchTitle(u32 messagePointer); + // Service commands + void launchTitle(u32 messagePointer); -public: - enum class Type { - S, // ns:s - P, // ns:p - C, // ns:c - }; + public: + enum class Type { + S, // ns:s + P, // ns:p + C, // ns:c + }; - NSService(Memory& mem) : mem(mem) {} - void reset(); + NSService(Memory& mem) : mem(mem) {} + void reset(); void handleSyncRequest(u32 messagePointer, Type type); }; diff --git a/readme.md b/readme.md index 7ffb7384..438a2b95 100644 --- a/readme.md +++ b/readme.md @@ -35,7 +35,7 @@ Panda3DS is still in the early stages of development. Many games boot, many don' For documenting game compatibility, make sure to visit the [games list repository](https://github.com/Panda3DS-emu/Panda3DS-Games-List). For miscellaneous issues or more technical issues, feel free to use this repo's issues tab. # Why? -The 3DS emulation scene is already pretty mature, with offerings such as [Citra](https://github.com/citra-emu/citra) which can offer a great playing experience for most games in the library, [Corgi3DS](https://github.com/PSI-Rockin/Corgi3DS), an innovative LLE emulator, or [Mikage](https://mikage.app/). However, there's always room for more emulators! While Panda3DS was initially a mere curiosity, there's many different concepts I would like to explore with it in the future, such as: +The 3DS emulation scene is already pretty mature, with offerings such as Citra which can offer a great playing experience for most games in the library, [Corgi3DS](https://github.com/PSI-Rockin/Corgi3DS), an innovative LLE emulator, or [Mikage](https://mikage.app/). However, there's always room for more emulators! While Panda3DS was initially a mere curiosity, there's many different concepts I would like to explore with it in the future, such as: - Virtualization. What motivated the creation of this emulator was actually a discussion on whether it is possible to get fast 3DS emulation on low-end hardware such as the Raspberry Pi 4, using the KVM API. At the moment, Panda3DS is powered by Dynarmic rather than using virtualization, but this is definitely a concept I want to explore in the future. @@ -113,11 +113,12 @@ Panda3DS also supports controller input using the SDL2 GameController API. - [SkyEmu](https://github.com/skylersaleh/SkyEmu): A seagull-themed low-level GameBoy, GameBoy Color, GameBoy Advance and Nintendo DS emulator that is designed to be easy to use, cross platform and accurate. - [NanoBoyAdvance](https://github.com/nba-emu/NanoBoyAdvance): A Game Boy Advance emulator focusing on hardware research and cycle-accurate emulation - [Dust](https://github.com/kelpsyberry/dust): Nintendo DS emulator for desktop devices and the web +- [felix86](https://github.com/OFFTKP/felix86): A new x86-64 → RISC-V Linux userspace emulator +- [ChonkyStation](https://github.com/liuk7071/ChonkyStation): Work-in-progress PlayStation emulator +- [ChonkyStation 3](https://github.com/liuk7071/ChonkyStation3): Experimental HLE PS3 emulator for Windows, MacOS and Linux - [MelonDS](https://github.com/melonDS-emu/melonDS): "DS emulator, sorta" - Arisotura - [Kaizen](https://github.com/SimoneN64/Kaizen): Experimental work-in-progress low-level N64 emulator -- [ChonkyStation](https://github.com/liuk7071/ChonkyStation): Work-in-progress PlayStation emulator - [shadPS4](https://github.com/shadps4-emu/shadPS4): Work-in-progress PS4 emulator by the founder of PCSX, PCSX2 and more -- [Hydra](https://github.com/hydra-emu/hydra): Cross-platform GameBoy, NES, N64 and Chip-8 emulator - [Tanuki3DS](https://github.com/burhanr13/Tanuki3DS/): A new 3DS emulator for MacOS and Linux # Support If you find this project exciting and want to support the founder, check out [his Patreon](https://www.patreon.com/wheremyfoodat) or [Ko-fi](https://ko-fi.com/wheremyfoodat) diff --git a/src/config.cpp b/src/config.cpp index 73b5d664..59f10bd5 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "helpers.hpp" #include "toml.hpp" @@ -26,6 +27,7 @@ void EmulatorConfig::load() { return; } + printf("Loading existing configuration file %s\n", path.string().c_str()); toml::value data; try { @@ -45,6 +47,7 @@ void EmulatorConfig::load() { defaultRomPath = toml::find_or(general, "DefaultRomPath", ""); printAppVersion = toml::find_or(general, "PrintAppVersion", true); + systemLanguage = languageCodeFromString(toml::find_or(general, "SystemLanguage", "en")); } } @@ -69,14 +72,14 @@ void EmulatorConfig::load() { auto gpu = gpuResult.unwrap(); // Get renderer - auto rendererName = toml::find_or(gpu, "Renderer", "OpenGL"); + auto rendererName = toml::find_or(gpu, "Renderer", Renderer::typeToString(rendererDefault)); auto configRendererType = Renderer::typeFromString(rendererName); if (configRendererType.has_value()) { rendererType = configRendererType.value(); } else { Helpers::warn("Invalid renderer specified: %s\n", rendererName.c_str()); - rendererType = RendererType::OpenGL; + rendererType = rendererDefault; } shaderJitEnabled = toml::find_or(gpu, "EnableShaderJIT", shaderJitDefault); @@ -87,6 +90,7 @@ void EmulatorConfig::load() { forceShadergenForLights = toml::find_or(gpu, "ForceShadergenForLighting", true); lightShadergenThreshold = toml::find_or(gpu, "ShadergenLightThreshold", 1); + hashTextures = toml::find_or(gpu, "HashTextures", hashTexturesDefault); enableRenderdoc = toml::find_or(gpu, "EnableRenderdoc", false); } } @@ -98,8 +102,8 @@ void EmulatorConfig::load() { auto dspCoreName = toml::find_or(audio, "DSPEmulation", "HLE"); dspType = Audio::DSPCore::typeFromString(dspCoreName); - - audioEnabled = toml::find_or(audio, "EnableAudio", false); + + audioEnabled = toml::find_or(audio, "EnableAudio", audioEnabledDefault); aacEnabled = toml::find_or(audio, "EnableAACAudio", true); printDSPFirmware = toml::find_or(audio, "PrintDSPFirmware", false); @@ -169,6 +173,7 @@ void EmulatorConfig::save() { data["General"]["UsePortableBuild"] = usePortableBuild; data["General"]["DefaultRomPath"] = defaultRomPath.string(); data["General"]["PrintAppVersion"] = printAppVersion; + data["General"]["SystemLanguage"] = languageCodeToString(systemLanguage); data["Window"]["AppVersionOnWindow"] = windowSettings.showAppVersion; data["Window"]["RememberWindowPosition"] = windowSettings.rememberPosition; @@ -176,7 +181,7 @@ void EmulatorConfig::save() { data["Window"]["WindowPosY"] = windowSettings.y; data["Window"]["WindowWidth"] = windowSettings.width; data["Window"]["WindowHeight"] = windowSettings.height; - + data["GPU"]["EnableShaderJIT"] = shaderJitEnabled; data["GPU"]["Renderer"] = std::string(Renderer::typeToString(rendererType)); data["GPU"]["EnableVSync"] = vsyncEnabled; @@ -186,6 +191,7 @@ void EmulatorConfig::save() { data["GPU"]["ShadergenLightThreshold"] = lightShadergenThreshold; data["GPU"]["AccelerateShaders"] = accelerateShaders; data["GPU"]["EnableRenderdoc"] = enableRenderdoc; + data["GPU"]["HashTextures"] = hashTextures; data["Audio"]["DSPEmulation"] = std::string(Audio::DSPCore::typeToString(dspType)); data["Audio"]["EnableAudio"] = audioEnabled; @@ -231,4 +237,34 @@ const char* AudioDeviceConfig::volumeCurveToString(AudioDeviceConfig::VolumeCurv case VolumeCurve::Cubic: default: return "cubic"; } +} + +LanguageCodes EmulatorConfig::languageCodeFromString(std::string inString) { // Transform to lower-case to make the setting case-insensitive + std::transform(inString.begin(), inString.end(), inString.begin(), [](unsigned char c) { return std::tolower(c); }); + + static const std::unordered_map map = { + {"ja", LanguageCodes::Japanese}, {"en", LanguageCodes::English}, {"fr", LanguageCodes::French}, {"de", LanguageCodes::German}, + {"it", LanguageCodes::Italian}, {"es", LanguageCodes::Spanish}, {"zh", LanguageCodes::Chinese}, {"ko", LanguageCodes::Korean}, + {"nl", LanguageCodes::Dutch}, {"pt", LanguageCodes::Portuguese}, {"ru", LanguageCodes::Russian}, {"tw", LanguageCodes::Taiwanese}, + }; + + if (auto search = map.find(inString); search != map.end()) { + return search->second; + } + + // Default to English if no language code in our map matches + return LanguageCodes::English; +} + +const char* EmulatorConfig::languageCodeToString(LanguageCodes code) { + static constexpr std::array codes = { + "ja", "en", "fr", "de", "it", "es", "zh", "ko", "nl", "pt", "ru", "tw", + }; + + // Invalid country code, return english + if (static_cast(code) > static_cast(LanguageCodes::Taiwanese)) { + return "en"; + } else { + return codes[static_cast(code)]; + } } \ No newline at end of file diff --git a/src/core/PICA/regs.cpp b/src/core/PICA/regs.cpp index 4c865d12..f63ee186 100644 --- a/src/core/PICA/regs.cpp +++ b/src/core/PICA/regs.cpp @@ -284,7 +284,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { break; case VertexShaderOpDescriptorIndex: { - shaderUnit.vs.setOpDescriptorIndex(value); + shaderUnit.vs.setOpDescriptorIndex(newValue); break; } @@ -301,7 +301,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { } case VertexBoolUniform: { - shaderUnit.vs.uploadBoolUniform(value & 0xffff); + shaderUnit.vs.uploadBoolUniform(newValue & 0xffff); break; } @@ -309,7 +309,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { case VertexIntUniform1: case VertexIntUniform2: case VertexIntUniform3: { - shaderUnit.vs.uploadIntUniform(index - VertexIntUniform0, value); + shaderUnit.vs.uploadIntUniform(index - VertexIntUniform0, newValue); break; } @@ -326,7 +326,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { } case VertexShaderEntrypoint: { - shaderUnit.vs.entrypoint = value & 0xffff; + shaderUnit.vs.entrypoint = newValue & 0xffff; break; } @@ -336,13 +336,13 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) { break; */ - case VertexShaderTransferIndex: shaderUnit.vs.setBufferIndex(value); break; + case VertexShaderTransferIndex: shaderUnit.vs.setBufferIndex(newValue); break; // Command lists can write to the command processor registers and change the command list stream // Several games are known to do this, including New Super Mario Bros 2 and Super Mario 3D Land case CmdBufTrigger0: case CmdBufTrigger1: { - if (value != 0) { // A non-zero value triggers command list processing + if (newValue != 0) { // A non-zero value triggers command list processing int bufferIndex = index - CmdBufTrigger0; // Index of the command buffer to execute (0 or 1) u32 addr = (regs[CmdBufAddr0 + bufferIndex] & 0xfffffff) << 3; u32 size = (regs[CmdBufSize0 + bufferIndex] & 0xfffff) << 3; diff --git a/src/core/audio/miniaudio_device.cpp b/src/core/audio/miniaudio_device.cpp index 550fb039..8e2a1e71 100644 --- a/src/core/audio/miniaudio_device.cpp +++ b/src/core/audio/miniaudio_device.cpp @@ -7,8 +7,9 @@ #include "helpers.hpp" -MiniAudioDevice::MiniAudioDevice(const AudioDeviceConfig& audioSettings) - : initialized(false), running(false), samples(nullptr), audioSettings(audioSettings) {} +MiniAudioDevice::MiniAudioDevice(const AudioDeviceConfig& audioSettings) : AudioDeviceInterface(nullptr, audioSettings), initialized(false) { + running = false; +} void MiniAudioDevice::init(Samples& samples, bool safe) { this->samples = &samples; @@ -212,4 +213,4 @@ void MiniAudioDevice::close() { ma_device_uninit(&device); ma_context_uninit(&context); } -} +} \ No newline at end of file diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index d4229b55..e097fab6 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -69,6 +69,10 @@ void Kernel::serviceSVC(u32 svc) { case 0x3A: getResourceLimitCurrentValues(); break; case 0x3B: getThreadContext(); break; case 0x3D: outputDebugString(); break; + + // Luma SVCs + case 0x93: svcInvalidateInstructionCacheRange(); break; + case 0x94: svcInvalidateEntireInstructionCache(); break; default: Helpers::panic("Unimplemented svc: %X @ %08X", svc, regs[15]); break; } @@ -298,6 +302,23 @@ void Kernel::duplicateHandle() { } void Kernel::clearInstructionCache() { cpu.clearCache(); } +void Kernel::clearInstructionCacheRange(u32 start, u32 size) { cpu.clearCacheRange(start, size); } + +void Kernel::svcInvalidateInstructionCacheRange() { + const u32 start = regs[0]; + const u32 size = regs[1]; + logSVC("svcInvalidateInstructionCacheRange(start = %08X, size = %08X)\n", start, size); + + clearInstructionCacheRange(start, size); + regs[0] = Result::Success; +} + +void Kernel::svcInvalidateEntireInstructionCache() { + logSVC("svcInvalidateEntireInstructionCache()\n"); + + clearInstructionCache(); + regs[0] = Result::Success; +} namespace SystemInfoType { enum : u32 { diff --git a/src/core/kernel/memory_management.cpp b/src/core/kernel/memory_management.cpp index 26f50023..18038d2e 100644 --- a/src/core/kernel/memory_management.cpp +++ b/src/core/kernel/memory_management.cpp @@ -122,7 +122,10 @@ void Kernel::mapMemoryBlock() { } if (KernelHandles::isSharedMemHandle(block)) { - if (block == KernelHandles::FontSharedMemHandle && addr == 0) addr = 0x18000000; + if (block == KernelHandles::FontSharedMemHandle && addr == 0) { + addr = getSharedFontVaddr(); + } + u8* ptr = mem.mapSharedMemory(block, addr, myPerms, otherPerms); // Map shared memory block // Pass pointer to shared memory to the appropriate service @@ -216,3 +219,8 @@ void Kernel::unmapMemoryBlock() { Helpers::warn("Stubbed svcUnmapMemoryBlock!"); regs[0] = Result::Success; } + +u32 Kernel::getSharedFontVaddr() { + // Place shared font at the very beginning of system FCRAM + return mem.getLinearHeapVaddr() + Memory::FCRAM_APPLICATION_SIZE; +} \ No newline at end of file diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 90b8f910..828ca120 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -8,6 +8,7 @@ #include "PICA/float_types.hpp" #include "PICA/gpu.hpp" #include "PICA/pica_frag_uniforms.hpp" +#include "PICA/pica_hash.hpp" #include "PICA/pica_simd.hpp" #include "PICA/regs.hpp" #include "PICA/shader_decompiler.hpp" @@ -51,17 +52,12 @@ void RendererGL::reset() { gl.useProgram(oldProgram); // Switch to old GL program } - -#ifdef USING_GLES - fragShaderGen.setTarget(PICA::ShaderGen::API::GLES, PICA::ShaderGen::Language::GLSL); -#endif } void RendererGL::initGraphicsContextInternal() { gl.reset(); auto gl_resources = cmrc::RendererGL::get_filesystem(); - auto vertexShaderSource = gl_resources.open("opengl_vertex_shader.vert"); auto fragmentShaderSource = gl_resources.open("opengl_fragment_shader.frag"); @@ -70,16 +66,7 @@ void RendererGL::initGraphicsContextInternal() { triangleProgram.create({vert, frag}); initUbershader(triangleProgram); - auto displayVertexShaderSource = gl_resources.open("opengl_display.vert"); - auto displayFragmentShaderSource = gl_resources.open("opengl_display.frag"); - - OpenGL::Shader vertDisplay({displayVertexShaderSource.begin(), displayVertexShaderSource.size()}, OpenGL::Vertex); - OpenGL::Shader fragDisplay({displayFragmentShaderSource.begin(), displayFragmentShaderSource.size()}, OpenGL::Fragment); - displayProgram.create({vertDisplay, fragDisplay}); - - gl.useProgram(displayProgram); - glUniform1i(OpenGL::uniformLocation(displayProgram, "u_texture"), 0); // Init sampler object - + compileDisplayShader(); // Create stream buffers for vertex, index and uniform buffers static constexpr usize hwIndexBufferSize = 2_MB; static constexpr usize hwVertexBufferSize = 16_MB; @@ -191,6 +178,7 @@ void RendererGL::initGraphicsContextInternal() { } reset(); + fragShaderGen.setTarget(driverInfo.usingGLES ? PICA::ShaderGen::API::GLES : PICA::ShaderGen::API::GL, PICA::ShaderGen::Language::GLSL); // Populate our driver info structure driverInfo.supportsExtFbFetch = (GLAD_GL_EXT_shader_framebuffer_fetch != 0); @@ -372,17 +360,29 @@ void RendererGL::bindTexturesToSlots() { const u32 width = getBits<16, 11>(dim); const u32 addr = (regs[ioBase + 4] & 0x0FFFFFFF) << 3; u32 format = regs[ioBase + (i == 0 ? 13 : 5)] & 0xF; - glActiveTexture(GL_TEXTURE0 + i); if (addr != 0) [[likely]] { Texture targetTex(addr, static_cast(format), width, height, config); + + if (hashTextures) { + const u8* startPointer = gpu.getPointerPhys(targetTex.location); + const usize sizeInBytes = targetTex.sizeInBytes(); + + if (startPointer == nullptr || (sizeInBytes > 0 && gpu.getPointerPhys(targetTex.location + sizeInBytes - 1) == nullptr)) + [[unlikely]] { + Helpers::warn("Out-of-bounds texture fetch"); + } else { + targetTex.hash = PICAHash::computeHash((const char*)startPointer, sizeInBytes); + } + } + OpenGL::Texture tex = getTexture(targetTex); tex.bind(); } else { - // Mapping a texture from NULL. PICA seems to read the last sampled colour, but for now we will display a black texture instead since it is far easier. - // Games that do this don't really care what it does, they just expect the PICA to not crash, since it doesn't have a PU/MMU and can do all sorts of - // Weird invalid memory accesses without crashing + // Mapping a texture from NULL. PICA seems to read the last sampled colour, but for now we will display a black texture instead since it + // is far easier. Games that do this don't really care what it does, they just expect the PICA to not crash, since it doesn't have a + // PU/MMU and can do all sorts of Weird invalid memory accesses without crashing blankTexture.bind(); } } @@ -805,6 +805,8 @@ void RendererGL::textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 shutUpCounter++; printf("RendererGL::TextureCopy failed to locate src framebuffer!\n"); } + + doSoftwareTextureCopy(inputAddr, outputAddr, copySize, inputWidth, inputGap, outputWidth, outputGap); return; } @@ -850,9 +852,9 @@ OpenGL::Program& RendererGL::getSpecializedShader() { PICA::FragmentConfig fsConfig(regs); // If we're not on GLES, ignore the logic op configuration and don't generate redundant shaders for it, since we use hw logic ops -#ifndef USING_GLES - fsConfig.outConfig.logicOpMode = PICA::LogicOpMode(0); -#endif + if (!driverInfo.usingGLES) { + fsConfig.outConfig.logicOpMode = PICA::LogicOpMode(0); + } OpenGL::Shader& fragShader = shaderCache.fragmentShaderCache[fsConfig]; if (!fragShader.exists()) { @@ -1010,7 +1012,7 @@ bool RendererGL::prepareForDraw(ShaderUnit& shaderUnit, PICA::DrawAcceleration* std::string picaShaderSource = PICA::ShaderGen::decompileShader( shaderUnit.vs, *emulatorConfig, shaderUnit.vs.entrypoint, - Helpers::isAndroid() ? PICA::ShaderGen::API::GLES : PICA::ShaderGen::API::GL, PICA::ShaderGen::Language::GLSL + driverInfo.usingGLES ? PICA::ShaderGen::API::GLES : PICA::ShaderGen::API::GL, PICA::ShaderGen::Language::GLSL ); // Empty source means compilation error, if the source is not empty then we convert the recompiled PICA code into a valid shader and upload @@ -1156,6 +1158,19 @@ void RendererGL::initUbershader(OpenGL::Program& program) { glUniform1i(OpenGL::uniformLocation(program, "u_tex_luts"), 3); } +void RendererGL::compileDisplayShader() { + auto gl_resources = cmrc::RendererGL::get_filesystem(); + auto displayVertexShaderSource = driverInfo.usingGLES ? gl_resources.open("opengl_es_display.vert") : gl_resources.open("opengl_display.vert"); + auto displayFragmentShaderSource = driverInfo.usingGLES ? gl_resources.open("opengl_es_display.frag") : gl_resources.open("opengl_display.frag"); + + OpenGL::Shader vertDisplay({displayVertexShaderSource.begin(), displayVertexShaderSource.size()}, OpenGL::Vertex); + OpenGL::Shader fragDisplay({displayFragmentShaderSource.begin(), displayFragmentShaderSource.size()}, OpenGL::Fragment); + displayProgram.create({vertDisplay, fragDisplay}); + + gl.useProgram(displayProgram); + glUniform1i(OpenGL::uniformLocation(displayProgram, "u_texture"), 0); // Init sampler object +} + void RendererGL::accelerateVertexUpload(ShaderUnit& shaderUnit, PICA::DrawAcceleration* accel) { u32 buffer = 0; // Vertex buffer index for non-fixed attributes u32 attrCount = 0; @@ -1250,4 +1265,20 @@ void RendererGL::accelerateVertexUpload(ShaderUnit& shaderUnit, PICA::DrawAccele ); } } -} \ No newline at end of file +} + +void RendererGL::setupGLES() { + driverInfo.usingGLES = true; + + // OpenGL ES hardware is typically way too slow to use the ubershader (eg RPi, mobile phones, handhelds) or has other issues with it. + // So, display a warning and turn them off on OpenGL ES. + if (emulatorConfig->useUbershaders) { + emulatorConfig->useUbershaders = false; + Helpers::warn("Ubershaders enabled on OpenGL ES. This usually results in a worse experience, turning it off..."); + } + + // Stub out logic operations so that calling them doesn't crash the emulator + if (!glLogicOp) { + glLogicOp = [](GLenum) {}; + } +} diff --git a/src/core/renderer_mtl/mtl_etc1.cpp b/src/core/renderer_mtl/mtl_etc1.cpp deleted file mode 100644 index 420a60ca..00000000 --- a/src/core/renderer_mtl/mtl_etc1.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include - -#include "colour.hpp" -#include "renderer_mtl/mtl_texture.hpp" -#include "renderer_mtl/renderer_mtl.hpp" - - -using namespace Helpers; - -namespace Metal { - static constexpr u32 signExtend3To32(u32 val) { - return (u32)(s32(val) << 29 >> 29); - } - - u32 Texture::getTexelETC(bool hasAlpha, u32 u, u32 v, u32 width, std::span data) { - // Pixel offset of the 8x8 tile based on u, v and the width of the texture - u32 offs = ((u & ~7) * 8) + ((v & ~7) * width); - if (!hasAlpha) { - offs >>= 1; - } - - // In-tile offsets for u/v - u &= 7; - v &= 7; - - // ETC1(A4) also subdivide the 8x8 tile to 4 4x4 tiles - // Each tile is 8 bytes for ETC1, but since ETC1A4 has 4 alpha bits per pixel, that becomes 16 bytes - const u32 subTileSize = hasAlpha ? 16 : 8; - const u32 subTileIndex = (u / 4) + 2 * (v / 4); // Which of the 4 subtiles is this texel in? - - // In-subtile offsets for u/v - u &= 3; - v &= 3; - offs += subTileSize * subTileIndex; - - u32 alpha; - const u64* ptr = reinterpret_cast(data.data() + offs); // Cast to u64* - - if (hasAlpha) { - // First 64 bits of the 4x4 subtile are alpha data - const u64 alphaData = *ptr++; - alpha = Colour::convert4To8Bit((alphaData >> (4 * (u * 4 + v))) & 0xf); - } else { - alpha = 0xff; // ETC1 without alpha uses ff for every pixel - } - - // Next 64 bits of the subtile are colour data - u64 colourData = *ptr; - return decodeETC(alpha, u, v, colourData); - } - - u32 Texture::decodeETC(u32 alpha, u32 u, u32 v, u64 colourData) { - static constexpr u32 modifiers[8][2] = { - {2, 8}, {5, 17}, {9, 29}, {13, 42}, {18, 60}, {24, 80}, {33, 106}, {47, 183}, - }; - - // Parse colour data for 4x4 block - const u32 subindices = getBits<0, 16, u32>(colourData); - const u32 negationFlags = getBits<16, 16, u32>(colourData); - const bool flip = getBit<32>(colourData); - const bool diffMode = getBit<33>(colourData); - - // Note: index1 is indeed stored on the higher bits, with index2 in the lower bits - const u32 tableIndex1 = getBits<37, 3, u32>(colourData); - const u32 tableIndex2 = getBits<34, 3, u32>(colourData); - const u32 texelIndex = u * 4 + v; // Index of the texel in the block - - if (flip) std::swap(u, v); - - s32 r, g, b; - if (diffMode) { - r = getBits<59, 5, s32>(colourData); - g = getBits<51, 5, s32>(colourData); - b = getBits<43, 5, s32>(colourData); - - if (u >= 2) { - r += signExtend3To32(getBits<56, 3, u32>(colourData)); - g += signExtend3To32(getBits<48, 3, u32>(colourData)); - b += signExtend3To32(getBits<40, 3, u32>(colourData)); - } - - // Expand from 5 to 8 bits per channel - r = Colour::convert5To8Bit(r); - g = Colour::convert5To8Bit(g); - b = Colour::convert5To8Bit(b); - } else { - if (u < 2) { - r = getBits<60, 4, s32>(colourData); - g = getBits<52, 4, s32>(colourData); - b = getBits<44, 4, s32>(colourData); - } else { - r = getBits<56, 4, s32>(colourData); - g = getBits<48, 4, s32>(colourData); - b = getBits<40, 4, s32>(colourData); - } - - // Expand from 4 to 8 bits per channel - r = Colour::convert4To8Bit(r); - g = Colour::convert4To8Bit(g); - b = Colour::convert4To8Bit(b); - } - - const u32 index = (u < 2) ? tableIndex1 : tableIndex2; - s32 modifier = modifiers[index][(subindices >> texelIndex) & 1]; - - if (((negationFlags >> texelIndex) & 1) != 0) { - modifier = -modifier; - } - - r = std::clamp(r + modifier, 0, 255); - g = std::clamp(g + modifier, 0, 255); - b = std::clamp(b + modifier, 0, 255); - - return (alpha << 24) | (u32(b) << 16) | (u32(g) << 8) | u32(r); - } -} // namespace Metal diff --git a/src/core/renderer_mtl/mtl_texture.cpp b/src/core/renderer_mtl/mtl_texture.cpp index 149fea26..29d4024a 100644 --- a/src/core/renderer_mtl/mtl_texture.cpp +++ b/src/core/renderer_mtl/mtl_texture.cpp @@ -1,16 +1,18 @@ #include "renderer_mtl/mtl_texture.hpp" +#include + #include +#include #include "colour.hpp" #include "renderer_mtl/objc_helper.hpp" - using namespace Helpers; namespace Metal { void Texture::allocate() { - formatInfo = PICA::getPixelFormatInfo(format); + formatInfo = PICA::getMTLPixelFormatInfo(format); MTL::TextureDescriptor* descriptor = MTL::TextureDescriptor::alloc()->init(); descriptor->setTextureType(MTL::TextureType2D); @@ -20,11 +22,14 @@ namespace Metal { descriptor->setUsage(MTL::TextureUsageShaderRead); descriptor->setStorageMode(MTL::StorageModeShared); // TODO: use private + staging buffers? texture = device->newTexture(descriptor); - texture->setLabel(toNSString( - "Texture " + std::string(PICA::textureFormatToString(format)) + " " + std::to_string(size.u()) + "x" + std::to_string(size.v()) - )); + texture->setLabel(toNSString(fmt::format("Base texture {} {}x{}", std::string(PICA::textureFormatToString(format)), size.u(), size.v()))); descriptor->release(); + if (formatInfo.needsSwizzle) { + base = texture; + texture = base->newTextureView(formatInfo.pixelFormat, MTL::TextureType2D, NS::Range(0, 1), NS::Range(0, 1), formatInfo.swizzle); + } + setNewConfig(config); } @@ -58,6 +63,11 @@ namespace Metal { if (texture) { texture->release(); } + + if (base) { + base->release(); + } + if (sampler) { sampler->release(); } @@ -99,210 +109,19 @@ namespace Metal { } } - // u and v are the UVs of the relevant texel - // Texture data is stored interleaved in Morton order, ie in a Z - order curve as shown here - // https://en.wikipedia.org/wiki/Z-order_curve - // Textures are split into 8x8 tiles.This function returns the in - tile offset depending on the u & v of the texel - // The in - tile offset is the sum of 2 offsets, one depending on the value of u % 8 and the other on the value of y % 8 - // As documented in this picture https ://en.wikipedia.org/wiki/File:Moser%E2%80%93de_Bruijn_addition.svg - u32 Texture::mortonInterleave(u32 u, u32 v) { - static constexpr u32 xOffsets[] = {0, 1, 4, 5, 16, 17, 20, 21}; - static constexpr u32 yOffsets[] = {0, 2, 8, 10, 32, 34, 40, 42}; - - return xOffsets[u & 7] + yOffsets[v & 7]; - } - - // Get the byte offset of texel (u, v) in the texture - u32 Texture::getSwizzledOffset(u32 u, u32 v, u32 width, u32 bytesPerPixel) { - u32 offset = ((u & ~7) * 8) + ((v & ~7) * width); // Offset of the 8x8 tile the texel belongs to - offset += mortonInterleave(u, v); // Add the in-tile offset of the texel - - return offset * bytesPerPixel; - } - - // Same as the above code except we need to divide by 2 because 4 bits is smaller than a byte - u32 Texture::getSwizzledOffset_4bpp(u32 u, u32 v, u32 width) { - u32 offset = ((u & ~7) * 8) + ((v & ~7) * width); // Offset of the 8x8 tile the texel belongs to - offset += mortonInterleave(u, v); // Add the in-tile offset of the texel - - return offset / 2; - } - - u8 Texture::decodeTexelU8(u32 u, u32 v, PICA::TextureFmt fmt, std::span data) { - switch (fmt) { - case PICA::TextureFmt::A4: { - const u32 offset = getSwizzledOffset_4bpp(u, v, size.u()); - - // For odd U coordinates, grab the top 4 bits, and the low 4 bits for even coordinates - u8 alpha = data[offset] >> ((u % 2) ? 4 : 0); - alpha = Colour::convert4To8Bit(getBits<0, 4>(alpha)); - - // A8 - return alpha; - } - - case PICA::TextureFmt::A8: { - u32 offset = getSwizzledOffset(u, v, size.u(), 1); - const u8 alpha = data[offset]; - - // A8 - return alpha; - } - - default: Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast(fmt)); - } - } - - u16 Texture::decodeTexelU16(u32 u, u32 v, PICA::TextureFmt fmt, std::span data) { - switch (fmt) { - case PICA::TextureFmt::RG8: { - u32 offset = getSwizzledOffset(u, v, size.u(), 2); - constexpr u8 b = 0; - const u8 g = data[offset]; - const u8 r = data[offset + 1]; - - // RG8 - return (g << 8) | r; - } - - case PICA::TextureFmt::RGBA4: { - u32 offset = getSwizzledOffset(u, v, size.u(), 2); - u16 texel = u16(data[offset]) | (u16(data[offset + 1]) << 8); - - u8 alpha = getBits<0, 4, u8>(texel); - u8 b = getBits<4, 4, u8>(texel); - u8 g = getBits<8, 4, u8>(texel); - u8 r = getBits<12, 4, u8>(texel); - - // ABGR4 - return (r << 12) | (g << 8) | (b << 4) | alpha; - } - - case PICA::TextureFmt::RGBA5551: { - const u32 offset = getSwizzledOffset(u, v, size.u(), 2); - const u16 texel = u16(data[offset]) | (u16(data[offset + 1]) << 8); - - u8 alpha = getBit<0>(texel) ? 0xff : 0; - u8 b = getBits<1, 5, u8>(texel); - u8 g = getBits<6, 5, u8>(texel); - u8 r = getBits<11, 5, u8>(texel); - - // BGR5A1 - return (alpha << 15) | (r << 10) | (g << 5) | b; - } - - case PICA::TextureFmt::RGB565: { - const u32 offset = getSwizzledOffset(u, v, size.u(), 2); - const u16 texel = u16(data[offset]) | (u16(data[offset + 1]) << 8); - - const u8 b = getBits<0, 5, u8>(texel); - const u8 g = getBits<5, 6, u8>(texel); - const u8 r = getBits<11, 5, u8>(texel); - - // B5G6R5 - return (r << 11) | (g << 5) | b; - } - - case PICA::TextureFmt::IA4: { - const u32 offset = getSwizzledOffset(u, v, size.u(), 1); - const u8 texel = data[offset]; - const u8 alpha = texel & 0xf; - const u8 intensity = texel >> 4; - - // ABGR4 - return (intensity << 12) | (intensity << 8) | (intensity << 4) | alpha; - } - - case PICA::TextureFmt::I4: { - u32 offset = getSwizzledOffset_4bpp(u, v, size.u()); - - // For odd U coordinates, grab the top 4 bits, and the low 4 bits for even coordinates - u8 intensity = data[offset] >> ((u % 2) ? 4 : 0); - intensity = getBits<0, 4>(intensity); - - // ABGR4 - return (intensity << 12) | (intensity << 8) | (intensity << 4) | 0xff; - } - - default: Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast(fmt)); - } - } - - u32 Texture::decodeTexelU32(u32 u, u32 v, PICA::TextureFmt fmt, std::span data) { - switch (fmt) { - case PICA::TextureFmt::RGB8: { - const u32 offset = getSwizzledOffset(u, v, size.u(), 3); - const u8 b = data[offset]; - const u8 g = data[offset + 1]; - const u8 r = data[offset + 2]; - - // RGBA8 - return (0xff << 24) | (b << 16) | (g << 8) | r; - } - - case PICA::TextureFmt::RGBA8: { - const u32 offset = getSwizzledOffset(u, v, size.u(), 4); - const u8 alpha = data[offset]; - const u8 b = data[offset + 1]; - const u8 g = data[offset + 2]; - const u8 r = data[offset + 3]; - - // RGBA8 - return (alpha << 24) | (b << 16) | (g << 8) | r; - } - - case PICA::TextureFmt::I8: { - u32 offset = getSwizzledOffset(u, v, size.u(), 1); - const u8 intensity = data[offset]; - - // RGBA8 - return (0xff << 24) | (intensity << 16) | (intensity << 8) | intensity; - } - - case PICA::TextureFmt::IA8: { - u32 offset = getSwizzledOffset(u, v, size.u(), 2); - - // Same as I8 except each pixel gets its own alpha value too - const u8 alpha = data[offset]; - const u8 intensity = data[offset + 1]; - - // RGBA8 - return (alpha << 24) | (intensity << 16) | (intensity << 8) | intensity; - } - - case PICA::TextureFmt::ETC1: return getTexelETC(false, u, v, size.u(), data); - case PICA::TextureFmt::ETC1A4: return getTexelETC(true, u, v, size.u(), data); - - default: Helpers::panic("[Texture::DecodeTexel] Unimplemented format = %d", static_cast(fmt)); - } - } - void Texture::decodeTexture(std::span data) { - std::vector decoded; - decoded.reserve(u64(size.u()) * u64(size.v()) * formatInfo.bytesPerTexel); + std::unique_ptr decodedData(new u8[u64(size.u()) * u64(size.v()) * formatInfo.bytesPerTexel]); + // This pointer will be incremented by our texture decoders + u8* decodePtr = decodedData.get(); // Decode texels line by line for (u32 v = 0; v < size.v(); v++) { for (u32 u = 0; u < size.u(); u++) { - if (formatInfo.bytesPerTexel == 1) { - u8 texel = decodeTexelU8(u, v, format, data); - decoded.push_back(texel); - } else if (formatInfo.bytesPerTexel == 2) { - u16 texel = decodeTexelU16(u, v, format, data); - decoded.push_back((texel & 0x00ff) >> 0); - decoded.push_back((texel & 0xff00) >> 8); - } else if (formatInfo.bytesPerTexel == 4) { - u32 texel = decodeTexelU32(u, v, format, data); - decoded.push_back((texel & 0x000000ff) >> 0); - decoded.push_back((texel & 0x0000ff00) >> 8); - decoded.push_back((texel & 0x00ff0000) >> 16); - decoded.push_back((texel & 0xff000000) >> 24); - } else { - Helpers::panic("[Texture::decodeTexture] Unimplemented bytesPerTexel (%u)", formatInfo.bytesPerTexel); - } + formatInfo.decoder(size, u, v, data, decodePtr); + decodePtr += formatInfo.bytesPerTexel; } } - texture->replaceRegion(MTL::Region(0, 0, size.u(), size.v()), 0, 0, decoded.data(), formatInfo.bytesPerTexel * size.u(), 0); + texture->replaceRegion(MTL::Region(0, 0, size.u(), size.v()), 0, 0, decodedData.get(), formatInfo.bytesPerTexel * size.u(), 0); } } // namespace Metal diff --git a/src/core/renderer_mtl/pica_to_mtl.cpp b/src/core/renderer_mtl/pica_to_mtl.cpp new file mode 100644 index 00000000..538e6d52 --- /dev/null +++ b/src/core/renderer_mtl/pica_to_mtl.cpp @@ -0,0 +1,62 @@ +#include "renderer_mtl/pica_to_mtl.hpp" + +#include "renderer_mtl/texture_decoder.hpp" + +using namespace Helpers; + +namespace PICA { + MTLPixelFormatInfo mtlPixelFormatInfos[14] = { + {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelABGR8ToRGBA8}, // RGBA8 + {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelBGR8ToRGBA8}, // RGB8 + {MTL::PixelFormatBGR5A1Unorm, 2, decodeTexelA1BGR5ToBGR5A1}, // RGBA5551 + {MTL::PixelFormatB5G6R5Unorm, 2, decodeTexelB5G6R5ToB5G6R5}, // RGB565 + {MTL::PixelFormatABGR4Unorm, 2, decodeTexelABGR4ToABGR4}, // RGBA4 + {MTL::PixelFormatRG8Unorm, + 2, + decodeTexelAI8ToRG8, + true, + { + .red = MTL::TextureSwizzleRed, + .green = MTL::TextureSwizzleRed, + .blue = MTL::TextureSwizzleRed, + .alpha = MTL::TextureSwizzleGreen, + }}, // IA8 + {MTL::PixelFormatRG8Unorm, 2, decodeTexelGR8ToRG8}, // RG8 + {MTL::PixelFormatR8Unorm, + 1, + decodeTexelI8ToR8, + true, + {.red = MTL::TextureSwizzleRed, .green = MTL::TextureSwizzleRed, .blue = MTL::TextureSwizzleRed, .alpha = MTL::TextureSwizzleOne}}, // I8 + {MTL::PixelFormatA8Unorm, 1, decodeTexelA8ToA8}, // A8 + {MTL::PixelFormatABGR4Unorm, 2, decodeTexelAI4ToABGR4}, // IA4 + {MTL::PixelFormatR8Unorm, + 1, + decodeTexelI4ToR8, + true, + {.red = MTL::TextureSwizzleRed, .green = MTL::TextureSwizzleRed, .blue = MTL::TextureSwizzleRed, .alpha = MTL::TextureSwizzleOne}}, // I4 + {MTL::PixelFormatA8Unorm, 1, decodeTexelA4ToA8}, // A4 + {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelETC1ToRGBA8}, // ETC1 + {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelETC1A4ToRGBA8}, // ETC1A4 + }; + + void checkForMTLPixelFormatSupport(MTL::Device* device) { + if (!device->supportsFamily(MTL::GPUFamilyApple1)) { + mtlPixelFormatInfos[2] = {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelA1BGR5ToRGBA8}; + mtlPixelFormatInfos[3] = {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelB5G6R5ToRGBA8}; + mtlPixelFormatInfos[4] = {MTL::PixelFormatRGBA8Unorm, 4, decodeTexelABGR4ToRGBA8}; + + mtlPixelFormatInfos[9] = { + MTL::PixelFormatRG8Unorm, + 2, + decodeTexelAI4ToRG8, + true, + { + .red = MTL::TextureSwizzleRed, + .green = MTL::TextureSwizzleRed, + .blue = MTL::TextureSwizzleRed, + .alpha = MTL::TextureSwizzleGreen, + } + }; + } + } +} // namespace PICA diff --git a/src/core/renderer_mtl/renderer_mtl.cpp b/src/core/renderer_mtl/renderer_mtl.cpp index 9cf58716..e2e4c085 100644 --- a/src/core/renderer_mtl/renderer_mtl.cpp +++ b/src/core/renderer_mtl/renderer_mtl.cpp @@ -9,6 +9,7 @@ #undef NO #include "PICA/gpu.hpp" +#include "PICA/pica_hash.hpp" #include "SDL_metal.h" using namespace PICA; @@ -30,7 +31,6 @@ PICA::ColorFmt ToColorFormat(u32 format) { } MTL::Library* loadLibrary(MTL::Device* device, const cmrc::file& shaderSource) { - // MTL::CompileOptions* compileOptions = MTL::CompileOptions::alloc()->init(); NS::Error* error = nullptr; MTL::Library* library = device->newLibrary(Metal::createDispatchData(shaderSource.begin(), shaderSource.size()), &error); // MTL::Library* library = device->newLibrary(NS::String::string(source.c_str(), NS::ASCIIStringEncoding), compileOptions, &error); @@ -56,12 +56,18 @@ void RendererMTL::reset() { colorRenderTargetCache.reset(); } +void RendererMTL::setMTKLayer(void* layer) { + metalLayer = (CA::MetalLayer*)layer; +} + void RendererMTL::display() { CA::MetalDrawable* drawable = metalLayer->nextDrawable(); if (!drawable) { return; } + MTL::Texture* texture = drawable->texture(); + using namespace PICA::ExternalRegs; // Top screen @@ -87,13 +93,13 @@ void RendererMTL::display() { MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); MTL::RenderPassColorAttachmentDescriptor* colorAttachment = renderPassDescriptor->colorAttachments()->object(0); - colorAttachment->setTexture(drawable->texture()); + colorAttachment->setTexture(texture); colorAttachment->setLoadAction(MTL::LoadActionClear); colorAttachment->setClearColor(MTL::ClearColor{0.0f, 0.0f, 0.0f, 1.0f}); colorAttachment->setStoreAction(MTL::StoreActionStore); nextRenderPassName = "Display"; - beginRenderPassIfNeeded(renderPassDescriptor, false, drawable->texture()); + beginRenderPassIfNeeded(renderPassDescriptor, false, texture); renderCommandEncoder->setRenderPipelineState(displayPipeline); renderCommandEncoder->setFragmentSamplerState(nearestSampler, 0); @@ -119,17 +125,22 @@ void RendererMTL::display() { // Inform the vertex buffer cache that the frame ended vertexBufferCache.endFrame(); - - // Release drawable->release(); } void RendererMTL::initGraphicsContext(SDL_Window* window) { + // On iOS, the SwiftUI side handles the MetalLayer +#ifdef PANDA3DS_IOS + device = MTL::CreateSystemDefaultDevice(); +#else // TODO: what should be the type of the view? void* view = SDL_Metal_CreateView(window); metalLayer = (CA::MetalLayer*)SDL_Metal_GetLayer(view); device = MTL::CreateSystemDefaultDevice(); metalLayer->setDevice(device); +#endif + checkForMTLPixelFormatSupport(device); + commandQueue = device->newCommandQueue(); // Textures @@ -426,7 +437,7 @@ void RendererMTL::textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 // Find the source surface. auto srcFramebuffer = getColorRenderTarget(inputAddr, PICA::ColorFmt::RGBA8, copyStride, copyHeight, false); if (!srcFramebuffer) { - Helpers::warn("RendererMTL::TextureCopy failed to locate src framebuffer!\n"); + doSoftwareTextureCopy(inputAddr, outputAddr, copySize, inputWidth, inputGap, outputWidth, outputGap); return; } nextRenderPassName = "Clear before texture copy"; @@ -719,6 +730,19 @@ void RendererMTL::bindTexturesToSlots() { if (addr != 0) [[likely]] { Metal::Texture targetTex(device, addr, static_cast(format), width, height, config); + + if (hashTextures) { + const u8* startPointer = gpu.getPointerPhys(targetTex.location); + const usize sizeInBytes = targetTex.sizeInBytes(); + + if (startPointer == nullptr || (sizeInBytes > 0 && gpu.getPointerPhys(targetTex.location + sizeInBytes - 1) == nullptr)) + [[unlikely]] { + Helpers::warn("Out-of-bounds texture fetch"); + } else { + targetTex.hash = PICAHash::computeHash((const char*)startPointer, sizeInBytes); + } + } + auto tex = getTexture(targetTex); commandEncoder.setFragmentTexture(tex.texture, i); commandEncoder.setFragmentSamplerState(tex.sampler ? tex.sampler : nearestSampler, i); diff --git a/src/core/renderer_mtl/texture_decoder.cpp b/src/core/renderer_mtl/texture_decoder.cpp new file mode 100644 index 00000000..06db2d76 --- /dev/null +++ b/src/core/renderer_mtl/texture_decoder.cpp @@ -0,0 +1,334 @@ +#include "renderer_mtl/texture_decoder.hpp" + +#include +#include + +#include "colour.hpp" +#include "math_util.hpp" + +using namespace Helpers; + +// u and v are the UVs of the relevant texel +// Texture data is stored interleaved in Morton order, ie in a Z - order curve as shown here +// https://en.wikipedia.org/wiki/Z-order_curve +// Textures are split into 8x8 tiles.This function returns the in - tile offset depending on the u & v of the texel +// The in - tile offset is the sum of 2 offsets, one depending on the value of u % 8 and the other on the value of y % 8 +// As documented in this picture https ://en.wikipedia.org/wiki/File:Moser%E2%80%93de_Bruijn_addition.svg +u32 mortonInterleave(u32 u, u32 v) { + static constexpr u32 xOffsets[] = {0, 1, 4, 5, 16, 17, 20, 21}; + static constexpr u32 yOffsets[] = {0, 2, 8, 10, 32, 34, 40, 42}; + + return xOffsets[u & 7] + yOffsets[v & 7]; +} + +// Get the byte offset of texel (u, v) in the texture +u32 getSwizzledOffset(u32 u, u32 v, u32 width, u32 bytesPerPixel) { + u32 offset = ((u & ~7) * 8) + ((v & ~7) * width); // Offset of the 8x8 tile the texel belongs to + offset += mortonInterleave(u, v); // Add the in-tile offset of the texel + + return offset * bytesPerPixel; +} + +// Same as the above code except we need to divide by 2 because 4 bits is smaller than a byte +u32 getSwizzledOffset_4bpp(u32 u, u32 v, u32 width) { + u32 offset = ((u & ~7) * 8) + ((v & ~7) * width); // Offset of the 8x8 tile the texel belongs to + offset += mortonInterleave(u, v); // Add the in-tile offset of the texel + + return offset / 2; +} + +void decodeTexelABGR8ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + const u32 offset = getSwizzledOffset(u, v, size.u(), 4); + const u8 alpha = inData[offset]; + const u8 b = inData[offset + 1]; + const u8 g = inData[offset + 2]; + const u8 r = inData[offset + 3]; + + *outData++ = r; + *outData++ = g; + *outData++ = b; + *outData++ = alpha; +} + +void decodeTexelBGR8ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + const u32 offset = getSwizzledOffset(u, v, size.u(), 3); + const u8 b = inData[offset]; + const u8 g = inData[offset + 1]; + const u8 r = inData[offset + 2]; + + *outData++ = r; + *outData++ = g; + *outData++ = b; + *outData++ = 0xff; +} + +void decodeTexelA1BGR5ToBGR5A1(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + const u32 offset = getSwizzledOffset(u, v, size.u(), 2); + const u16 texel = u16(inData[offset]) | (u16(inData[offset + 1]) << 8); + + u8 alpha = getBit<0>(texel); + u8 b = getBits<1, 5, u8>(texel); + u8 g = getBits<6, 5, u8>(texel); + u8 r = getBits<11, 5, u8>(texel); + + u16 outTexel = (alpha << 15) | (r << 10) | (g << 5) | b; + *outData++ = outTexel & 0xff; + *outData++ = (outTexel >> 8) & 0xff; +} + +void decodeTexelA1BGR5ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + const u32 offset = getSwizzledOffset(u, v, size.u(), 2); + const u16 texel = u16(inData[offset]) | (u16(inData[offset + 1]) << 8); + + u8 alpha = getBit<0>(texel) ? 0xff : 0; + u8 b = Colour::convert5To8Bit(getBits<1, 5, u8>(texel)); + u8 g = Colour::convert5To8Bit(getBits<6, 5, u8>(texel)); + u8 r = Colour::convert5To8Bit(getBits<11, 5, u8>(texel)); + + *outData++ = r; + *outData++ = g; + *outData++ = b; + *outData++ = alpha; +} + +void decodeTexelB5G6R5ToB5G6R5(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + const u32 offset = getSwizzledOffset(u, v, size.u(), 2); + const u16 texel = u16(inData[offset]) | (u16(inData[offset + 1]) << 8); + + *outData++ = texel & 0xff; + *outData++ = (texel >> 8) & 0xff; +} + +void decodeTexelB5G6R5ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + const u32 offset = getSwizzledOffset(u, v, size.u(), 2); + const u16 texel = u16(inData[offset]) | (u16(inData[offset + 1]) << 8); + + const u8 b = Colour::convert5To8Bit(getBits<0, 5, u8>(texel)); + const u8 g = Colour::convert6To8Bit(getBits<5, 6, u8>(texel)); + const u8 r = Colour::convert5To8Bit(getBits<11, 5, u8>(texel)); + + *outData++ = r; + *outData++ = g; + *outData++ = b; + *outData++ = 0xff; +} + +void decodeTexelABGR4ToABGR4(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + u32 offset = getSwizzledOffset(u, v, size.u(), 2); + u16 texel = u16(inData[offset]) | (u16(inData[offset + 1]) << 8); + + u8 alpha = getBits<0, 4, u8>(texel); + u8 b = getBits<4, 4, u8>(texel); + u8 g = getBits<8, 4, u8>(texel); + u8 r = getBits<12, 4, u8>(texel); + + *outData++ = (b << 4) | alpha; + *outData++ = (r << 4) | g; +} + +void decodeTexelABGR4ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + u32 offset = getSwizzledOffset(u, v, size.u(), 2); + u16 texel = u16(inData[offset]) | (u16(inData[offset + 1]) << 8); + + u8 alpha = Colour::convert4To8Bit(getBits<0, 4, u8>(texel)); + u8 b = Colour::convert4To8Bit(getBits<4, 4, u8>(texel)); + u8 g = Colour::convert4To8Bit(getBits<8, 4, u8>(texel)); + u8 r = Colour::convert4To8Bit(getBits<12, 4, u8>(texel)); + + *outData++ = r; + *outData++ = g; + *outData++ = b; + *outData++ = alpha; +} + +void decodeTexelAI8ToRG8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + u32 offset = getSwizzledOffset(u, v, size.u(), 2); + + // Same as I8 except each pixel gets its own alpha value too + const u8 alpha = inData[offset]; + const u8 intensity = inData[offset + 1]; + + *outData++ = intensity; + *outData++ = alpha; +} + +void decodeTexelGR8ToRG8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + u32 offset = getSwizzledOffset(u, v, size.u(), 2); + constexpr u8 b = 0; + const u8 g = inData[offset]; + const u8 r = inData[offset + 1]; + + *outData++ = r; + *outData++ = g; +} + +void decodeTexelI8ToR8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + u32 offset = getSwizzledOffset(u, v, size.u(), 1); + const u8 intensity = inData[offset]; + + *outData++ = intensity; +} + +void decodeTexelA8ToA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + u32 offset = getSwizzledOffset(u, v, size.u(), 1); + const u8 alpha = inData[offset]; + + *outData++ = alpha; +} + +void decodeTexelAI4ToABGR4(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + const u32 offset = getSwizzledOffset(u, v, size.u(), 1); + const u8 texel = inData[offset]; + const u8 alpha = texel & 0xf; + const u8 intensity = texel >> 4; + + *outData++ = (intensity << 4) | intensity; + *outData++ = (alpha << 4) | intensity; +} + +void decodeTexelAI4ToRG8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + const u32 offset = getSwizzledOffset(u, v, size.u(), 1); + const u8 texel = inData[offset]; + const u8 alpha = Colour::convert4To8Bit(texel & 0xf); + const u8 intensity = Colour::convert4To8Bit(texel >> 4); + + *outData++ = intensity; + *outData++ = alpha; +} + +void decodeTexelI4ToR8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + u32 offset = getSwizzledOffset_4bpp(u, v, size.u()); + + // For odd U coordinates, grab the top 4 bits, and the low 4 bits for even coordinates + u8 intensity = inData[offset] >> ((u % 2) ? 4 : 0); + intensity = Colour::convert4To8Bit(getBits<0, 4>(intensity)); + + *outData++ = intensity; +} + +void decodeTexelA4ToA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + const u32 offset = getSwizzledOffset_4bpp(u, v, size.u()); + + // For odd U coordinates, grab the top 4 bits, and the low 4 bits for even coordinates + u8 alpha = inData[offset] >> ((u % 2) ? 4 : 0); + alpha = Colour::convert4To8Bit(getBits<0, 4>(alpha)); + + *outData++ = alpha; +} + +static constexpr u32 signExtend3To32(u32 val) { return (u32)(s32(val) << 29 >> 29); } + +void decodeETC(u32 u, u32 v, u64 colourData, u32 alpha, u8* outData) { + static constexpr u32 modifiers[8][2] = { + {2, 8}, {5, 17}, {9, 29}, {13, 42}, {18, 60}, {24, 80}, {33, 106}, {47, 183}, + }; + + // Parse colour data for 4x4 block + const u32 subindices = getBits<0, 16, u32>(colourData); + const u32 negationFlags = getBits<16, 16, u32>(colourData); + const bool flip = getBit<32>(colourData); + const bool diffMode = getBit<33>(colourData); + + // Note: index1 is indeed stored on the higher bits, with index2 in the lower bits + const u32 tableIndex1 = getBits<37, 3, u32>(colourData); + const u32 tableIndex2 = getBits<34, 3, u32>(colourData); + const u32 texelIndex = u * 4 + v; // Index of the texel in the block + + if (flip) std::swap(u, v); + + s32 r, g, b; + if (diffMode) { + r = getBits<59, 5, s32>(colourData); + g = getBits<51, 5, s32>(colourData); + b = getBits<43, 5, s32>(colourData); + + if (u >= 2) { + r += signExtend3To32(getBits<56, 3, u32>(colourData)); + g += signExtend3To32(getBits<48, 3, u32>(colourData)); + b += signExtend3To32(getBits<40, 3, u32>(colourData)); + } + + // Expand from 5 to 8 bits per channel + r = Colour::convert5To8Bit(r); + g = Colour::convert5To8Bit(g); + b = Colour::convert5To8Bit(b); + } else { + if (u < 2) { + r = getBits<60, 4, s32>(colourData); + g = getBits<52, 4, s32>(colourData); + b = getBits<44, 4, s32>(colourData); + } else { + r = getBits<56, 4, s32>(colourData); + g = getBits<48, 4, s32>(colourData); + b = getBits<40, 4, s32>(colourData); + } + + // Expand from 4 to 8 bits per channel + r = Colour::convert4To8Bit(r); + g = Colour::convert4To8Bit(g); + b = Colour::convert4To8Bit(b); + } + + const u32 index = (u < 2) ? tableIndex1 : tableIndex2; + s32 modifier = modifiers[index][(subindices >> texelIndex) & 1]; + + if (((negationFlags >> texelIndex) & 1) != 0) { + modifier = -modifier; + } + + r = std::clamp(r + modifier, 0, 255); + g = std::clamp(g + modifier, 0, 255); + b = std::clamp(b + modifier, 0, 255); + + *outData++ = r; + *outData++ = g; + *outData++ = b; + *outData++ = alpha; +} + +template +void getTexelETC(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + // Pixel offset of the 8x8 tile based on u, v and the width of the texture + u32 offs = ((u & ~7) * 8) + ((v & ~7) * size.u()); + if (!hasAlpha) { + offs >>= 1; + } + + // In-tile offsets for u/v + u &= 7; + v &= 7; + + // ETC1(A4) also subdivide the 8x8 tile to 4 4x4 tiles + // Each tile is 8 bytes for ETC1, but since ETC1A4 has 4 alpha bits per pixel, that becomes 16 bytes + const u32 subTileSize = hasAlpha ? 16 : 8; + const u32 subTileIndex = (u / 4) + 2 * (v / 4); // Which of the 4 subtiles is this texel in? + + // In-subtile offsets for u/v + u &= 3; + v &= 3; + offs += subTileSize * subTileIndex; + + u32 alpha; + const u64* ptr = reinterpret_cast(inData.data() + offs); // Cast to u64* + + if (hasAlpha) { + // First 64 bits of the 4x4 subtile are alpha data + const u64 alphaData = *ptr++; + alpha = Colour::convert4To8Bit((alphaData >> (4 * (u * 4 + v))) & 0xf); + } else { + alpha = 0xff; // ETC1 without alpha uses ff for every pixel + } + + // Next 64 bits of the subtile are colour data + u64 colourData = *ptr; + + decodeETC(u, v, colourData, alpha, outData); +} + +void decodeTexelETC1ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + getTexelETC(size, u, v, inData, outData); +} + +void decodeTexelETC1A4ToRGBA8(OpenGL::uvec2 size, u32 u, u32 v, std::span inData, u8* outData) { + getTexelETC(size, u, v, inData, outData); +} diff --git a/src/core/renderer_vk/renderer_vk.cpp b/src/core/renderer_vk/renderer_vk.cpp index d05a070f..57533bde 100644 --- a/src/core/renderer_vk/renderer_vk.cpp +++ b/src/core/renderer_vk/renderer_vk.cpp @@ -885,10 +885,17 @@ void RendererVK::display() { } } +// DynamicLoader is in a different namespace in different versions of Vulkan-Hpp +#if VK_HEADER_VERSION >= 301 +using VulkanDynamicLoader = vk::detail::DynamicLoader; +#else +using VulkanDynamicLoader = vk::DynamicLoader; +#endif + void RendererVK::initGraphicsContext(SDL_Window* window) { targetWindow = window; // Resolve all instance function pointers - static vk::DynamicLoader dl; + static VulkanDynamicLoader dl; VULKAN_HPP_DEFAULT_DISPATCHER.init(dl.getProcAddress("vkGetInstanceProcAddr")); // Create Instance @@ -1588,4 +1595,4 @@ void RendererVK::deinitGraphicsContext() { // TODO: Make it so that depth and colour buffers get written back to 3DS memory printf("RendererVK::DeinitGraphicsContext called\n"); -} \ No newline at end of file +} diff --git a/src/core/renderer_vk/vk_debug.cpp b/src/core/renderer_vk/vk_debug.cpp index f3f099c8..5e26e77a 100644 --- a/src/core/renderer_vk/vk_debug.cpp +++ b/src/core/renderer_vk/vk_debug.cpp @@ -61,8 +61,8 @@ namespace Vulkan { } VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData + vk::DebugUtilsMessageSeverityFlagBitsEXT messageSeverity, vk::DebugUtilsMessageTypeFlagsEXT messageType, + const vk::DebugUtilsMessengerCallbackDataEXT* callbackData, void* userData ) { debugMessageCallback( vk::DebugUtilsMessageSeverityFlagBitsEXT(messageSeverity), vk::DebugUtilsMessageTypeFlagsEXT(messageType), *callbackData @@ -70,7 +70,7 @@ namespace Vulkan { return VK_FALSE; } - #ifdef GPU_DEBUG_INFO +#ifdef GPU_DEBUG_INFO void setObjectName(vk::Device device, vk::ObjectType objectType, const void* objectHandle, const char* format, ...) { va_list args; va_start(args, format); diff --git a/src/core/services/ac.cpp b/src/core/services/ac.cpp index b4b9730b..7bc150ae 100644 --- a/src/core/services/ac.cpp +++ b/src/core/services/ac.cpp @@ -1,4 +1,5 @@ #include "services/ac.hpp" + #include "ipc.hpp" namespace ACCommands { @@ -36,7 +37,8 @@ void ACService::handleSyncRequest(u32 messagePointer) { case ACCommands::IsConnected: isConnected(messagePointer); break; case ACCommands::RegisterDisconnectEvent: registerDisconnectEvent(messagePointer); break; case ACCommands::SetClientVersion: setClientVersion(messagePointer); break; - default: + + default: mem.write32(messagePointer + 4, Result::Success); Helpers::warn("AC service requested. Command: %08X\n", command); break; @@ -77,7 +79,7 @@ void ACService::getLastErrorCode(u32 messagePointer) { mem.write32(messagePointer, IPC::responseHeader(0x0A, 2, 0)); mem.write32(messagePointer + 4, Result::Success); - mem.write32(messagePointer + 8, 0); // Hopefully this means no error? + mem.write32(messagePointer + 8, 0); // Hopefully this means no error? } void ACService::getConnectingInfraPriority(u32 messagePointer) { diff --git a/src/core/services/apt.cpp b/src/core/services/apt.cpp index 8b98af4b..e690f60a 100644 --- a/src/core/services/apt.cpp +++ b/src/core/services/apt.cpp @@ -397,7 +397,7 @@ void APTService::setScreencapPostPermission(u32 messagePointer) { void APTService::getSharedFont(u32 messagePointer) { log("APT::GetSharedFont\n"); - constexpr u32 fontVaddr = 0x18000000; + const u32 fontVaddr = kernel.getSharedFontVaddr(); mem.write32(messagePointer, IPC::responseHeader(0x44, 2, 2)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, fontVaddr); diff --git a/src/core/services/boss.cpp b/src/core/services/boss.cpp index d8eed981..29518832 100644 --- a/src/core/services/boss.cpp +++ b/src/core/services/boss.cpp @@ -1,4 +1,5 @@ #include "services/boss.hpp" + #include "ipc.hpp" namespace BOSSCommands { @@ -39,9 +40,7 @@ namespace BOSSCommands { }; } -void BOSSService::reset() { - optoutFlag = 0; -} +void BOSSService::reset() { optoutFlag = 0; } void BOSSService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); @@ -84,7 +83,7 @@ void BOSSService::handleSyncRequest(u32 messagePointer) { case 0x04500102: // Home Menu uses this command, what is this? Helpers::warn("BOSS command 0x04500102"); - mem.write32(messagePointer, IPC::responseHeader(0x450, 1, 0)); + mem.write32(messagePointer, IPC::responseHeader(0x450, 1, 0)); mem.write32(messagePointer + 4, Result::Success); break; @@ -126,7 +125,7 @@ void BOSSService::getTaskState(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); mem.write8(messagePointer + 8, 0); // TaskStatus: Report the task finished successfully mem.write32(messagePointer + 12, 0); // Current state value for task PropertyID 0x4 - mem.write8(messagePointer + 16, 0); // TODO: Figure out what this should be + mem.write8(messagePointer + 16, 0); // TODO: Figure out what this should be } void BOSSService::getTaskStatus(u32 messagePointer) { @@ -177,15 +176,15 @@ void BOSSService::getErrorCode(u32 messagePointer) { log("BOSS::GetErrorCode (stubbed)\n"); mem.write32(messagePointer, IPC::responseHeader(0x2E, 2, 0)); mem.write32(messagePointer + 4, Result::Success); - mem.write32(messagePointer + 8, Result::Success); // No error code + mem.write32(messagePointer + 8, Result::Success); // No error code } void BOSSService::getStorageEntryInfo(u32 messagePointer) { log("BOSS::GetStorageEntryInfo (undocumented)\n"); mem.write32(messagePointer, IPC::responseHeader(0x30, 3, 0)); mem.write32(messagePointer + 4, Result::Success); - mem.write32(messagePointer + 8, 0); // u32, unknown meaning - mem.write16(messagePointer + 12, 0); // s16, unknown meaning + mem.write32(messagePointer + 8, 0); // u32, unknown meaning + mem.write16(messagePointer + 12, 0); // s16, unknown meaning } void BOSSService::sendProperty(u32 messagePointer) { @@ -200,7 +199,6 @@ void BOSSService::sendProperty(u32 messagePointer) { // TODO: Should this do anything else? } - void BOSSService::receiveProperty(u32 messagePointer) { const u32 id = mem.read32(messagePointer + 4); const u32 size = mem.read32(messagePointer + 8); @@ -209,13 +207,13 @@ void BOSSService::receiveProperty(u32 messagePointer) { log("BOSS::ReceiveProperty (id = %d, size = %08X, ptr = %08X) (stubbed)\n", id, size, ptr); mem.write32(messagePointer, IPC::responseHeader(0x16, 2, 2)); mem.write32(messagePointer + 4, Result::Success); - mem.write32(messagePointer + 8, 0); // Read size + mem.write32(messagePointer + 8, 0); // Read size } // This seems to accept a KEvent as a parameter and register it for something Spotpass related // I need to update the 3DBrew page when it's known what it does properly void BOSSService::registerNewArrivalEvent(u32 messagePointer) { - const Handle eventHandle = mem.read32(messagePointer + 4); // Kernel event handle to register + const Handle eventHandle = mem.read32(messagePointer + 4); // Kernel event handle to register log("BOSS::RegisterNewArrivalEvent (handle = %X)\n", eventHandle); mem.write32(messagePointer, IPC::responseHeader(0x8, 1, 0)); @@ -279,7 +277,7 @@ void BOSSService::getNewArrivalFlag(u32 messagePointer) { log("BOSS::GetNewArrivalFlag (stubbed)\n"); mem.write32(messagePointer, IPC::responseHeader(0x7, 2, 0)); mem.write32(messagePointer + 4, Result::Success); - mem.write8(messagePointer + 8, 0); // Flag + mem.write8(messagePointer + 8, 0); // Flag } void BOSSService::startBgImmediate(u32 messagePointer) { diff --git a/src/core/services/cfg.cpp b/src/core/services/cfg.cpp index 906a7c24..2f2344ae 100644 --- a/src/core/services/cfg.cpp +++ b/src/core/services/cfg.cpp @@ -21,41 +21,80 @@ namespace CFGCommands { SetConfigInfoBlk4 = 0x04020082, UpdateConfigNANDSavegame = 0x04030000, + GetCountryCodeString = 0x00090040, + GetCountryCodeID = 0x000A0040, + IsFangateSupported = 0x000B0000, + SetConfigInfoBlk4 = 0x04020082, + UpdateConfigNANDSavegame = 0x04030000, GetLocalFriendCodeSeed = 0x04050000, SecureInfoGetByte101 = 0x04070000, }; } +// cfg:i commands +namespace CFGICommands { + enum : u32 { + GetConfigInfoBlk8 = 0x08010082, + }; +} + +// cfg:nor commands +namespace NORCommands { + enum : u32 { + Initialize = 0x00010040, + ReadData = 0x00050082, + }; +} + void CFGService::reset() {} void CFGService::handleSyncRequest(u32 messagePointer, CFGService::Type type) { const u32 command = mem.read32(messagePointer); - switch (command) { - case CFGCommands::GetConfigInfoBlk2: [[likely]] getConfigInfoBlk2(messagePointer); break; - case CFGCommands::GetCountryCodeID: getCountryCodeID(messagePointer); break; - case CFGCommands::GetRegionCanadaUSA: getRegionCanadaUSA(messagePointer); break; - case CFGCommands::GetSystemModel: getSystemModel(messagePointer); break; - case CFGCommands::GenHashConsoleUnique: genUniqueConsoleHash(messagePointer); break; - case CFGCommands::SecureInfoGetRegion: secureInfoGetRegion(messagePointer); break; - case CFGCommands::TranslateCountryInfo: translateCountryInfo(messagePointer); break; + if (type != Type::NOR) { + switch (command) { + case CFGCommands::GetConfigInfoBlk2: [[likely]] getConfigInfoBlk2(messagePointer); break; + case CFGCommands::GetCountryCodeString: getCountryCodeString(messagePointer); break; + case CFGCommands::GetCountryCodeID: getCountryCodeID(messagePointer); break; + case CFGCommands::GetRegionCanadaUSA: getRegionCanadaUSA(messagePointer); break; + case CFGCommands::GetSystemModel: getSystemModel(messagePointer); break; + case CFGCommands::GenHashConsoleUnique: genUniqueConsoleHash(messagePointer); break; + case CFGCommands::IsFangateSupported: isFangateSupported(messagePointer); break; + case CFGCommands::SecureInfoGetRegion: secureInfoGetRegion(messagePointer); break; + case CFGCommands::TranslateCountryInfo: translateCountryInfo(messagePointer); break; - default: - if (type == Type::S) { - // cfg:s-only functions - switch (command) { - case CFGCommands::GetConfigInfoBlk8: getConfigInfoBlk8(messagePointer); break; - case CFGCommands::GetLocalFriendCodeSeed: getLocalFriendCodeSeed(messagePointer); break; - case CFGCommands::SecureInfoGetByte101: secureInfoGetByte101(messagePointer); break; - case CFGCommands::SetConfigInfoBlk4: setConfigInfoBlk4(messagePointer); break; - case CFGCommands::UpdateConfigNANDSavegame: updateConfigNANDSavegame(messagePointer); break; + default: + if (type == Type::S) { + // cfg:s (and cfg:i) functions only functions + switch (command) { + case CFGCommands::GetConfigInfoBlk8: getConfigInfoBlk8(messagePointer, command); break; + case CFGCommands::GetLocalFriendCodeSeed: getLocalFriendCodeSeed(messagePointer); break; + case CFGCommands::SecureInfoGetByte101: secureInfoGetByte101(messagePointer); break; + case CFGCommands::SetConfigInfoBlk4: setConfigInfoBlk4(messagePointer); break; + case CFGCommands::UpdateConfigNANDSavegame: updateConfigNANDSavegame(messagePointer); break; - default: Helpers::panic("CFG:S service requested. Command: %08X\n", command); + default: Helpers::panic("CFG:S service requested. Command: %08X\n", command); + } + } else if (type == Type::I) { + switch (command) { + case CFGCommands::GetConfigInfoBlk8: + case CFGICommands::GetConfigInfoBlk8: getConfigInfoBlk8(messagePointer, command); break; + + default: Helpers::panic("CFG:I service requested. Command: %08X\n", command); + } + } else { + Helpers::panic("CFG service requested. Command: %08X\n", command); } - } else { - Helpers::panic("CFG service requested. Command: %08X\n", command); - } - break; + break; + } + } else { + // cfg:nor functions + switch (command) { + case NORCommands::Initialize: norInitialize(messagePointer); break; + case NORCommands::ReadData: norReadData(messagePointer); break; + + default: Helpers::panic("CFG:NOR service requested. Command: %08X\n", command); + } } } @@ -88,14 +127,14 @@ void CFGService::getConfigInfoBlk2(u32 messagePointer) { mem.write32(messagePointer + 4, Result::Success); } -void CFGService::getConfigInfoBlk8(u32 messagePointer) { +void CFGService::getConfigInfoBlk8(u32 messagePointer, u32 commandWord) { u32 size = mem.read32(messagePointer + 4); u32 blockID = mem.read32(messagePointer + 8); u32 output = mem.read32(messagePointer + 16); // Pointer to write the output data to log("CFG::GetConfigInfoBlk8 (size = %X, block ID = %X, output pointer = %08X)\n", size, blockID, output); getConfigInfo(output, blockID, size, 0x8); - mem.write32(messagePointer, IPC::responseHeader(0x401, 1, 2)); + mem.write32(messagePointer, IPC::responseHeader(commandWord >> 16, 1, 2)); mem.write32(messagePointer + 4, Result::Success); } @@ -104,7 +143,7 @@ void CFGService::getConfigInfo(u32 output, u32 blockID, u32 size, u32 permission if (size == 1 && blockID == 0x70001) { // Sound output mode mem.write8(output, static_cast(DSPService::SoundOutputMode::Stereo)); } else if (size == 1 && blockID == 0xA0002) { // System language - mem.write8(output, static_cast(LanguageCodes::English)); + mem.write8(output, static_cast(settings.systemLanguage)); } else if (size == 4 && blockID == 0xB0000) { // Country info mem.write8(output, 0); // Unknown mem.write8(output + 1, 0); // Unknown @@ -178,6 +217,23 @@ void CFGService::getConfigInfo(u32 output, u32 blockID, u32 size, u32 permission mem.write32(output, 0); } else if (size == 1 && blockID == 0xE0000) { mem.write8(output, 0); + } else if ((size == 512 && blockID == 0xC0002) || (size == 148 && blockID == 0x100001)) { + // CTR parental controls block (0xC0002) and TWL parental controls block (0x100001) + for (u32 i = 0; i < size; i++) { + mem.write8(output + i, 0); + } + } else if (size == 2 && blockID == 0x100000) { + // EULA agreed + mem.write8(output, 1); // We have agreed to the EULA + mem.write8(output + 1, 1); // EULA version = 1 + } else if (size == 1 && blockID == 0x100002) { + Helpers::warn("Unimplemented TWL country code access"); + mem.write8(output, 0); + } else if (size == 24 && blockID == 0x180001) { + // QTM calibration data + for (u32 i = 0; i < size; i++) { + mem.write8(output + i, 0); + } } else { Helpers::panic("Unhandled GetConfigInfoBlk2 configuration. Size = %d, block = %X", size, blockID); } @@ -262,6 +318,24 @@ void CFGService::getCountryCodeID(u32 messagePointer) { } } +void CFGService::getCountryCodeString(u32 messagePointer) { + const u16 id = mem.read16(messagePointer + 4); + log("CFG::getCountryCodeString (id = %04X)\n", id); + + mem.write32(messagePointer, IPC::responseHeader(0x09, 2, 0)); + + for (auto [string, code] : countryCodeToTableIDMap) { + if (code == id) { + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, u32(string)); + return; + } + } + + // Code is not a valid country code, return an appropriate error + mem.write32(messagePointer + 4, 0xD90103FA); +} + void CFGService::secureInfoGetByte101(u32 messagePointer) { log("CFG::SecureInfoGetByte101\n"); @@ -329,4 +403,28 @@ void CFGService::translateCountryInfo(u32 messagePointer) { mem.write32(messagePointer, IPC::responseHeader(0x8, 2, 0)); mem.write32(messagePointer + 4, Result::Success); mem.write32(messagePointer + 8, result); +} + +void CFGService::isFangateSupported(u32 messagePointer) { + log("CFG::IsFangateSupported\n"); + + // TODO: What even is fangate? + mem.write32(messagePointer, IPC::responseHeader(0xB, 2, 0)); + mem.write32(messagePointer + 4, Result::Success); + mem.write32(messagePointer + 8, 1); +} + +void CFGService::norInitialize(u32 messagePointer) { + log("CFG::NOR::Initialize\n"); + + mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); +} + +void CFGService::norReadData(u32 messagePointer) { + log("CFG::NOR::ReadData\n"); + Helpers::warn("Unimplemented CFG::NOR::ReadData"); + + mem.write32(messagePointer, IPC::responseHeader(0x5, 1, 0)); + mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/gsp_gpu.cpp b/src/core/services/gsp_gpu.cpp index 96364e73..5c6ab3d6 100644 --- a/src/core/services/gsp_gpu.cpp +++ b/src/core/services/gsp_gpu.cpp @@ -1,4 +1,5 @@ #include "services/gsp_gpu.hpp" + #include "PICA/regs.hpp" #include "ipc.hpp" #include "kernel.hpp" @@ -39,7 +40,7 @@ namespace GXCommands { } void GPUService::reset() { - privilegedProcess = 0xFFFFFFFF; // Set the privileged process to an invalid handle + privilegedProcess = 0xFFFFFFFF; // Set the privileged process to an invalid handle interruptEvent = std::nullopt; gspThreadCount = 0; sharedMem = nullptr; @@ -113,38 +114,38 @@ void GPUService::registerInterruptRelayQueue(u32 messagePointer) { log("GSP::GPU::RegisterInterruptRelayQueue (flags = %X, event handle = %X)\n", flags, eventHandle); const auto event = kernel.getObject(eventHandle, KernelObjectType::Event); - if (event == nullptr) { // Check if interrupt event is invalid + if (event == nullptr) { // Check if interrupt event is invalid Helpers::panic("Invalid event passed to GSP::GPU::RegisterInterruptRelayQueue"); } else { interruptEvent = eventHandle; } mem.write32(messagePointer, IPC::responseHeader(0x13, 2, 2)); - mem.write32(messagePointer + 4, Result::GSP::SuccessRegisterIRQ); // First init returns a unique result - mem.write32(messagePointer + 8, 0); // TODO: GSP module thread index - mem.write32(messagePointer + 12, 0); // Translation descriptor + mem.write32(messagePointer + 4, Result::GSP::SuccessRegisterIRQ); // First init returns a unique result + mem.write32(messagePointer + 8, 0); // TODO: GSP module thread index + mem.write32(messagePointer + 12, 0); // Translation descriptor mem.write32(messagePointer + 16, KernelHandles::GSPSharedMemHandle); } void GPUService::requestInterrupt(GPUInterrupt type) { - if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet + if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet return; } // TODO: Add support for multiple GSP threads - u8 index = sharedMem[0]; // The interrupt block is normally located at sharedMem + processGSPIndex*0x40 + u8 index = sharedMem[0]; // The interrupt block is normally located at sharedMem + processGSPIndex*0x40 u8& interruptCount = sharedMem[1]; u8 flagIndex = (index + interruptCount) % 0x34; interruptCount++; - sharedMem[2] = 0; // Set error code to 0 - sharedMem[0xC + flagIndex] = static_cast(type); // Write interrupt type to queue + sharedMem[2] = 0; // Set error code to 0 + sharedMem[0xC + flagIndex] = static_cast(type); // Write interrupt type to queue // Update framebuffer info in shared memory // Most new games check to make sure that the "flag" byte of the framebuffer info header is set to 0 // Not emulating this causes Yoshi's Wooly World, Captain Toad, Metroid 2 et al to hang if (type == GPUInterrupt::VBlank0 || type == GPUInterrupt::VBlank1) { - int screen = static_cast(type) - static_cast(GPUInterrupt::VBlank0); // 0 for top screen, 1 for bottom + int screen = static_cast(type) - static_cast(GPUInterrupt::VBlank0); // 0 for top screen, 1 for bottom FramebufferUpdate* update = getFramebufferInfo(screen); if (update->dirtyFlag & 1) { @@ -165,7 +166,6 @@ void GPUService::readHwRegs(u32 messagePointer) { const u32 initialDataPointer = mem.read32(messagePointer + 0x104); u32 dataPointer = initialDataPointer; log("GSP::GPU::ReadHwRegs (GPU address = %08X, size = %X, data address = %08X)\n", ioAddr, size, dataPointer); - // Check for alignment if ((size & 3) || (ioAddr & 3) || (dataPointer & 3)) { @@ -197,8 +197,8 @@ void GPUService::readHwRegs(u32 messagePointer) { } void GPUService::writeHwRegs(u32 messagePointer) { - u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned - const u32 size = mem.read32(messagePointer + 8); // Size in bytes + u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned + const u32 size = mem.read32(messagePointer + 8); // Size in bytes u32 dataPointer = mem.read32(messagePointer + 16); log("GSP::GPU::writeHwRegs (GPU address = %08X, size = %X, data address = %08X)\n", ioAddr, size, dataPointer); @@ -230,14 +230,14 @@ void GPUService::writeHwRegs(u32 messagePointer) { // Update sequential GPU registers using an array of data and mask values using this formula // GPU register = (register & ~mask) | (data & mask). void GPUService::writeHwRegsWithMask(u32 messagePointer) { - u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned - const u32 size = mem.read32(messagePointer + 8); // Size in bytes + u32 ioAddr = mem.read32(messagePointer + 4); // GPU address based at 0x1EB00000, word aligned + const u32 size = mem.read32(messagePointer + 8); // Size in bytes - u32 dataPointer = mem.read32(messagePointer + 16); // Data pointer - u32 maskPointer = mem.read32(messagePointer + 24); // Mask pointer + u32 dataPointer = mem.read32(messagePointer + 16); // Data pointer + u32 maskPointer = mem.read32(messagePointer + 24); // Mask pointer - log("GSP::GPU::writeHwRegsWithMask (GPU address = %08X, size = %X, data address = %08X, mask address = %08X)\n", - ioAddr, size, dataPointer, maskPointer); + log("GSP::GPU::writeHwRegsWithMask (GPU address = %08X, size = %X, data address = %08X, mask address = %08X)\n", ioAddr, size, dataPointer, + maskPointer); // Check for alignment if ((size & 3) || (ioAddr & 3) || (dataPointer & 3) || (maskPointer & 3)) { @@ -351,11 +351,11 @@ void GPUService::setInternalPriorities(u32 messagePointer) { } void GPUService::processCommandBuffer() { - if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet + if (sharedMem == nullptr) [[unlikely]] { // Shared memory hasn't been set up yet return; } - constexpr int threadCount = 1; // TODO: More than 1 thread can have GSP commands at a time + constexpr int threadCount = 1; // TODO: More than 1 thread can have GSP commands at a time for (int t = 0; t < threadCount; t++) { u8* cmdBuffer = &sharedMem[0x800 + t * 0x200]; u8& commandsLeft = cmdBuffer[1]; @@ -408,9 +408,9 @@ void GPUService::memoryFill(u32* cmd) { u32 control = cmd[7]; // buf0 parameters - u32 start0 = cmd[1]; // Start address for the fill. If 0, don't fill anything - u32 value0 = cmd[2]; // Value to fill the framebuffer with - u32 end0 = cmd[3]; // End address for the fill + u32 start0 = cmd[1]; // Start address for the fill. If 0, don't fill anything + u32 value0 = cmd[2]; // Value to fill the framebuffer with + u32 end0 = cmd[3]; // End address for the fill u32 control0 = control & 0xffff; // buf1 parameters @@ -439,7 +439,7 @@ void GPUService::triggerDisplayTransfer(u32* cmd) { log("GSP::GPU::TriggerDisplayTransfer (Stubbed)\n"); gpu.displayTransfer(inputAddr, outputAddr, inputSize, outputSize, flags); - requestInterrupt(GPUInterrupt::PPF); // Send "Display transfer finished" interrupt + requestInterrupt(GPUInterrupt::PPF); // Send "Display transfer finished" interrupt } void GPUService::triggerDMARequest(u32* cmd) { @@ -453,22 +453,14 @@ void GPUService::triggerDMARequest(u32* cmd) { requestInterrupt(GPUInterrupt::DMA); } -void GPUService::flushCacheRegions(u32* cmd) { - log("GSP::GPU::FlushCacheRegions (Stubbed)\n"); -} +void GPUService::flushCacheRegions(u32* cmd) { log("GSP::GPU::FlushCacheRegions (Stubbed)\n"); } void GPUService::setBufferSwapImpl(u32 screenId, const FramebufferInfo& info) { using namespace PICA::ExternalRegs; static constexpr std::array fbAddresses = { - Framebuffer0AFirstAddr, - Framebuffer0BFirstAddr, - Framebuffer1AFirstAddr, - Framebuffer1BFirstAddr, - Framebuffer0ASecondAddr, - Framebuffer0BSecondAddr, - Framebuffer1ASecondAddr, - Framebuffer1BSecondAddr, + Framebuffer0AFirstAddr, Framebuffer0BFirstAddr, Framebuffer1AFirstAddr, Framebuffer1BFirstAddr, + Framebuffer0ASecondAddr, Framebuffer0BSecondAddr, Framebuffer1ASecondAddr, Framebuffer1BSecondAddr, }; auto& regs = gpu.getExtRegisters(); @@ -478,12 +470,7 @@ void GPUService::setBufferSwapImpl(u32 screenId, const FramebufferInfo& info) { regs[fbAddresses[fbIndex + 1]] = VaddrToPaddr(info.rightFramebufferVaddr); static constexpr std::array configAddresses = { - Framebuffer0Config, - Framebuffer0Select, - Framebuffer0Stride, - Framebuffer1Config, - Framebuffer1Select, - Framebuffer1Stride, + Framebuffer0Config, Framebuffer0Select, Framebuffer0Stride, Framebuffer1Config, Framebuffer1Select, Framebuffer1Stride, }; const u32 configIndex = screenId * 3; @@ -494,14 +481,14 @@ void GPUService::setBufferSwapImpl(u32 screenId, const FramebufferInfo& info) { // Actually send command list (aka display list) to GPU void GPUService::processCommandList(u32* cmd) { - const u32 address = cmd[1] & ~7; // Buffer address - const u32 size = cmd[2] & ~3; // Buffer size in bytes - [[maybe_unused]] const bool updateGas = cmd[3] == 1; // Update gas additive blend results (0 = don't update, 1 = update) - [[maybe_unused]] const bool flushBuffer = cmd[7] == 1; // Flush buffer (0 = don't flush, 1 = flush) + const u32 address = cmd[1] & ~7; // Buffer address + const u32 size = cmd[2] & ~3; // Buffer size in bytes + [[maybe_unused]] const bool updateGas = cmd[3] == 1; // Update gas additive blend results (0 = don't update, 1 = update) + [[maybe_unused]] const bool flushBuffer = cmd[7] == 1; // Flush buffer (0 = don't flush, 1 = flush) log("GPU::GSP::processCommandList. Address: %08X, size in bytes: %08X\n", address, size); gpu.startCommandList(address, size); - requestInterrupt(GPUInterrupt::P3D); // Send an IRQ when command list processing is over + requestInterrupt(GPUInterrupt::P3D); // Send an IRQ when command list processing is over } // TODO: Emulate the transfer engine & its registers @@ -576,4 +563,4 @@ void GPUService::importDisplayCaptureInfo(u32 messagePointer) { mem.write32(messagePointer + 28, bottomScreenCapture.rightFramebuffer); mem.write32(messagePointer + 32, bottomScreenCapture.format); mem.write32(messagePointer + 36, bottomScreenCapture.stride); -} +} \ No newline at end of file diff --git a/src/core/services/gsp_lcd.cpp b/src/core/services/gsp_lcd.cpp index c8416e03..d2e0ac21 100644 --- a/src/core/services/gsp_lcd.cpp +++ b/src/core/services/gsp_lcd.cpp @@ -1,4 +1,5 @@ #include "services/gsp_lcd.hpp" + #include "ipc.hpp" namespace LCDCommands { diff --git a/src/core/services/http.cpp b/src/core/services/http.cpp index 076afa06..801cdabb 100644 --- a/src/core/services/http.cpp +++ b/src/core/services/http.cpp @@ -19,7 +19,11 @@ void HTTPService::handleSyncRequest(u32 messagePointer) { case HTTPCommands::CreateRootCertChain: createRootCertChain(messagePointer); break; case HTTPCommands::Initialize: initialize(messagePointer); break; case HTTPCommands::RootCertChainAddDefaultCert: rootCertChainAddDefaultCert(messagePointer); break; - default: Helpers::panic("HTTP service requested. Command: %08X\n", command); + + default: + Helpers::warn("HTTP service requested. Command: %08X\n", command); + mem.write32(messagePointer + 4, Result::FailurePlaceholder); + break; } } diff --git a/src/core/services/ldr_ro.cpp b/src/core/services/ldr_ro.cpp index a6114729..48621986 100644 --- a/src/core/services/ldr_ro.cpp +++ b/src/core/services/ldr_ro.cpp @@ -22,6 +22,7 @@ namespace CROHeader { NameOffset = 0x084, NextCRO = 0x088, PrevCRO = 0x08C, + FixedSize = 0x98, OnUnresolved = 0x0AC, CodeOffset = 0x0B0, DataOffset = 0x0B8, @@ -167,6 +168,10 @@ public: return mem.read32(croPointer + CROHeader::PrevCRO); } + u32 getFixedSize() { + return mem.read32(croPointer + CROHeader::FixedSize); + } + void setNextCRO(u32 nextCRO) { mem.write32(croPointer + CROHeader::NextCRO, nextCRO); } @@ -1248,8 +1253,7 @@ void LDRService::initialize(u32 messagePointer) { Helpers::panic("Failed to rebase CRS"); } - kernel.clearInstructionCache(); - + kernel.clearInstructionCacheRange(mapVaddr, size); loadedCRS = mapVaddr; mem.write32(messagePointer, IPC::responseHeader(0x1, 1, 0)); @@ -1278,8 +1282,6 @@ void LDRService::linkCRO(u32 messagePointer) { Helpers::panic("Failed to link CRO"); } - kernel.clearInstructionCache(); - mem.write32(messagePointer, IPC::responseHeader(0x6, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } @@ -1346,8 +1348,7 @@ void LDRService::loadCRO(u32 messagePointer, bool isNew) { // TODO: add fixing cro.fix(fixLevel); - - kernel.clearInstructionCache(); + kernel.clearInstructionCacheRange(mapVaddr, size); if (isNew) { mem.write32(messagePointer, IPC::responseHeader(0x9, 2, 0)); @@ -1377,7 +1378,6 @@ void LDRService::unloadCRO(u32 messagePointer) { } CRO cro(mem, mapVaddr, true); - cro.unregisterCRO(loadedCRS); if (!cro.unlink(loadedCRS)) { @@ -1388,8 +1388,7 @@ void LDRService::unloadCRO(u32 messagePointer) { Helpers::panic("Failed to unrebase CRO"); } - kernel.clearInstructionCache(); - + kernel.clearInstructionCacheRange(mapVaddr, cro.getFixedSize()); mem.write32(messagePointer, IPC::responseHeader(0x5, 1, 0)); mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file diff --git a/src/core/services/ptm.cpp b/src/core/services/ptm.cpp index f5d02889..82ac2e52 100644 --- a/src/core/services/ptm.cpp +++ b/src/core/services/ptm.cpp @@ -1,4 +1,5 @@ #include "services/ptm.hpp" + #include "ipc.hpp" namespace PTMCommands { @@ -128,7 +129,7 @@ void PTMService::getTotalStepCount(u32 messagePointer) { log("PTM::GetTotalStepCount\n"); mem.write32(messagePointer, IPC::responseHeader(0xC, 2, 0)); mem.write32(messagePointer + 4, Result::Success); - mem.write32(messagePointer + 8, 3); // We walk a lot + mem.write32(messagePointer + 8, 3); // We walk a lot } void PTMService::configureNew3DSCPU(u32 messagePointer) { diff --git a/src/core/services/service_manager.cpp b/src/core/services/service_manager.cpp index f99b6668..6f463894 100644 --- a/src/core/services/service_manager.cpp +++ b/src/core/services/service_manager.cpp @@ -114,6 +114,7 @@ static std::map serviceMap = { { "cfg:u", KernelHandles::CFG_U }, { "cfg:i", KernelHandles::CFG_I }, { "cfg:s", KernelHandles::CFG_S }, + { "cfg:nor", KernelHandles::CFG_NOR }, { "csnd:SND", KernelHandles::CSND }, { "dlp:SRVR", KernelHandles::DLP_SRVR }, { "dsp::DSP", KernelHandles::DSP }, @@ -134,6 +135,7 @@ static std::map serviceMap = { { "news:u", KernelHandles::NEWS_U }, { "nfc:u", KernelHandles::NFC }, { "ns:s", KernelHandles::NS_S }, + { "nwm::EXT", KernelHandles::NWM_EXT }, { "nwm::UDS", KernelHandles::NWM_UDS }, { "nim:aoc", KernelHandles::NIM_AOC }, { "nim:u", KernelHandles::NIM_U }, @@ -223,6 +225,7 @@ void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) { case KernelHandles::CFG_U: cfg.handleSyncRequest(messagePointer, CFGService::Type::U); break; case KernelHandles::CFG_I: cfg.handleSyncRequest(messagePointer, CFGService::Type::I); break; case KernelHandles::CFG_S: cfg.handleSyncRequest(messagePointer, CFGService::Type::S); break; + case KernelHandles::CFG_NOR: cfg.handleSyncRequest(messagePointer, CFGService::Type::NOR); break; case KernelHandles::CSND: csnd.handleSyncRequest(messagePointer); break; case KernelHandles::DLP_SRVR: dlp_srvr.handleSyncRequest(messagePointer); break; case KernelHandles::HID: hid.handleSyncRequest(messagePointer); break; @@ -246,6 +249,7 @@ void ServiceManager::sendCommandToService(u32 messagePointer, Handle handle) { case KernelHandles::PTM_PLAY: ptm.handleSyncRequest(messagePointer, PTMService::Type::PLAY); break; case KernelHandles::PTM_SYSM: ptm.handleSyncRequest(messagePointer, PTMService::Type::SYSM); break; case KernelHandles::PTM_U: ptm.handleSyncRequest(messagePointer, PTMService::Type::U); break; + case KernelHandles::PTM_GETS: ptm.handleSyncRequest(messagePointer, PTMService::Type::GETS); break; case KernelHandles::SOC: soc.handleSyncRequest(messagePointer); break; case KernelHandles::SSL: ssl.handleSyncRequest(messagePointer); break; case KernelHandles::Y2R: y2r.handleSyncRequest(messagePointer); break; diff --git a/src/emulator.cpp b/src/emulator.cpp index 86adbf22..ca6f3f7d 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -32,18 +32,14 @@ Emulator::Emulator() dspService.setDSPCore(dsp.get()); audioDevice.init(dsp->getSamples()); - setAudioEnabled(config.audioEnabled); - - if (Renderdoc::isSupported() && config.enableRenderdoc) { - loadRenderdoc(); - } - #ifdef PANDA3DS_ENABLE_DISCORD_RPC if (config.discordRpcEnabled) { discordRpc.init(); updateDiscord(); } #endif + + reloadSettings(); reset(ReloadOption::NoReload); } @@ -105,13 +101,18 @@ std::filesystem::path Emulator::getConfigPath() { if constexpr (Helpers::isAndroid()) { return getAndroidAppPath() / "config.toml"; } else { - return std::filesystem::current_path() / "config.toml"; + std::filesystem::path localPath = std::filesystem::current_path() / "config.toml"; + + if (std::filesystem::exists(localPath)) { + return localPath; + } else { + return getAppDataRoot() / "config.toml"; + } } } #endif void Emulator::step() {} -void Emulator::render() {} // Only resume if a ROM is properly loaded void Emulator::resume() { @@ -456,6 +457,8 @@ void Emulator::reloadSettings() { loadRenderdoc(); } + gpu.getRenderer()->setHashTextures(config.hashTextures); + #ifdef PANDA3DS_ENABLE_DISCORD_RPC // Reload RPC setting if we're compiling with RPC support @@ -468,4 +471,4 @@ void Emulator::reloadSettings() { } } #endif -} \ No newline at end of file +} diff --git a/src/frontend_settings.cpp b/src/frontend_settings.cpp index 498ba500..2d1d37c6 100644 --- a/src/frontend_settings.cpp +++ b/src/frontend_settings.cpp @@ -11,7 +11,7 @@ FrontendSettings::Theme FrontendSettings::themeFromString(std::string inString) std::transform(inString.begin(), inString.end(), inString.begin(), [](unsigned char c) { return std::tolower(c); }); static const std::unordered_map map = { - {"system", Theme::System}, {"light", Theme::Light}, {"dark", Theme::Dark}, {"greetingscat", Theme::GreetingsCat}, {"cream", Theme::Cream}, + {"system", Theme::System}, {"light", Theme::Light}, {"dark", Theme::Dark}, {"greetingscat", Theme::GreetingsCat}, {"cream", Theme::Cream}, {"oled", Theme::Oled} }; if (auto search = map.find(inString); search != map.end()) { @@ -28,6 +28,7 @@ const char* FrontendSettings::themeToString(Theme theme) { case Theme::Light: return "light"; case Theme::GreetingsCat: return "greetingscat"; case Theme::Cream: return "cream"; + case Theme::Oled: return "oled"; case Theme::Dark: default: return "dark"; @@ -39,7 +40,7 @@ FrontendSettings::WindowIcon FrontendSettings::iconFromString(std::string inStri static const std::unordered_map map = { {"rpog", WindowIcon::Rpog}, {"rsyn", WindowIcon::Rsyn}, {"rcow", WindowIcon::Rcow}, - {"rnap", WindowIcon::Rnap}, {"skyemu", WindowIcon::SkyEmu}, + {"rnap", WindowIcon::Rnap}, {"skyemu", WindowIcon::SkyEmu}, {"runpog", WindowIcon::Runpog}, }; if (auto search = map.find(inString); search != map.end()) { @@ -56,6 +57,7 @@ const char* FrontendSettings::iconToString(WindowIcon icon) { case WindowIcon::Rcow: return "rcow"; case WindowIcon::Rnap: return "rnap"; case WindowIcon::SkyEmu: return "skyemu"; + case WindowIcon::Runpog: return "runpog"; case WindowIcon::Rpog: default: return "rpog"; diff --git a/src/host_shaders/metal_shaders.metal b/src/host_shaders/metal_shaders.metal index 18c310f7..b9640816 100644 --- a/src/host_shaders/metal_shaders.metal +++ b/src/host_shaders/metal_shaders.metal @@ -1,4 +1,6 @@ #include +#include + using namespace metal; struct BasicVertexOut { @@ -219,12 +221,6 @@ struct Globals { uint GPUREG_LIGHTING_LUTINPUT_SELECT; uint GPUREG_LIGHTi_CONFIG; - // HACK - //bool lightingEnabled; - //uint8_t lightingNumLights; - //uint32_t lightingConfig1; - //uint16_t alphaControl; - float3 normal; }; @@ -655,14 +651,15 @@ float4 performLogicOp(LogicOp logicOp, float4 s, float4 d) { return as_type(performLogicOpU(logicOp, as_type(s), as_type(d))); } -fragment float4 fragmentDraw(DrawVertexOut in [[stage_in]], float4 prevColor [[color(0)]], constant PicaRegs& picaRegs [[buffer(0)]], constant FragTEV& tev [[buffer(1)]], constant LogicOp& logicOp [[buffer(2)]], constant uint2& lutSlices [[buffer(3)]], texture2d tex0 [[texture(0)]], texture2d tex1 [[texture(1)]], texture2d tex2 [[texture(2)]], texture2d_array texLightingLut [[texture(3)]], texture1d_array texFogLut [[texture(4)]], sampler samplr0 [[sampler(0)]], sampler samplr1 [[sampler(1)]], sampler samplr2 [[sampler(2)]], sampler linearSampler [[sampler(3)]]) { - Globals globals; +// iOS simulator doesn't support fb fetch, so don't enable it +#ifndef TARGET_OS_SIMULATOR +#define PREVIOUS_COLOR_DECL float4 prevColor [[color(0)]], +#else +#define PREVIOUS_COLOR_DECL +#endif - // HACK - //globals.lightingEnabled = picaRegs.read(0x008Fu) != 0u; - //globals.lightingNumLights = picaRegs.read(0x01C2u); - //globals.lightingConfig1 = picaRegs.read(0x01C4u); - //globals.alphaControl = picaRegs.read(0x104); +fragment float4 fragmentDraw(DrawVertexOut in [[stage_in]], PREVIOUS_COLOR_DECL constant PicaRegs& picaRegs [[buffer(0)]], constant FragTEV& tev [[buffer(1)]], constant LogicOp& logicOp [[buffer(2)]], constant uint2& lutSlices [[buffer(3)]], texture2d tex0 [[texture(0)]], texture2d tex1 [[texture(1)]], texture2d tex2 [[texture(2)]], texture2d_array texLightingLut [[texture(3)]], texture1d_array texFogLut [[texture(4)]], sampler samplr0 [[sampler(0)]], sampler samplr1 [[sampler(1)]], sampler samplr2 [[sampler(2)]], sampler linearSampler [[sampler(3)]]) { + Globals globals; globals.tevSources[0] = in.color; if (lightingEnabled) { @@ -755,5 +752,9 @@ fragment float4 fragmentDraw(DrawVertexOut in [[stage_in]], float4 prevColor [[c } } +#ifndef TARGET_OS_SIMULATOR return performLogicOp(logicOp, color, prevColor); -} +#else + return performLogicOp(logicOp, color, float4(0.0)); +#endif +} \ No newline at end of file diff --git a/src/host_shaders/opengl_es_display.frag b/src/host_shaders/opengl_es_display.frag new file mode 100644 index 00000000..600ebfcd --- /dev/null +++ b/src/host_shaders/opengl_es_display.frag @@ -0,0 +1,10 @@ +#version 310 es +precision mediump float; + +in vec2 UV; +out vec4 FragColor; + +uniform sampler2D u_texture; +void main() { + FragColor = texture(u_texture, UV); +} \ No newline at end of file diff --git a/src/host_shaders/opengl_es_display.vert b/src/host_shaders/opengl_es_display.vert new file mode 100644 index 00000000..04fadfc6 --- /dev/null +++ b/src/host_shaders/opengl_es_display.vert @@ -0,0 +1,25 @@ +#version 310 es +precision mediump float; + +out vec2 UV; + +void main() { + const vec4 positions[4] = vec4[]( + vec4(-1.0, 1.0, 1.0, 1.0), // Top-left + vec4(1.0, 1.0, 1.0, 1.0), // Top-right + vec4(-1.0, -1.0, 1.0, 1.0), // Bottom-left + vec4(1.0, -1.0, 1.0, 1.0) // Bottom-right + ); + + // The 3DS displays both screens' framebuffer rotated 90 deg counter clockwise + // So we adjust our texcoords accordingly + const vec2 texcoords[4] = vec2[]( + vec2(1.0, 1.0), // Top-right + vec2(1.0, 0.0), // Bottom-right + vec2(0.0, 1.0), // Top-left + vec2(0.0, 0.0) // Bottom-left + ); + + gl_Position = positions[gl_VertexID]; + UV = texcoords[gl_VertexID]; +} \ No newline at end of file diff --git a/src/hydra_core.cpp b/src/hydra_core.cpp index 078b8a6c..0bcd21a8 100644 --- a/src/hydra_core.cpp +++ b/src/hydra_core.cpp @@ -118,6 +118,7 @@ void HydraCore::resetContext() { if (!gladLoadGLES2Loader(reinterpret_cast(getProcAddress))) { Helpers::panic("OpenGL ES init failed"); } + emulator->getRenderer()->setupGLES(); #else if (!gladLoadGLLoader(reinterpret_cast(getProcAddress))) { Helpers::panic("OpenGL init failed"); diff --git a/src/ios_driver.mm b/src/ios_driver.mm new file mode 100644 index 00000000..8ec87436 --- /dev/null +++ b/src/ios_driver.mm @@ -0,0 +1,38 @@ +#import + +extern "C" { +#include "ios_driver.h" +} + +// Apple's Foundation headers define some macros globablly that create issues with our own code, so remove the definitions +#undef ABS +#undef NO + +#include +#include "emulator.hpp" + +// The Objective-C++ bridge functions must be exported without name mangling in order for the SwiftUI frontend to be able to call them +#define IOS_EXPORT extern "C" __attribute__((visibility("default"))) + +std::unique_ptr emulator = nullptr; +HIDService* hidService = nullptr; + +IOS_EXPORT void iosCreateEmulator() { + printf("Creating emulator\n"); + + emulator = std::make_unique(); + hidService = &emulator->getServiceManager().getHID(); + emulator->initGraphicsContext(nullptr); +} + +IOS_EXPORT void iosRunFrame(CAMetalLayer* layer) { + void* layerBridged = (__bridge void*)layer; + + emulator->getRenderer()->setMTKLayer(layerBridged); + emulator->runFrame(); +} + +IOS_EXPORT void iosLoadROM(NSString* pathNS) { + auto path = std::filesystem::path([pathNS UTF8String]); + emulator->loadROM(path); +} \ No newline at end of file diff --git a/src/jni_driver.cpp b/src/jni_driver.cpp index 60bbc680..6a156360 100644 --- a/src/jni_driver.cpp +++ b/src/jni_driver.cpp @@ -78,6 +78,7 @@ AlberFunction(void, Initialize)(JNIEnv* env, jobject obj) { } __android_log_print(ANDROID_LOG_INFO, "AlberDriver", "OpenGL ES %d.%d", GLVersion.major, GLVersion.minor); + emulator->getRenderer()->setupGLES(); emulator->initGraphicsContext(nullptr); } @@ -153,7 +154,6 @@ int AndroidUtils::openDocument(const char* path, const char* perms) { jstring uri = env->NewStringUTF(path); jstring jmode = env->NewStringUTF(perms); - jint result = env->CallStaticIntMethod(alberClass, alberClassOpenDocument, uri, jmode); env->DeleteLocalRef(uri); diff --git a/src/libretro_core.cpp b/src/libretro_core.cpp index 1e5b532d..24651516 100644 --- a/src/libretro_core.cpp +++ b/src/libretro_core.cpp @@ -17,7 +17,8 @@ static retro_input_state_t inputStateCallback; static retro_hw_render_callback hwRender; static std::filesystem::path savePath; -static bool screenTouched; +static bool screenTouched = false; +static bool usingGLES = false; std::unique_ptr emulator; RendererGL* renderer; @@ -35,15 +36,19 @@ static void* getGLProcAddress(const char* name) { } static void videoResetContext() { -#ifdef USING_GLES - if (!gladLoadGLES2Loader(reinterpret_cast(getGLProcAddress))) { - Helpers::panic("OpenGL ES init failed"); + if (usingGLES) { + if (!gladLoadGLES2Loader(reinterpret_cast(getGLProcAddress))) { + Helpers::panic("OpenGL ES init failed"); + } + + emulator->getRenderer()->setupGLES(); } -#else - if (!gladLoadGLLoader(reinterpret_cast(getGLProcAddress))) { - Helpers::panic("OpenGL init failed"); + + else { + if (!gladLoadGLLoader(reinterpret_cast(getGLProcAddress))) { + Helpers::panic("OpenGL init failed"); + } } -#endif emulator->initGraphicsContext(nullptr); } @@ -73,6 +78,7 @@ static bool setHWRender(retro_hw_context_type type) { hwRender.version_minor = 1; if (envCallback(RETRO_ENVIRONMENT_SET_HW_RENDER, &hwRender)) { + usingGLES = true; return true; } break; @@ -170,8 +176,12 @@ static void configInit() { {"panda3ds_use_ubershader", EmulatorConfig::ubershaderDefault ? "Use ubershaders (No stutter, maybe slower); enabled|disabled" : "Use ubershaders (No stutter, maybe slower); disabled|enabled"}, {"panda3ds_use_vsync", "Enable VSync; enabled|disabled"}, + {"panda3ds_hash_textures", EmulatorConfig::hashTexturesDefault ? "Hash textures (Better graphics, maybe slower); enabled|disabled" + : "Hash textures (Better graphics, maybe slower); disabled|enabled"}, + + {"panda3ds_system_language", "System language; En|Fr|Es|De|It|Pt|Nl|Ru|Ja|Zh|Ko|Tw"}, {"panda3ds_dsp_emulation", "DSP emulation; HLE|LLE|Null"}, - {"panda3ds_use_audio", "Enable audio; disabled|enabled"}, + {"panda3ds_use_audio", EmulatorConfig::audioEnabledDefault ? "Enable audio; enabled|disabled" : "Enable audio; disabled|enabled"}, {"panda3ds_audio_volume", "Audio volume; 100|0|10|20|40|60|80|90|100|120|140|150|180|200"}, {"panda3ds_mute_audio", "Mute audio; disabled|enabled"}, {"panda3ds_enable_aac", "Enable AAC audio; enabled|disabled"}, @@ -196,6 +206,8 @@ static void configUpdate() { config.shaderJitEnabled = fetchVariableBool("panda3ds_use_shader_jit", EmulatorConfig::shaderJitDefault); config.chargerPlugged = fetchVariableBool("panda3ds_use_charger", true); config.batteryPercentage = fetchVariableRange("panda3ds_battery_level", 5, 100); + config.systemLanguage = EmulatorConfig::languageCodeFromString(fetchVariable("panda3ds_system_language", "en")); + config.dspType = Audio::DSPCore::typeFromString(fetchVariable("panda3ds_dsp_emulation", "null")); config.audioEnabled = fetchVariableBool("panda3ds_use_audio", false); config.aacEnabled = fetchVariableBool("panda3ds_enable_aac", true); @@ -207,6 +219,7 @@ static void configUpdate() { config.accurateShaderMul = fetchVariableBool("panda3ds_accurate_shader_mul", false); config.useUbershaders = fetchVariableBool("panda3ds_use_ubershader", EmulatorConfig::ubershaderDefault); config.accelerateShaders = fetchVariableBool("panda3ds_accelerate_shaders", EmulatorConfig::accelerateShadersDefault); + config.hashTextures = fetchVariableBool("panda3ds_hash_textures", EmulatorConfig::hashTexturesDefault); config.forceShadergenForLights = fetchVariableBool("panda3ds_ubershader_lighting_override", true); config.lightShadergenThreshold = fetchVariableRange("panda3ds_ubershader_lighting_override_threshold", 1, 8); @@ -380,6 +393,8 @@ void retro_run() { emulator->runFrame(); videoCallback(RETRO_HW_FRAME_BUFFER_VALID, emulator->width, emulator->height, 0); + // Call audio batch callback + emulator->getAudioDevice().renderBatch(audioBatchCallback); } void retro_set_controller_port_device(uint port, uint device) {} diff --git a/src/miniaudio.cpp b/src/miniaudio/miniaudio.cpp similarity index 82% rename from src/miniaudio.cpp rename to src/miniaudio/miniaudio.cpp index a61979e0..aa816812 100644 --- a/src/miniaudio.cpp +++ b/src/miniaudio/miniaudio.cpp @@ -4,4 +4,6 @@ #define MA_NO_ENCODING #define MINIAUDIO_IMPLEMENTATION -#include "miniaudio.h" \ No newline at end of file +#ifndef PANDA3DS_IOS +#include "miniaudio.h" +#endif \ No newline at end of file diff --git a/src/miniaudio/miniaudio.m b/src/miniaudio/miniaudio.m new file mode 100644 index 00000000..80934f06 --- /dev/null +++ b/src/miniaudio/miniaudio.m @@ -0,0 +1,8 @@ +// We do not need the ability to be able to encode or decode audio files for the time being +// So we disable said functionality to make the executable smaller. +#define MA_NO_DECODING +#define MA_NO_ENCODING +#define MINIAUDIO_IMPLEMENTATION + +// On iOS we have to compile miniaudio as Obj-C +#include "miniaudio.h" diff --git a/src/panda_qt/config_window.cpp b/src/panda_qt/config_window.cpp index 519a4a22..0b2eb64b 100644 --- a/src/panda_qt/config_window.cpp +++ b/src/panda_qt/config_window.cpp @@ -71,6 +71,7 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win themeSelect->addItem(tr("Dark")); themeSelect->addItem(tr("Greetings Cat")); themeSelect->addItem(tr("Cream")); + themeSelect->addItem(tr("OLED")); themeSelect->setCurrentIndex(static_cast(config.frontendSettings.theme)); connect(themeSelect, &QComboBox::currentIndexChanged, this, [&](int index) { config.frontendSettings.theme = static_cast(index); @@ -86,6 +87,7 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win iconSelect->addItem(tr("Sleepy panda")); iconSelect->addItem(tr("Cow panda")); iconSelect->addItem(tr("The penguin from SkyEmu")); + iconSelect->addItem(tr("Unpog")); iconSelect->setCurrentIndex(static_cast(config.frontendSettings.icon)); connect(iconSelect, &QComboBox::currentIndexChanged, this, [&](int index) { @@ -145,6 +147,27 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win romLayout->addWidget(browseRomPath); genLayout->addRow(tr("Default ROMs path"), romLayout); + QComboBox* systemLanguage = new QComboBox(); + systemLanguage->addItem(tr("Japanese")); + systemLanguage->addItem(tr("English")); + systemLanguage->addItem(tr("French")); + systemLanguage->addItem(tr("German")); + systemLanguage->addItem(tr("Italian")); + systemLanguage->addItem(tr("Spanish")); + systemLanguage->addItem(tr("Chinese")); + systemLanguage->addItem(tr("Korean")); + systemLanguage->addItem(tr("Dutch")); + systemLanguage->addItem(tr("Portuguese")); + systemLanguage->addItem(tr("Russian")); + systemLanguage->addItem(tr("Taiwanese")); + + systemLanguage->setCurrentIndex(static_cast(config.systemLanguage)); + connect(systemLanguage, &QComboBox::currentIndexChanged, this, [&](int index) { + config.systemLanguage = static_cast(index); + updateConfig(); + }); + genLayout->addRow(tr("System language"), systemLanguage); + QCheckBox* discordRpcEnabled = new QCheckBox(tr("Enable Discord RPC")); connectCheckbox(discordRpcEnabled, config.discordRpcEnabled); genLayout->addRow(discordRpcEnabled); @@ -163,14 +186,24 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win gpuLayout->setHorizontalSpacing(20); gpuLayout->setVerticalSpacing(10); - QComboBox* rendererType = new QComboBox; + QComboBox* rendererType = new QComboBox(); rendererType->addItem(tr("Null")); rendererType->addItem(tr("OpenGL")); rendererType->addItem(tr("Vulkan")); rendererType->setCurrentIndex(static_cast(config.rendererType)); connect(rendererType, &QComboBox::currentIndexChanged, this, [&](int index) { - config.rendererType = static_cast(index); - updateConfig(); + auto type = static_cast(index); + + if (type == RendererType::Vulkan) { + QMessageBox messageBox( + QMessageBox::Icon::Critical, tr("Vulkan renderer unavailable"), + tr("Qt UI doesn't currently support Vulkan, try again at a later time") + ); + messageBox.exec(); + } else { + config.rendererType = type; + updateConfig(); + } }); gpuLayout->addRow(tr("GPU renderer"), rendererType); @@ -198,6 +231,11 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win connectCheckbox(accelerateShaders, config.accelerateShaders); gpuLayout->addRow(accelerateShaders); + QCheckBox* hashTextures = new QCheckBox(tr("Hash textures")); + hashTextures->setToolTip(tr("Enable this to reduce texture mismatches at the cost of slightly lower performance")); + connectCheckbox(hashTextures, config.hashTextures); + gpuLayout->addRow(hashTextures); + QCheckBox* forceShadergenForLights = new QCheckBox(tr("Force shadergen when rendering lights")); connectCheckbox(forceShadergenForLights, config.forceShadergenForLights); gpuLayout->addRow(forceShadergenForLights); @@ -217,7 +255,7 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win audioLayout->setHorizontalSpacing(20); audioLayout->setVerticalSpacing(10); - QComboBox* dspType = new QComboBox; + QComboBox* dspType = new QComboBox(); dspType->addItem(tr("Null")); dspType->addItem(tr("LLE")); dspType->addItem(tr("HLE")); @@ -244,7 +282,7 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win connectCheckbox(muteAudio, config.audioDeviceConfig.muteAudio); audioLayout->addRow(muteAudio); - QComboBox* volumeCurveType = new QComboBox; + QComboBox* volumeCurveType = new QComboBox(); volumeCurveType->addItem(tr("Cubic")); volumeCurveType->addItem(tr("Linear")); volumeCurveType->setCurrentIndex(static_cast(config.audioDeviceConfig.volumeCurve)); @@ -406,6 +444,34 @@ void ConfigWindow::setTheme(Theme theme) { break; } + case Theme::Oled: { + QApplication::setStyle(QStyleFactory::create("Fusion")); + + QPalette p; + p.setColor(QPalette::Window, Qt::black); + p.setColor(QPalette::WindowText, Qt::white); + p.setColor(QPalette::Base, Qt::black); + p.setColor(QPalette::AlternateBase, Qt::black); + p.setColor(QPalette::ToolTipBase, Qt::black); + p.setColor(QPalette::ToolTipText, Qt::white); + p.setColor(QPalette::Text, Qt::white); + p.setColor(QPalette::Button, QColor(5, 5, 5)); + p.setColor(QPalette::ButtonText, Qt::white); + p.setColor(QPalette::BrightText, Qt::red); + p.setColor(QPalette::Link, QColor(42, 130, 218)); + + p.setColor(QPalette::Highlight, QColor(42, 130, 218)); + p.setColor(QPalette::HighlightedText, Qt::black); + qApp->setPalette(p); + qApp->setStyleSheet("QLineEdit {" + "background-color: #000000; color: #ffffff; border: 1px solid #a0a0a0; " + "border-radius: 4px; padding: 5px; }" + + "QCheckBox::indicator:unchecked {" + "border: 1px solid #808080; border-radius: 4px; }"); + break; + } + case Theme::System: { qApp->setPalette(this->style()->standardPalette()); qApp->setStyle(QStyleFactory::create("WindowsVista")); @@ -423,6 +489,7 @@ void ConfigWindow::setIcon(WindowIcon icon) { case WindowIcon::Rnap: updateIcon(":/docs/img/rnap_icon.png"); break; case WindowIcon::Rcow: updateIcon(":/docs/img/rcow_icon.png"); break; case WindowIcon::SkyEmu: updateIcon(":/docs/img/skyemu_icon.png"); break; + case WindowIcon::Runpog: updateIcon(":/docs/img/runpog_icon.png"); break; case WindowIcon::Rpog: default: updateIcon(":/docs/img/rpog_icon.png"); break; diff --git a/src/panda_qt/main.cpp b/src/panda_qt/main.cpp index a7a6216c..4ab737b0 100644 --- a/src/panda_qt/main.cpp +++ b/src/panda_qt/main.cpp @@ -7,6 +7,5 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWindow window(&app); - window.show(); return app.exec(); } diff --git a/src/panda_qt/main_window.cpp b/src/panda_qt/main_window.cpp index 881dc02d..c060318e 100644 --- a/src/panda_qt/main_window.cpp +++ b/src/panda_qt/main_window.cpp @@ -22,14 +22,13 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent) // Enable drop events for loading ROMs setAcceptDrops(true); resize(800, 240 * 4); + show(); // We pass a callback to the screen widget that will be triggered every time we resize the screen screen = new ScreenWidget([this](u32 width, u32 height) { handleScreenResize(width, height); }, this); setCentralWidget(screen); - screen->show(); appRunning = true; - // Set our menu bar up menuBar = new QMenuBar(nullptr); @@ -140,6 +139,10 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent) glContext->MakeCurrent(); glContext->SetSwapInterval(emu->getConfig().vsyncEnabled ? 1 : 0); + if (glContext->IsGLES()) { + emu->getRenderer()->setupGLES(); + } + emu->initGraphicsContext(glContext); } else if (usingVk) { Helpers::panic("Vulkan on Qt is currently WIP, try the SDL frontend instead!"); @@ -695,4 +698,4 @@ void MainWindow::setupControllerSensors(SDL_GameController* controller) { if (haveAccelerometer) { SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); } -} \ No newline at end of file +} diff --git a/src/panda_qt/screen.cpp b/src/panda_qt/screen.cpp index 25ff576c..fc783683 100644 --- a/src/panda_qt/screen.cpp +++ b/src/panda_qt/screen.cpp @@ -29,6 +29,7 @@ ScreenWidget::ScreenWidget(ResizeCallback resizeCallback, QWidget* parent) : QWi setAttribute(Qt::WA_KeyCompression, false); setFocusPolicy(Qt::StrongFocus); setMouseTracking(true); + show(); if (!createGLContext()) { Helpers::panic("Failed to create GL context for display"); @@ -60,11 +61,12 @@ void ScreenWidget::resizeSurface(u32 width, u32 height) { } bool ScreenWidget::createGLContext() { - // List of GL context versions we will try. Anything 4.1+ is good - static constexpr std::array versionsToTry = { + // List of GL context versions we will try. Anything 4.1+ is good for desktop OpenGL, and 3.1+ for OpenGL ES + static constexpr std::array versionsToTry = { GL::Context::Version{GL::Context::Profile::Core, 4, 6}, GL::Context::Version{GL::Context::Profile::Core, 4, 5}, GL::Context::Version{GL::Context::Profile::Core, 4, 4}, GL::Context::Version{GL::Context::Profile::Core, 4, 3}, GL::Context::Version{GL::Context::Profile::Core, 4, 2}, GL::Context::Version{GL::Context::Profile::Core, 4, 1}, + GL::Context::Version{GL::Context::Profile::ES, 3, 2}, GL::Context::Version{GL::Context::Profile::ES, 3, 1}, }; std::optional windowInfo = getWindowInfo(); @@ -72,6 +74,10 @@ bool ScreenWidget::createGLContext() { this->windowInfo = *windowInfo; glContext = GL::Context::Create(*getWindowInfo(), versionsToTry); + if (glContext == nullptr) { + return false; + } + glContext->DoneCurrent(); } @@ -79,7 +85,7 @@ bool ScreenWidget::createGLContext() { } qreal ScreenWidget::devicePixelRatioFromScreen() const { - const QScreen* screenForRatio = window()->windowHandle()->screen(); + const QScreen* screenForRatio = windowHandle()->screen(); if (!screenForRatio) { screenForRatio = QGuiApplication::primaryScreen(); } diff --git a/src/panda_qt/translations.cpp b/src/panda_qt/translations.cpp index bfadd570..cefc6263 100644 --- a/src/panda_qt/translations.cpp +++ b/src/panda_qt/translations.cpp @@ -46,12 +46,13 @@ struct LanguageInfo { // Please keep this list mostly in alphabetical order. // Also, for Unicode characters in language names, use Unicode keycodes instead of writing out the name, // as some compilers/toolchains may not enjoy Unicode in source files. -static std::array languages = { +static std::array languages = { LanguageInfo(QStringLiteral(u"English"), "en"), // English LanguageInfo(QStringLiteral(u"\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC"), "el"), // Greek LanguageInfo(QStringLiteral(u"Espa\u00F1ol"), "es"), // Spanish LanguageInfo(QStringLiteral(u"Nederlands"), "nl"), // Dutch - LanguageInfo(QStringLiteral(u"Portugu\u00EAs (Brasil)"), "pt_br") // Portuguese (Brazilian) + LanguageInfo(QStringLiteral(u"Portugu\u00EAs (Brasil)"), "pt_br"), // Portuguese (Brazilian) + LanguageInfo(QStringLiteral(u"Svenska"), "sv"), // Swedish }; QComboBox* ConfigWindow::createLanguageSelect() { diff --git a/src/panda_sdl/frontend_sdl.cpp b/src/panda_sdl/frontend_sdl.cpp index 1c07c25e..2d60d2fa 100644 --- a/src/panda_sdl/frontend_sdl.cpp +++ b/src/panda_sdl/frontend_sdl.cpp @@ -71,11 +71,27 @@ FrontendSDL::FrontendSDL() : keyboardMappings(InputMappings::defaultKeyboardMapp glContext = SDL_GL_CreateContext(window); if (glContext == nullptr) { - Helpers::panic("OpenGL context creation failed: %s", SDL_GetError()); - } + Helpers::warn("OpenGL context creation failed: %s\nTrying again with OpenGL ES.", SDL_GetError()); - if (!gladLoadGLLoader(reinterpret_cast(SDL_GL_GetProcAddress))) { - Helpers::panic("OpenGL init failed"); + // Some low end devices (eg RPi, emulation handhelds) don't support desktop GL, but only OpenGL ES, so fall back to that if GL context + // creation failed + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + glContext = SDL_GL_CreateContext(window); + if (glContext == nullptr) { + Helpers::panic("OpenGL context creation failed: %s", SDL_GetError()); + } + + if (!gladLoadGLES2Loader(reinterpret_cast(SDL_GL_GetProcAddress))) { + Helpers::panic("OpenGL init failed"); + } + + emu.getRenderer()->setupGLES(); + } else { + if (!gladLoadGLLoader(reinterpret_cast(SDL_GL_GetProcAddress))) { + Helpers::panic("OpenGL init failed"); + } } SDL_GL_SetSwapInterval(config.vsyncEnabled ? 1 : 0); diff --git a/src/pandios/.gitignore b/src/pandios/.gitignore new file mode 100644 index 00000000..1bad9862 --- /dev/null +++ b/src/pandios/.gitignore @@ -0,0 +1,2 @@ +libAlber.dylib +Alber/Headers/ios_driver.h \ No newline at end of file diff --git a/src/pandios/Alber/Headers/ios_driver.h b/src/pandios/Alber/Headers/ios_driver.h new file mode 100644 index 00000000..7f783970 --- /dev/null +++ b/src/pandios/Alber/Headers/ios_driver.h @@ -0,0 +1,7 @@ +#pragma once +#include +#include + +void iosCreateEmulator(); +void iosLoadROM(NSString* pathNS); +void iosRunFrame(CAMetalLayer* layer); \ No newline at end of file diff --git a/src/pandios/Alber/module.map b/src/pandios/Alber/module.map new file mode 100644 index 00000000..54ca3f2a --- /dev/null +++ b/src/pandios/Alber/module.map @@ -0,0 +1,5 @@ +module AlberDriver { + umbrella "Headers" // for multiple files + link "libAlber" + export * +} \ No newline at end of file diff --git a/src/pandios/Pandios.xcodeproj/project.pbxproj b/src/pandios/Pandios.xcodeproj/project.pbxproj new file mode 100644 index 00000000..3f698015 --- /dev/null +++ b/src/pandios/Pandios.xcodeproj/project.pbxproj @@ -0,0 +1,587 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 70; + objects = { + +/* Begin PBXBuildFile section */ + 4F798C782D8747B000F5D23F /* libAlber.dylib in Copy Files */ = {isa = PBXBuildFile; fileRef = 4F798C772D8747B000F5D23F /* libAlber.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 4F798C7A2D8747F400F5D23F /* libAlber.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F798C792D8747B800F5D23F /* libAlber.dylib */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 4F6E8FD32D77C0140025DD0D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4F6E8FBA2D77C0120025DD0D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4F6E8FC12D77C0120025DD0D; + remoteInfo = Pandios; + }; + 4F6E8FDD2D77C0140025DD0D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4F6E8FBA2D77C0120025DD0D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4F6E8FC12D77C0120025DD0D; + remoteInfo = Pandios; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 4F9EEBE82D78898B00E0B72D /* Copy Files */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 4F798C782D8747B000F5D23F /* libAlber.dylib in Copy Files */, + ); + name = "Copy Files"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 4F6E8FC22D77C0120025DD0D /* Pandios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Pandios.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4F6E8FD22D77C0140025DD0D /* PandiosTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PandiosTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 4F6E8FDC2D77C0140025DD0D /* PandiosUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PandiosUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 4F798C772D8747B000F5D23F /* libAlber.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libAlber.dylib; path = ../../build/libAlber.dylib; sourceTree = ""; }; + 4F798C792D8747B800F5D23F /* libAlber.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libAlber.dylib; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 4F6E8FC42D77C0120025DD0D /* Pandios */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Pandios; sourceTree = ""; }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4F6E8FCF2D77C0140025DD0D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4F6E8FD92D77C0140025DD0D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4F9EEBF82D78963D00E0B72D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4F798C7A2D8747F400F5D23F /* libAlber.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4F6E8FB92D77C0120025DD0D = { + isa = PBXGroup; + children = ( + 4F798C772D8747B000F5D23F /* libAlber.dylib */, + 4F6E8FC42D77C0120025DD0D /* Pandios */, + 4F9EEBF62D7895D700E0B72D /* Frameworks */, + 4F6E8FC32D77C0120025DD0D /* Products */, + ); + sourceTree = ""; + }; + 4F6E8FC32D77C0120025DD0D /* Products */ = { + isa = PBXGroup; + children = ( + 4F6E8FC22D77C0120025DD0D /* Pandios.app */, + 4F6E8FD22D77C0140025DD0D /* PandiosTests.xctest */, + 4F6E8FDC2D77C0140025DD0D /* PandiosUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 4F9EEBF62D7895D700E0B72D /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4F798C792D8747B800F5D23F /* libAlber.dylib */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 4F6E8FC12D77C0120025DD0D /* Pandios */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4F6E8FE62D77C0140025DD0D /* Build configuration list for PBXNativeTarget "Pandios" */; + buildPhases = ( + 4F6E8FBE2D77C0120025DD0D /* Sources */, + 4F6E8FC02D77C0120025DD0D /* Resources */, + 4F9EEBE82D78898B00E0B72D /* Copy Files */, + 4F9EEBF82D78963D00E0B72D /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + 4F6E8FC42D77C0120025DD0D /* Pandios */, + ); + name = Pandios; + packageProductDependencies = ( + ); + productName = Pandios; + productReference = 4F6E8FC22D77C0120025DD0D /* Pandios.app */; + productType = "com.apple.product-type.application"; + }; + 4F6E8FD12D77C0140025DD0D /* PandiosTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4F6E8FE92D77C0140025DD0D /* Build configuration list for PBXNativeTarget "PandiosTests" */; + buildPhases = ( + 4F6E8FCE2D77C0140025DD0D /* Sources */, + 4F6E8FCF2D77C0140025DD0D /* Frameworks */, + 4F6E8FD02D77C0140025DD0D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 4F6E8FD42D77C0140025DD0D /* PBXTargetDependency */, + ); + name = PandiosTests; + packageProductDependencies = ( + ); + productName = PandiosTests; + productReference = 4F6E8FD22D77C0140025DD0D /* PandiosTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 4F6E8FDB2D77C0140025DD0D /* PandiosUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4F6E8FEC2D77C0140025DD0D /* Build configuration list for PBXNativeTarget "PandiosUITests" */; + buildPhases = ( + 4F6E8FD82D77C0140025DD0D /* Sources */, + 4F6E8FD92D77C0140025DD0D /* Frameworks */, + 4F6E8FDA2D77C0140025DD0D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 4F6E8FDE2D77C0140025DD0D /* PBXTargetDependency */, + ); + name = PandiosUITests; + packageProductDependencies = ( + ); + productName = PandiosUITests; + productReference = 4F6E8FDC2D77C0140025DD0D /* PandiosUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 4F6E8FBA2D77C0120025DD0D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1620; + LastUpgradeCheck = 1620; + TargetAttributes = { + 4F6E8FC12D77C0120025DD0D = { + CreatedOnToolsVersion = 16.2; + }; + 4F6E8FD12D77C0140025DD0D = { + CreatedOnToolsVersion = 16.2; + TestTargetID = 4F6E8FC12D77C0120025DD0D; + }; + 4F6E8FDB2D77C0140025DD0D = { + CreatedOnToolsVersion = 16.2; + TestTargetID = 4F6E8FC12D77C0120025DD0D; + }; + }; + }; + buildConfigurationList = 4F6E8FBD2D77C0120025DD0D /* Build configuration list for PBXProject "Pandios" */; + compatibilityVersion = "Xcode 16.0.Superseded.1"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 4F6E8FB92D77C0120025DD0D; + minimizedProjectReferenceProxies = 1; + productRefGroup = 4F6E8FC32D77C0120025DD0D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4F6E8FC12D77C0120025DD0D /* Pandios */, + 4F6E8FD12D77C0140025DD0D /* PandiosTests */, + 4F6E8FDB2D77C0140025DD0D /* PandiosUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 4F6E8FC02D77C0120025DD0D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4F6E8FD02D77C0140025DD0D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4F6E8FDA2D77C0140025DD0D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 4F6E8FBE2D77C0120025DD0D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4F6E8FCE2D77C0140025DD0D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4F6E8FD82D77C0140025DD0D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 4F6E8FD42D77C0140025DD0D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4F6E8FC12D77C0120025DD0D /* Pandios */; + targetProxy = 4F6E8FD32D77C0140025DD0D /* PBXContainerItemProxy */; + }; + 4F6E8FDE2D77C0140025DD0D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4F6E8FC12D77C0120025DD0D /* Pandios */; + targetProxy = 4F6E8FDD2D77C0140025DD0D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 4F6E8FE42D77C0140025DD0D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 4F6E8FE52D77C0140025DD0D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 4F6E8FE72D77C0140025DD0D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"Pandios/Preview Content\""; + DEVELOPMENT_TEAM = 877A43U8RR; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = Alber.Pandios; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Alber"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 4F6E8FE82D77C0140025DD0D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"Pandios/Preview Content\""; + DEVELOPMENT_TEAM = 877A43U8RR; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = Alber.Pandios; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INCLUDE_PATHS = "$(PROJECT_DIR)/Alber"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 4F6E8FEA2D77C0140025DD0D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = Alber.PandiosTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Pandios.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Pandios"; + }; + name = Debug; + }; + 4F6E8FEB2D77C0140025DD0D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = Alber.PandiosTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Pandios.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Pandios"; + }; + name = Release; + }; + 4F6E8FED2D77C0140025DD0D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = Alber.PandiosUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Pandios; + }; + name = Debug; + }; + 4F6E8FEE2D77C0140025DD0D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = Alber.PandiosUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Pandios; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4F6E8FBD2D77C0120025DD0D /* Build configuration list for PBXProject "Pandios" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4F6E8FE42D77C0140025DD0D /* Debug */, + 4F6E8FE52D77C0140025DD0D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4F6E8FE62D77C0140025DD0D /* Build configuration list for PBXNativeTarget "Pandios" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4F6E8FE72D77C0140025DD0D /* Debug */, + 4F6E8FE82D77C0140025DD0D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4F6E8FE92D77C0140025DD0D /* Build configuration list for PBXNativeTarget "PandiosTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4F6E8FEA2D77C0140025DD0D /* Debug */, + 4F6E8FEB2D77C0140025DD0D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4F6E8FEC2D77C0140025DD0D /* Build configuration list for PBXNativeTarget "PandiosUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4F6E8FED2D77C0140025DD0D /* Debug */, + 4F6E8FEE2D77C0140025DD0D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 4F6E8FBA2D77C0120025DD0D /* Project object */; +} diff --git a/src/pandios/Pandios.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/src/pandios/Pandios.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/src/pandios/Pandios.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/src/pandios/Pandios.xcodeproj/project.xcworkspace/xcuserdata/giorgos.xcuserdatad/UserInterfaceState.xcuserstate b/src/pandios/Pandios.xcodeproj/project.xcworkspace/xcuserdata/giorgos.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..38cf274735b604b141f2046cb9c061fd00c2f5b8 GIT binary patch literal 763693 zcmXWRWmp;tqX1wKqy-dEP`W`>8dPwjO92tY77?Vx?X0`IySux)yU%(%>+bH3@BX+y z-{*OQ9b03ayNJb?0YE?s00aO7QUMSE6o9B=cMEsw9P7|l&2H+{9F6^-yzDL=I##he z1mof6E}b&~z+np-u^4BCBiu6_(*1wB0DuADzKSkQUBUx^>(dpl0Z0G}kOd$DNPs** zKA->~21o!>fD9l9C;&=;3ZMo!0WN?WP!8|_Dga)94^Rp41G)mb0lEWv0D1y?0eS=a z0Qv&@0r~?500sgE0VV(@0ww__1Ev6`0%ic_0~P@m1C|4}0=5CR19kv*0(Joo01g6< z15N-=0!{8dw9Y1vUbkfgxZEFak^fI{~`_djR_a z`vIo_rvj$|rvqmIX98ydX9MQ|=K|*e=K~i27XlXn7Xz07mjagoHvu;Tw*a>Sw*hwn zcLNUs4*`z>j|0yDuK}+EZvbxsZvh_w9|9i%9|KciZCTNMUo;-QKqO;3@OGGQ;IpolHy1yP4T2ur1(>+ zQbH-=l$Ml8N;D;w(jlc|N|%(bDT7mnqzp|NmNGnLM9R37@hOv2rlibDnU}I8WogR# zlnp5xQ#Pe+PT8GuAmvEPiIg)b|E63>xtMY(8X5kvxIgXkazhzk;fBp@kB29kpmpmw14ARR~#a)MkSH>e!s z0X2XcK><(`CbqDnT^#t_-^#=6;^#%0<^#=_A4Fe4ajR8#qO$W^Y%>>N?EdebB ztpu$FtpjZWZ3gWE?FJnL9R(c&odTT&T?SnNT?gF;-2puWJq3LQeFJ?5{Q&(0{Q~_4 z{Q<+ka4-Ul1mnOgun;T;%fSk8Ay^C6f%RZ3*aj{Imw}z&7H|X{1;@Z~a01*4PJ-LO z9l#yIUBJD;eZYOeL&3wq!@=Xh6TlO}lfZMpbHVe#^TCV3%fPF^tHEo)Tfkev+rZnw zyTM1mr@`mIm%x|7*TC1ox50P7cft3-ufVUtZ@_QC@4)ZDAHZM0zrer2e^Ozo@Ki)9 zG8L7IO{J$YQkki&RCX#Sm76L|%}bq;Iy-e<>cZ3|smoJWrLIlgkh(c_Tk6i#J*oRs z52YSWJ&}4k^=#^e)XS;=rQS%roq8|zVd|6A=c%t!-==;@{hazO^=IlI2oM5>Kp_Z7 z8Uzc$K{6pE2pK|yFd-ZWACe2nhe#lDhze2!(L&lo3=lKK1}TNOARdShQU$4nG(egl zAxH!gha@2#A)O)JAUz>{ApIeOAVVP|AfqAUAQK@|Ak!hUAafxLAd4Z(AS)qjAnPHU zAX_0jAiE*^AO|5wAjcu6Apb(nL#{w>LT*8BL!LlhLq0;jLViO2LP1a{6b7Y38Biva z1!Y4yP%e}Qy<;8DS=v8D@c5VWqGNm>1@QRl*uzjj#YL3X8$wur9E!ux_yKu->r#umP}vu#vD) zu+gybu*tAFu*I;Iu(hy_u&uD2unVw@uuHJZuq&{uu>WA!VAo+cU^iiRVNYOBVQ*pY zVDDkyVL#wtcq$wMhr*F?3_J@?gp=SDI2A60=fXvBHM|gB1TThb;BI(1+yk$Gd*MEK zCEO3Mf;Ye$;URb%yaT)=ycfJTybpX1d@g(*d_H^ud?9=hd@+0pd?|bxd^vmtd?kDp zd^>zMd=LBp{2=@&{22Tc{51R={55%CYA6QUcUAEG~E0AdJY3}OOe24W6k31TT?8DbS;6Ji@;AL0<=6yhx67UCY_ zKH@Rr3E~CfCE_jO9pV$>GvX)W7ZQMkA>l{_5`!clGm+UyI+B58BKb%GG7l+3%8?3W zF|r-fh%_P1$Wo*m=|ff`{m6P`6EcWwLAD}0BL6`SMh-y^MGiv_M~*;_M2BK>k7g zMS)OY6buDNF;Gkt3&lopP+Sxb#YYKHLR2oQ0Hs8gpxU9@qpT4Mq(?4Mhz@4M&YYjYN$?jYf?}O+(E?%||UjtwOCvtwF6tZA5KF z?M3ZF?MEF)oj~0~-A6q@Jw!c1Jw`o2Jw-i3Jx9Gjy+M6O{YL#k{Y`_XA<~d(s5ERE zK8>74Nu#E5(|Bp^(%Pr#()4MDG-H}6&75XQv!>b7%8<}BZ<;TyKCL0GF)fxBPfMh= zrgco~lGZ1!Z(6^!VQItD=BF)4TbQ;eZE@O?w54gw(w3*KNL!hAVp0vGb`_fLN zolHBGb~^1`+NHFcX}8jDr#()4lJ+Oxn=GzHB; zbJ0As1T96&&~mgItwC$iC1^9+f^I|y&`szdx)~iphtVzQ2s(<6p_Aw?=sxJa=zi!C z=#l7A=+Wr$=*j5W=sD=Q=%wgo=zZw@=mY43=tJnk=p*Q(=ws;P=o9EO=u7CE=v(O9 z=%?ss=;!Dc=r`yO=pX2x=sy?;28y9!=okiuiD6;b7!HPu;bHg~0VWS4$7nEGObNz} zv0$ti52ga+#rQDQn0ibY(}L-T>5mzJ8HgE#8H^c%8HyQ(8IBo&8H1UOnT?r)nTuJ9 zS%%qw*@)SM*^Jqa*^N1jIfA)`xsADlxr@1nxsQ2(d5C$0d5n32d4YM4`HuO4`H4-% zLa_@S*eYxtHh>Lbqu4>% zVc6l=(bzHA3D}9)sn}`QS=iaw`Pc>6CD^6dmDp9-b=dXT&Dbs29oU`N{n!K8W7y-^ zbJ+9P3)tJ(d)NoqXV~Z1x7c^sZ`kkHAL)>ERC-!EE*+mvPN$?((}n5cbV<4@U7g-O zU6-y;ccy#Oed)F7b?Kq>aC%F6r}Q4_J=6QA4@e)8J~Dk&`n2>p>2uQ;r!PrglfE{6 zUHY!{1L+6TkEfqVKc9Xf{bKr^^hfEB(_f~)O8=DpIsHpUN(L+go`K20W)L$-8QB@! z3{gg2hAcy#p~=u@lw{a5+!@{sUq)?4T}CjYIU|&@FXK?g;f&)MCo;}t{F`wh<6_3u zjQ=ujX57lSmvKMiamJI37a1=z-e$bZ_>}QE<9o)Bj6WHFaUdKR2gAW}X*e`41Bb(9 z;fOdgj)G(0m^dzuhs(u@aAKSUr@$$3MYv*IJ6wC55of~LaCV#%=fYLsytpb{HLf1l zfD7W9aS>b;*NRKx{=s#^b;EVX^~UwV4Zsb=4aE(^jlzw_jmJ&EO~FmY&Bo2aEy69v zZN_cEZN+WFZO84v?ZoZH?ZX|z9mk!(oyT3kUBo@YJ;pu3J;go4J;%Mky~Mr6eZl>~ z{lx?D2s{#x!l&WW@dP{tPsMZbJUkyS#!K*0yb*80oADOB6>r1a@eaHTUy1kQ8}R{r z6Fz}&#V7G?_)hq4_uUr`0@Bj_-Xj*_}Tb{_(k{?_?7sb_+9wj_&xZ& z_DmNUzfRg+blRhJdY3TMT#x@Gmw8kjXa zYed$JteIJ}vSw$^$(oxrFKbcO;;fZftFks_ZO+<~bu8<6)`_f>S*Nm2XPwFVH|s*y zwXAzt_p=^ky~=u>^(O0W*2k=`S$~NDB8&(pB8X^W29Zdl5^2N&qL?TlN{KR}oTwlc z5{roKi8`W_F^J>_O~F97r5Q984Tb97h~aoIspH zoIzYbTu59>Tt-|)Tut0a+)mslOB_=WhD z_>K6T_=EV9_>1_P1SG*oSW-GEgG44#NK_Jy#3J!X1tc*^O)4Z6kxEEDd|CxNLkjA)Ay<&t_x`vW3~X*@|pswklhlt;uemZOyi2+p|5{ z71_1fb=mdV9kM%S|C8M*yK{Dz?5^3}vU_C@%pR0IDtmPHnCxlU)3aw}&&-~iy)b)a z_NwgF*_*SsWbet|o4qgleD;Oxi`kd5FK1uLzMB1C_RZ`E*)OtRX1~h*l>IsTOAa6h zn3IwN%7Nw}b8tEM9C8jNhngeKk>p5oWI6I2MUFB@l~bIf&oSgUa!PZ`a{M_}In_Be zISo0%oOn(mr!}WbPS>2CIm2>>=Zwf1nKLS9bk3NZu{q;%#^+4PnUOOuXGzY|oUJ+A za<=E}$k~~*D`$7k{+t6j$8wJ6oXa_%b0Ozp&ZC^iIZtw)<~+-Jp7SE-P0r_>-#LGB z{*vKj1Q|(2k+EbvnM|gTIb<%GN6sY|ki}#rSw+^8OUO>Li|i(slRe}LvX>kphsiDE z2suiQk>lh9xs{wGw~;%LJCgq)cPIBC4&Wrfi{XrEH^Y zr|hQep&X$cr5vN2rJSRjr#zrMq&%WLraYlMr97iNr@W?oqI{d(`{X2h@kuN7QH3x74rHZ`AKJ5DiRAr9o&28k&|#%c2o!bQ*)kq;Y9N zS}sjOQ_<8kE6ql;(;T!?S{cnr^Ux}2^|S_BBP~FS(qgnYtq-j)tskvFZ2)Z`Z4hlR zZ8&WlZ5nMlZ3b-tZ6R$nZ4GTLZ5?eBZ5wSLZ9nY*?F8*4?G)`6?KbTW?Jn&e?LO@R z?IGg&@<^&I*m@J^XUS*kglO?=_T}b^!9WeT~9aA zEp#WnlJ2Kh(F61*dV=0cPtx1yo#@@@{pkJagXzQRW9gIWQ|L?ROX(W#s$WIjN6Pmj5mz8jCYLpj1P>Dj8BXojGs&p6UWNa>cZ;E>c;BM>cQ&C>c#5E>dzX=8p|5T8qZqDTEtq+ zTEbe&TE<$=TESYw+RWO`+QZt*I?6i6I?uYmy2!f3`j2&!^^o<5^^En3^^Wz0^^5hJ zoyJD9F>EY5ot?qPv9s7jHl592Guc9RE?dMdVYg$qXY1H{wt;PAo7gtCn_b1OX4kMo z>@d599bqTf9oXI3J=g=-1KESvqu8U_W7zZ9^Vtj73)zd8tvxc*lvyQW#vw^dPvzv36bA)r0^DpNt z=Njia=LY8{=Pu_V=OyPA=M(2M=L;9cg>w;HBp1a^bc&Ec}RY%YhJ$Ia)e zxrN*!ZZWqV*T8jfOSxrSAGeb0=f=2kZi3s&O>*0~9k?C2UAVougSkVvL%CzQ~+6drbMQ)e zWjrU(%d6wn^BQ;^dH?V_@jCOm@VfH4@w)SR^9J!o@kaB;@TTyl^5*jv@D}nG@s{yc z@iy@`^S1Mj@Q(71@s9IO@J{kh@lNy3@c!kU@hO@J0) z1SCPWAV)wJ&;@LPNRTH`2$X^nK|4Wvfk#jw@Ctl_N`YTcC8!qE3qpccK~m5r=ppDS z=q2ba=r0&77%dnhm?D@em?@YgSSna1ST0y0SSeT~SS?s1*d*92*eTd0I3+kOI3xI1 za8__ma9(gza7%Doa7S=ga8Gbw@IdfT@J8@S@I&xZh!moPX+pFRBg6{Rg%lxGNE6b9 z3?Wm<60(IHAy+68%7qG{QfL+0gm$4rSSl=!Vkia!cW3)!oRuDTv#qVH$68amz+zPgot3*FcVX`G+!eVya(CwL%H5s2CwFh|zT88(hjUNnp31$LdnxyF z?vvc7xzBQ+=f22&nfogDb?*DzZz6yQC`u6_L`V@zlqt#*5k({sMZ^#ZL_$%ns6ZqW z$wft?Vv$ay7kNY#BCp6NsucM}RiYMAL=+XpL~&6<)GA7f+C&{h9Yz0$dWw3928jlX zhKQz#ri*5XW{PHsW{c*C=86`IR){u;Hi|Zhc8PY2j*5h1e=DaO=Tl2Q%?aDitcQWr(-s!wcd6)C<zb3ynKbhZ_-yy$a{y+Jh@;m2u$?uWhKYw`si2RZH6Z0qK&&i*gKQDiN{^I=Q z`RnsH08judNGSjnfC~@>$O2pezJO4`E8rIh3WNo@1)_qyg8Tw$L1BTeKwn@e za1@jlR2KLPstT$L>I<3*Vg>Pnwu0UT0}F;1j3}5|spCLSf8B%UmuBAy|hBc3Z>EM6&ICEg|8E#4#EE8ZvGFFqhX zB0efUDLyB@BEBkqB7Q1m1$wwwX)kGSX&-4{X+LRy>0s#)=@{u)={V^$>2&D~ z=_=`J=^E);={o6p=?3XW=~n3;=@IEs=`rb9={f0j=?&>k=`HC!=_BbY>1*j5=@;o& z={FfdhLoXXX)?47Bg4wlWds>n#+GqpT$xxVkx6ATnMzhHGsujxQdya-T;`Ki%Iai6 zS+lIOtc$FxtedR6tcR?pY?y4gY=ms2Y?N%YY>aHIY@BSoY=Uf#Y_4pcY`$!PY=vy4 zY?W+}Y_DveY`^S)?4azB?6B;(?5ymZ?7Zxn?7HlR?2+uT?1}8D?4|6j?5pgX93ThE z;c|o=DW}M(a+;hjXULgymYgl;%M0WxxmsQ*H^_~0liVz~%boH{xnJHW56GkPm^?1; zBkwEkC+{yGARj0nBp)mvE*~eKCZ8^!Azvh4EMFpDDqksIE8i;LCf_dKFFznZAwMZU zCBG%VEx#kbE59edFMl9^D1Rz{BmW}*D*vWPQGgU+MXCa>NK+6LnTjk0O+i<%6%vJ1 zAydc|3WZXkQm7S$iXug^La(qYoC=qsQ4vryDT0b-MMx1=#1wHwN5wyio{CtBMsTy;WqQgupoT6I)KoQ1El>;9xoVMGtd^@aYOUI&Hmfaam)fl^S2wFe z>ae;+9Z^TsF?C$srtYfltL~@nuO6-*p`N6kte&Ets-CHyt6r*Jre3aIt=^{IuHK>E zsotgDt=^;Ft3IecuKrhjR((f(SA9=?U;RM+Q2j{#O#NK_TK!S|UHzjFQHU%=6{Z!U z3o(V*LVO{ikX6Vo

rXd4>E!aiOG8T4*dZ6`Bhzh1Nn_p}o*i=qju%Y$$9j3>3x- z6NRmX$-;jMyB78>>{mFfaCqT}!U=^F3nvvWDO_5(tZ;eZio%tJs|r^at}onHxUX=3 z;eo;vg(nLy6<#j9Qh2rSM&X^pCxuT7-xj_rd|w1A0vDwgL5iS7up)R7q6l3?D54Zm zi)cl>B7TvyNLC~-QWO;yX^Tun<|1d2tH@mxENU(a6@`mhiXuhPqF7O~s7q0wqP|7_ ziiQ;pFB(xasc3T1l%lCcGmGXHEiGDBw617<(T1W!MTd)y6df%(R&>1RMA6Bje~T^` zT`9Uq7JVxET=b>rN70{RNHMe+S&S*h788rf#gt-3F|$}%tSVL) z7Zw*47Z+=awZ$dHx?*Fosn}d>FLoD~7ki2;i{r(~;*Q1t6n84_R@|q!Z}Gt5xy1{M z7ZoonUS7Pqcunz!;*G^yi?aDpCyP%NpDjLDe5v?y@wMVx#rKLI z6+bI}Rs62_Q}MUrUmAc0tU+rsG&oI`hNvNHC>oB2s}X7PG+IrGrk$p}MyJth3>vG( zrm<_h8lR?K)1Yb8{G;il>8$CZ>8k0b>8|Oa>7yB}8L1hinWCAhnWmYpnXQ?xS*}^3 zS*h8m*`(R5IjT9PIj%XOIjK3NIjuRPIj{Lob6ayq^Gx$x^Fs4d^H%dw^HcLn^IMy$ zg=nE#k~UkLqa|x8TB??&rEA&RT&+Ya)oQd_ZHcy>)}Xa$U0S!+tF6}7Xlu32+K@J` zO=x>-`)K=W`)T`Y2WSUshiZpu$7siDr)sBZr)yVgS7}#k*J#&j*J;;lH)ywLcWV!7 z4{6V6|J9z=p3`2^{-?dGy{EmeeV~1!eWQJ=eW(4R{aOMoftA2Z5GBYGR7qM1t^{8~ zD9J3Lme5M*CHxXWiLgXdqAe*YX;;#|L|39OF_c(JoF(28UrA$0prolJSkh7wFX>d$ zxui=;*OI;^{Yv_mOe~pHGPz_*$<&f*CDTi0l*}nvT(YEORmtj-ttHz^wwLTE*;8_$ zdL)LC_ba7om*Fo1&*G1P=*HhO^ z*H719H&{1BH$pd3H&!=JH%T{HH(fVFH%B*Dw@|l8w@kNOw_3MGw?Vg2w^g@Iw@bHM zw_kTacSLtocT#sscUE^!cS(0ycTIO)cUyNy_dxeh_f+>x_e%F#_g?ow_eJ+r_fz*v z56}bksd|VWp-1X5daNF=C+JD~Y&}&^)3fw!Jzp=-=jrqHQoT&C(yR3vy;iT&>-A>6 zMeop;>fQQsy-#1MuhG})8}$KwNFUb6^l^QgzJtEAzKgzxzNfygzMp=Oez1PHeuRFE zeyo0?ev*Ege!70PevW>DexZJ;ewluiezktReuI9Ceye_`ewTiqe!u>({)qmB{-pk2 z{aO7*{U!Z>`fK`I`rG>Z`Um2m{)H zG2je%1JOV-Pz+Q9)4($D419ygkY|t>qz0uyWhgdi4DAg%gUMhv*bNSY%iuP64L(D) zp~lc)Xf!k%LWZazW=I;^44n*}4c!er41ElJ4Fe5>48sh=4WkWX3=<3!4O0!%46_Wg z4f72P3`-144J!?+4C@T*4Vw*H3_A=v4SNmy42KMd4aW^93}+1g8ZHMx)7SGun+#qsv%f^ct&-)y8^bgE44qHb#t5 zW2-S~{KweI*v;78*xT60IKVj2IMg`IILbKMINmtHIK?>CIMX=GIL|oWxY)SFxWc&7 zxYoGNxXHNLxZSwJxW~BHc+hyrc+7a*c-nZzc;0xyc*S_tc*A(pc-MH(_{jL!_}uuy z_{R9w_|f>u_|5p;_}lo$lwtyzpeC3JWlA%pn=(w9rYuvAiEN^q7$%O1YZ97rO$8>g zNp4b@3Qa|(5>q>q!DKX9O*T`R$!YSKDolP;m8s5DZ)!3HO)aK~DPd|gbu|5B>T2p{ z>SgL}>Teog8e$r18fhA38fO}Bnrxb4nqiu0nroV8T4Y*mT5eilT4P#k+GyHj+Gg5r z+HKlnI$%0zI%+y*I%PU-I%hg>x@@{)x^B8*x?{R)dT4rNdS-fVdTn}R`e6EK`fB=S z`epiU2AWgM5Hr+_G^5N|bGn&e&NOG6bIdd|-OM&~%mTB}oNq2L%gl1K+FWSXnoG=j zv%zdJTg|2BGIP1vW3Dv&&9&w_bHLnW4x3xdadX1l!Q9c@#oX20)7;D4&)nZU*gV8M z!aUME);!KU$voLS-8{oQ$2`}((7edJ%)H#Z+PucR!MxGD)x6ET%e>pX-+aJ)#C+6z z(tOH%)_l%<$$Z&-&3xT_+kD6T!2Hns)cnl+%KX~=-u%J*#r)O$)BMWEW0gxEPE~c zEc-17EC(%zEQc*eEGI1IEdN=qS*}~|TOL?mSzcS-Sl(JbTE1HTS^-v~m1NDf=2*#A zij``mS?N}Wm1*T#^Q;Q1(yFqyv$nU|tqyCcwai*>^;zq!4c2bf?$#dGp4ML0-qt?W zzSe%${?-B3A=c5>$<`^>sn)sHdDa!ymDW|()zEIZGhYnR#O_ELM9-D!8(-S%?3$6jIg+I{v)dyT!x z9<#^o343RI7kfW@fBOLYK>JYpNc%+lB>O7+YWo`dTKhWtdiw_ZM*AlFX8RWV4*P!l zar+7TN&6-HW&0KTRr?M59s3jeQ~NXfbNdVX2m40{(t&cMInWM_1M5h4WH@jRyo2B% zIp_|)L*NiPH=}$n^rKr-hQcfwilvm0x6_g4~b4x{~d8PTK1*NjmqEdaS zq10IFEOnK-OUp}rrPZZPrNPp8X`*y+>5$T)rNc^xmyReMSvsn8bm^GVv85ABXOu1| zU0AxPbXDo<(ygW2O1GEpDBV+fp!7uP$9f-3r7ucfmcA|h zQu?R#ZyBHrQHCr-m8F%Xml4V+Wz;fm8LzBeS^F|wnZC?WW-K$6naeC?)-qdJS(&%2 zuB^VSp)6V!D~p#U$~u&FF6&*^r))^s(6YH@^UCIzEht-9wy11z*^;uQWy{Kzm#r?_ zRJN;ZciEn@V`az7PL!Q2`?u^u+4Zs;We>_8mi;XIRrb5=PuX85zzKAwI6+RZGt~)q zVx2@M$(ikBJ2_6SljqEJ7C2Q-wX?lb=d5m28tD=Yq?cC$s>)hwu?>yi<=sfB?U`<^==|jT<^1g;xH4T?E~1O%%68?r$S#VD>Y}+=E}={6lDXur z5?4D{dza2-a@kzvE|06mRqN{P>f-9^>gMY1>f!3?>gDR~>f`F`8t59~n&6t~n&g`0 zn(bQZTIO2rTH#vb+ThyZ+UdIBy6C#(y6n2*y6XDRbiEpbcTGPm5Va4X#^x7uCk*1C=EQg@l#>8^D9-Bs?O zyV)IbhutxE(%seF%{|UN-aWxR(LKpM**(QQ)jiEU-95uS$GzCS+P%iT*1gre&3(Xq z(0#~#*nQl6+I`7=+5O7>+Wp4;*8R@?-u=P-(f!H&+5N@+qa0WcFGrLk%W>uSa%wrP zoL(jRzAFZeEEd(73C|-SCy|WUsJxed|mna@(tx1%Quy8E8kmwwES54@$w7h7t1e| zUoO8^eyjXZ`Q!4}#+r#k`c*GuwN9s{} ziadIc!Q=3hdP1JCr^OTTL_IN2+>`LMdXkcI&uPyY&%d6to{OIAp8K8$o`;^7o>!hPp0A#7 zp6{OD6~GF31)_pk!Kz?aa4NVJyb6AWph8%YTOq0tSEwr5RkW|rRX8e2E6OUI6`qR9 ziiV2Dia z6&owIR_v|VS8=T3c*Wg{dlmO99#lN6cvSJY;z`BRif0wiD_&Q8s`yp$yW)=*;)QzC zy%}Dd7w;u{$zHaX9R@jAR7Z-v+Et@GA<8@w&vi1#0F zCvRtO7jF-5AMX(FQ14vtJnww(0`EfaBJX1F67N#)GVgNlYVRiRF7Iyd9`7;laqkK5 zN$Pi1ChRwc2LRGD3wQ%SC*R8lKxmGnw>Wp1UcQeLU3)K->MS}Sdp_DV;k ztFof9wz96WOJ&!}Zk63DdsOzU>{Z#jvQK5-%6^rDDo0jMtejLixpH>poXTaD%PUt@ zuB=>Jxv_F*<*v$$m6s|nS6->STKQk)waV+2H!5#d-m1J;`LyzF<-5xFmES9W_`&{E zKg199BmEeEmY?Vs`z3y|Iz=+|Jnb=|Dy_61+PL>A*%>gnN?X;#42(Xy^3EY zsFGAktL#;ds?w^mDrc3e%3W1n<*BNu@>W$j|o>Q&XRYFO3q zs_|75s#a93tXfsIx@t|;+NyO`>#H_YZLHcV?%St5;PYsyQ- zv$wa{8v zEvgnuN_c3qjqNPtlHVNb86?-&a0hYyP$Sq?V{RcwQFm))^4laUVE_iQ0?K` zBef@L&(vP7y;6I-_D=1W+OM_WYQNY1sQp>{tM+&8pW455fI4s;vJO{=uOrk^>Zobjb`+Pb>B`nra?#=1aVs4h|0xvooH*SfxS z{pv>4jjS70H@a?o-Q>F2b#v;r)NQTXR=2%wN8Qf4U3I(b_SEgI+gEp}?quDCx{Gy} z>TcHEs(VuRwC-8m^Sak{@9VzT{ix5V$JOKO3H6!vS@pzvQhj!PPCdDvUeBv9s2A5u z>Wk|&_1gN9dVRgQ-dXRe_t#g|cdY-XzEgeY`Y!cd>$}x=ukTUcv%Xh-zxtu|W9!G& zkFTFuKdXLr{hay*^-Jp4)UT~ySHG=(d;Pik^Ys_%FV&N;+qkrGS>y7?6^$z!S2eC~T+_I=ab4s3 z#?6hp8V@xdZamU>w((r!`Nj*4R~oN3-fw)+_^|O&KObOC+99&iMj1ED}T&=QCQqJdZ-9!LaQ1IfTY zfgXVYfq{WRfl-0cfvJIMf$4!6fjNN%ffa$3frEiVfy03#fun(Af#ZP_fs=t#fzyF= zfvbT#fxCfwffs?7fmeaof%k#Wf!~2YO^_yN6RnBf#AsqRv6|RToF;A)uZiCzXv%An zH))!*O(jj{CQDO!lc%Yo$=g)bRM!-03ODs_>etl2X+YD!ra?`En}#$EZ5q}zylHgP zq^4O-vzz8LEo)ldw4!Nc)7qwuO*@-*H63a?+;p?)R@3dKJ56_+?ls+SdeHQ+=~2_; zrsqxXn!YuCZ~75T34(%YL39uk#0K#}VvrtW1Pg;j!Q!AMs123`+XdSPbwPd55VQoH z!OEaNSQQKgn}eZXI2a2igI$B&g8hR1gVTdEf-{4&g0q8jf^&oOg7bq5f(wI7gKL6Y zf?I>zf(L>JgNK5LgU5rXgO`GrgI9vLgLi^of?tE*g5QHbf`*f`6L<&ERHa zGp-rmOlYPwQ=4hcf@WcJZnLOa+$?X_G;5oE&6Umm=BnoE=9=c(=DOzk=7#3R=H}*j zbEoFc&0U)NH1};D-aMjtWb>%zam|yOXEo1m-rT&Ud292w=IzZpns+wuYTn(vr+IJl z!R8aq=bJAyUu?eBe7pHh^WEl$%}<-(Hot5B*8Dw`9?A&eLii9Nlo`qj5ksUX+qkNE@TRog`6Q*$Q>#VRflRqokE>MT|!+$-9p_%JwiQ0y+XZ1 zeL@35!$TuN6G9V1lR|Ssb3^k&^Fxb6%R}o!8$vrmJ3|*j7ekjqmqS-VS401Wu7$3L zZiH@z?uMR(-h|$U-i3aIeujR9eushK)NooD9nK7Ag$u&sup}%E%fj-oBCHIn!s>8g zSQ|EmP2sYzGwcfc!&Tv6xH%jOhr_XOGTb%XEj%tfK0F~jF+3?eIXopiH9RdmJv<}4 zAiOZVD7-4XI=nT!ExbLvBfKYkAbcWxGJHS$Ap9`=DEv75B>Xh|Ec`tDBK$J^HvA?0 zC;Ybs(1K_|wxC+lTGCqxEtD2&3%7;W(ypa_i>^iAVrVh8m|Dy&mKJM^t);BR+fvt3 z-_p?1(h_O;r=?R%=aw!lJzDy-3~3qKGPh-3%lwuFEel%~wJdH~(z3K=S%xG4W7$rrsqd8G>loF*zX;D^G7?nn4QF*i^ z+Ai8Ys*9SUwrF|O6RnBXMmtBlM7u`2MY~6PM0-YiMSDm4MEgbuMn^;^L?=ckMdw84 zM(0K6M;AwzN7qL;M0Z4YMlVD!MlVG#N3TS$M*oXmi(Zf3h~A9ejXsIKiN1}#i~flI zjQ)!Ljsat-v9uUEhKXTg#26_iiAiI!m^`M4DPyXbI#w7fiWSG&#mq5h%oTITYGSpq zx>$XzDHe_;V{Nf+vF@?)u?ew>u}QJXu_>{sv1zgCu^F+MvAMA&u{E)^v30R+vF)*g zu|u)Lu_Lh)u`{vDu`99Hu{W`|v3Ifeu@AA2u}`tju`jW&v7hmjI3kXWqvH5DAx?|a z(zq<{h?mC8;?B4$?v9toJ@JaTH|~p9#{=jD#PP(5#L2{|#OcJD#J`ENiF1idi5rOriHC_tiC2l&iLZ%oiSLOYi9f9= zt%z1+E31{=%4y}c@>=<=f>vQ`ZmXy@uT|2jZf)PHYt^^fTOF;w*2-3YYgKDqYoImS z8fzWcI;eGU>yXx=t;1S}w~lBX**dCqbnE2SDXmjm=eEvkUD3L-bye%?*7dEMTX(na zX}#QfrS)p-f34SAueaW4z1e!J^>*u>)+en`Tc5RlX#Lpwsr7T~_txLZ)FdPcO=6PR zBtI!g3X{1>Q8F)?pDaj>mS(U6yhLYiAGTD|KmK>fO zksO&El^mTMlN_5ImmHs*kerg7om`w;l3bcxn_QRNk=&WwmE4`&pFEsAojj9#lzg0g zl6;zcmVBOkk$jnam3*Cill+kU-Ue(-X#=$(+fZ$pZCP!^Hc}g(th*tzTRJw&86f+7`4eY+KZ} zxNS+>(za!7%iC78t!!J>wyte!+upW)ZTs7fx1DIa*mkMya@&=*>utB&9=APd`_uNf z1E2%2LrMow2XKef4v-Ge4zLcW4!90E9mpLh9e5r19RwYO9r8O!I}~;JA9LRUmR8pM zeJ_~aOz(;5z4zXGkER!6lq4obdJ~aL5ky2pKv6+D0wNX!1ku#pluhs1l1=YD*-bW^ z@*S`w*>~If|3BaNeDMk8-gD-hJ9FkYb7tmpr(ow`=VCWww_vwoBeC1CQP}O+Xlx7? zgWZAMjm2Z>*aR#C%f<4r=~xLi11rTUusK*AR*&^zE3tlT6}B3?54#_G0DBO72zwZN z6nh$b8G8kL6?+4F6Z;tZ1p5^G4EqZE2KxyI;X2_u%qaN}_kaIHupVw@9KiSy$w;4b1W;V$E@;I87n$Nhl&5%&}B8tx|U0qzCv zCGHjOciek?LwqBAV|){Q3w&#QXM7j@X#5!bSo}Erc>DzXMEoTDWc(ETRQz20Jp6q8 zO8hGPYJ50;9exu&8Xtql;P>L=@qD}hpMn?SQ}H5v8eWV~$4l@TcsV`~Z@?SzCVUaz zfv>=O@jiSdejol2{yY2${B8Ul{9XJ#{C)fb{6qXB{A2tR{8Rj|_&4~s1c(3=P=w}$ z7KE0BR)n^Mj)b0sFv3K_B*J9E6v9-(G{SVk48lypEW&KUe8Muq8p2w_Izl928zG9Y zhY&~DONb{B2owU9z#w;K||0IbOb%YOei9_2yTLhaDZ@-aENf2 zaFlR@aDi}*Amwe*Aq7oHxf4yHxsuIw-O_X(ZtkNNq{&NbN}-NF7O?NS#StNL@+YNMWP_q!FZ%q*0_vq{*bYqoJtmv)5v0SI$1)_AWO-aWEojbR+2U30iGFqfVmEqRysn zq;8^arf#8brAAV>QKP8asnOIJ>MkmlN~O}MbSj(5p{7yA)O4zZDx+poHB>FNg6gIE zsFhSdwTfCz-ACO|JwQE3{g!%?dXajGdYO8IdXsvKdYgKm`k4Bf`U~{~^&_nVts|`y ztuw6)tt+h?tvjs;ttTyv)|WPfHikBqHjXxpHl4PRwurWvwuH8V7Eaql+e{EuW^LX=z59g;qiJ+6CH0+9ld$ z+7;SW+V`{{Xg|`f)9%rp(Vo*@(0-%6qleHN&>PYl(VNj*(L2&R(MQrp(MQwA(8top z(Z|y#&?nL-(I?ZV)92Bb(U;R#(AUw|)3?*3=`nN+J(j+g9#5yxsdNcFgD$0K(q(ix zT|v*HXVaDR9J-orq}%C5bO*hH?xp+amGph|L-gnbHf1(rHfOeAwq~|xc4zir_Gb=Y&S1`D z&SK7H&SB1F&STDJE?_QXE@CcYMljbfw=lOdBbl+x-ON4AI3|usVkR<~%p@kCDPU@t zTBeSvXBwDBrip207BDSLE3=4M&h#^@nAOa0nMassndg}2nHQK>m_IUaGw(1zFh4Rs zB|%AW5-JIu6q3{+sbNy1q-IHNlDZ^yP3o4^KWRYHz@$M*!;(fNO-h=aG&^Zd(x#-% zNn4V(CPgM~ONvU`o)n!FlY~i%O~NJ7lITeZNxY=wBz}@0Nt7f>%1%-yX_ItG-XvdA zWs*OsDyceYU()`h14##y4kdk;bRy|w(&eNpNmrA;Pr8mYk(vWwCNu`7AT5fK|*YVI5^1V;yIG$2!3} z$vVY4%{s$6%R0xp#QKSKhjo{AkM)f8ob`_NJL^5`0|FxrkQPWwq(3qM8Hfx*1|vg| zp~x^~I5GkmiHt?2Aajtp$UI~PvJzQ^tVY%%8O5fPGx zh>>(86Ujkzh#oN@g@_$-BOasz@gh~o0pu8R9Jz_yLT)2>kh{n|{T*iG5Z*zMUJ*d5uO*xlG+?1Ah->{;yD>^bbY?0M|@>;>$F>_zOw>?Q0K z?6vHz>`3-D_AYiTdpDcJCbKDQDx1M(u?6fDwwA49>)8gjk!@m|*#&G1+sd}F9c&l7 zie1g#$3DhB&i;;lf_;X4f&C-Bi~K>Bs5M8Oa&N8O<5PnZTLCnZudO+05C(*~*FJY~w_6wsWF6F&qqM2WK}2&!KY? zI1CP#!{elLB%BP6l%wF}aC96!$H%GU_&HUaYR*2+e$D~TLCzu0Va`#`Y0hQN70y-8 zEzWJu9nM|OL(WsqubelWPh5!GiQAdmh1-?ejoY2ugWHoE#_h%J&F#+}#vR8U&z-=X z!JWxn%w57=%3a1?#a+YQ!rjWHaH(7xm(ES#GPsFcCO3)8;v!rgSHzWZ zM!d$nCcLJ+mb^B+F1)V1F}$(7alG-o3A~BCNxaFtDZHt?X}npyg}jx#RlL=_&ActV zt-MHHG;b#l%fs<#JUUOx%jC&;a-M>h#mnX?c{#jXULH@wGxHq0VqOW)$E)P|c~!gv zyl;3Xd8c@nc$az4c+Yt+crSUcc&~ZC@P6gJ;l1Vk#`};QlH5GGMRLpJPRX5?<>g4d`h~zcNYm?U{Z%W>tygPYMa$GVcnVL*X zrYAF#*~!A>)a1-$S#n{rJ-H~^kzAZyl3bcxmh4O}Pj)4HllLbdO+J=F zjsK4SQGgOO6*Lp{5%d-G6Z97h5DXLy5)2j$5eyX!6O0l}6wDON63iAX7Az605v&!g z6Ra0(7Hktl31S7i1snlaz!M}3_yU0-MIaQU3Pgf5L53h(pb=;VI)PPS6O;>F0=K{; zs1)oI91$E9To>FB+!Wjr+!ovs+!fpt+!s6$JQO??{37@u_$c_4(kP{IN}H6nDeY3) zr*ux~p3*O+f6DZf87VVUW~IzdnUgX%WnRkslm#gZQZPmx50r zq!3f6DU1|u3NJ;KqE5+A(WGcobSe52Ly9rQlwwY?rIe<4Q+z3vDc_`gn{p)OXv&F{ zGbvY6uBO~bxta1V<@c2LDIZckrhF1YLRg3rqJ<&C#==&@j>1mD&ca^8-ol~6VZ!0U z5yCOT3Bnn|nZotL4Z@AWO~TE>EyAtBNZ~eNlyJLnhj6cuETjmjLY5E_vV|gHnoulE z7iJ2xgxNxkP%EqudWAk=rO+>|5>^ZM3HJ*R2oDOs6`mAc6kZZu7Tyrv6y6fv7Ty;= z7QPn#BK#oynA#z=V``_=&Z%8eyQX$a?Vj2rwP$KrYTwi$sbf;drjARUkvcPVR_g53 z`KgOjSEq)jZc5#pN=hZCQc|g@v{ZU(LMkIQF_oE`l*&mJrb<&YQ)Q{@)cjOUsy5Y_ zYDq0gElu^N`cluOo=?4ydNK7<>gCicsaI3KPyHeF$JFbo_fnswK2Lp-`g`j8)DNj2 zMJQ22QA<%PQAbfH(MZuK(P+^a(OA(q(Rk4W(L~WC(PYtd(LB+7(Q?rW(Mr*J(FRep zC`N=4?GWu2#fvB+sz@Tr5J^RuBAG}oQi!rd*&?MVN2C+!MFvr!$S!h=JfaGbS5zfB zAUY;GF1jhYCAuxTBf2ZPC%P|sAbKczBzi1*E_x&Slm?~2Y0c7_r?p6Hnbsz)Lt2lt zo@oQp2BytSo0T>@ZBE+Uw0UXs(-x#HOk0$;IBj{_nzSuxThk)bV$*h~?MaJE!=;hZ z64RJz$!Yww{4`CPHcgkNPcx($(@bgRw1PBCnmx^#R+;8ct4jMO?c207X=l^UrJYZ^ zoc2T7t+d-|@6$e{eN6i#hQzQKB}R)w#0|s^#ZASn#ht}n#9hVx#Qnts!~?}c#UsTN z#goLd#Iwa4#hb*N#aqN%#gXD|;wbTUakMx_yi1G~Q^hnfUCb79#A#x&I9)6e%f#7Y zjaVzL5PQWwai!QVt`b*^_lft54~P$nzZIVpUld;wUl#u?zAklddKum>7CQNq<2m4mfk(RM|#inu=Kv^L(<2jk4+z!J|lf*`mFTX>GRVUr>{;A zPv4ZjIh~YFPN$?((`o7S^n`RqdSW^=Jt>`&E=-rEXQs>2^U_u6=JbMeOS(0^D7`e@ zo9;_LmwrC|Li)w@OX-)>ucTj1|33YP^dHl&r{7C|mi|2bMfz{)?<66T29k!7Mv`Wd zR+5gAPLh$5QIgS;F_N*8agy5_SpWs>ER6_O2-jgn20&5~`B7)hLD zuY@e2NYW(|Nrpr!$&|<>a*0BcCCQd3B`S$QQYf)YiX<+HTe4qrKypxWNODB-o#eda zg5Vr%`)0&bjawK(J7-_Mp(wcj6oTr zGDc@C&RCMMG-FxD@{AQ3D>GJQtj-9}h{#x<5t*?wV^>CO20nw3k(j~ENXlSka5DrM zl8lTDONKSWmQk2t&nU`pWE5wVWRzx$`<95cK zj3*gSr46Nxq>ZIbq)nyGq|K!*q%Ebbq@mJw(yr1z(!SDu(qYo!(uvYZ(#g^((ize@ z(k0TR(ika5x-7VcCjg#(`#!CrOx|A*DNV!sxG)CkzSVmEWIwhA$=r$EPWz# zdghJHo0+#VZ)e`gyqozj^F`)wneQ@xmo<_BYUh>}Z{_?@{(eg3!De|fE z2>BZMTKPKpdie(VM)@ZBX89KRR{3^$tQ;>V$cb`>JWD-VOhho zMr4i58kIFVYfRSItch7OvKC}5%vzKco)wX`CTnfh#;mPbJF<3WVY6^qDOtj-)GSd} zT9!B~Jxh|6ktNN_%*x7AXPL6hSp`|8S!G$ytn#diEPvMFtZ%YTW}V8qn{_Yie%6Dm zhgpxZ9%nttdYbht>v`7etlzWI*&*2tvRh=g%{Hq2vM*&{%lH( zG&$NFTTWq)J*OzAG{==wl~bK_Dd%#|m7J?N z-{<_0^JC6WIoEQ2&bgj*JLgf(tDM(4zvO(#`Iy@{w@Gf(+-AA0a@*#1&Fz*uHg{a^ z_}mG(6LTl!PR^Z@J2iJ&?)2Q*xr=gF<*v>R&)t%{H8(PMTW(D5u3TI$K9`=Gkeit+ z%a!LUajc=KhxZF85JRJBrts#>essM@O9sXD28ss^YAss^dXsK%TReMx%s=cas6;_2);Z+0`Ma5JltN1E`N}|e8<*M>jDwSHLQ<+pnDu?P@ z)e+TE)iKp^)px2Bs*|cys?(}7stc+gRJT;ORd-ZRR8LiJRllj;seV^|Qlr())Xmj> z)&11{)dSQ6)q~W7)kD-n)x*@o)uYvu)U(vH)pOL#)XUW?)GO5y>hL_)rdbgUR z=Bjz>WHnzcP^YMc>QuEzouYKOW^?N(Q-_o?@*kE)NUZ>Vpo zZ>evq@2Kyp@2T&rAE+OyAE}?Ie^q}}f69mQ8|OF4Z=2sPzkPm({4V)D@_XhF$RC(L zGk;e8?EE?TbMxor&(B|wzc7DM{^I=Q`D^mGKZEdO}^sr+;K-{=33e=GlX z{`>q7`5*H?X&?=(L21yM5KRM3LrqgnYfWcO7fn}9KTUtl0L?(nP|ZlqM9n14EX{1q zM$IP8X3ZAOR!yX4ne zK24>@uc^{hYxZgOYYu1*YQEK+)LhhD(p=Wu(A?DA(%jbE*F4s|*8HORp!ulnpzWyb zr0uNjqV1~frtPlnq3x*+)ArR4(GJxP(~i@Q*G|yR(9YB@)-KU5)h^Sn(yq~N(QegJ zv{WrkOV=i78QMfGQ=6n^X%Q_?E7Hoea;-wE(Q36itzK)^+O%a_r?yh-*Iv+G)LznF z)?U$G)qb!2LHncjC+#)uP3;5i3++qoEA8*v_qv9Pkn0}moyneZUg?^=e zm43B8TpyudqhG6Er(dt%tdG|3(Z}ic>Zy8~o~}>OC+Ru*RJ}+q)64aCeUaXwFV>gn zOZ8=Xr@mb8(!2FO{Q>M#B;0$;J!9X!E4ao++L12&=G7PzfJcG)hHs}l{Ly^H@_||a5aMW@*SMwAh4Y-Vh3>}%|2>~9=k9B3S59Bdq7 z9BLe99Bv$KoMfD3oNb(ATxMKuTwz>kj4-Y@ZZk$1V~x9w93$7rGbS7PMu9QKC^V)T zMaDE^hB4cyF=~xEqt$3LmK$A0x6xy)H10DVF&;HuH{LMbG~P1aHr_GbHQqDcH$E^v zG(I){V*FtIX#8YqVrpt?W@>HLv?o3@xRrX41n32!2ph$gCuVd9#2CY4ET$~S3DT9eMCHyKPulgVT@*-WJ- zugPbsG<{?G)^x;l)O5mh#&pGW)pWyj)AY{tyXn2@gXyE`lNmC@W|SFi4ly@2w=#D$ zcQSW2_cHf34>b=n4>yl6k1-&2F>DTw(T_edbED-&|#`Ht#d2syyZL=VyMp!w9SS-YbSmgv(50YjLAQeL1w9IS7Yr&GRWQ0> zOu>|bsRi>378EQjSX8jAU{%3}f{g`)0%8HFfLuT+pcc>y=miM{jDo}hq(D$0Daa_0 z7UUG<78nam1?GZ+g2IC00#89j!I^@y1?LLR7hEW~Sa7M}a>12?s|DW|Tr0R!@TA~r z!Lx!l1#c}V3)&K5X<%t$X<=z^>0lXd8DSY|8D$x58Dkl18D|-9nP8b{nQED1Sz=jg zS!P*hS#Q~3*=X5n*>2fw*<&GENR~8<*phCMSTZb9OQuC;ky{j&EK9ycW6@eH7OTZ+ zDYv*RZi~-SZTZ%6#PYM{y5)xDrsbC9w&jlHuH~NPzU6`CiRHEBz2$@DqqU*6k+rq8 zjkT?{owbv-o3*dCpLLpbx^;$irgfHewsnqmu63SuzIB0hiFLJgqji&Yvo*$wv0|+_ zE8a@5QmhG9j+JZ8v#P9WYra)u)mn8{z13hfT1{4~wZvLs^;&(_gVsaVlh#w#)7CTA z3)U;v>((3A->mPfzgyp1KUhCnKiMD~Y(v@5wnny=whp$AwobO*wm!DLwtlujwqdq$ zw(+*{i&luvg*0!jXle3P%@CEu2<3y>Le1oWcc#D+*T@ zt}onBh%Y1*5(`O%wujgo+nd|l z+1uNP*@xRl*hkt&*+<*Q*vHz(*~i-_*r(WM+ZWrH*q7QP>}%|i_HFhk`*!;d`))hI zPPB{cX?C$a-7c|b*roPNyUZ@PE9^OTt=(d`+HLkSyVG7}ueR^A@3$YeAGM#cpS3@* zKeRuxKej)yKea!zKexZIzqG%yzp;NTYFN~$sBux7qP9itirN=-F6v&?uc&{~@S+h# z3yKyNEh<`Ew4`Wh(XyiDMJtL{7Og5;Q?$7#rU+BCqX<`oFCr8Xi>O76B5o0{D6L3b zWGXTj6%<*DtVOn>!XkT7QIVslxX4-LD>_(osOWIfsiMf zh;nRqL_1;}7{?CBPRA}stYf!hj|1zVIFcMJ2jWO^2puwq+@Ww}IdUEO4zr`cvCpyJ zalmoVamaDl@r~nK#}UU-$1%rA#|6iaj-MRY9Csb}9QPeB9j_d(9ltn!b9``oEN)ob zsJLfwSaGl7-o<^2`xf^r?q58hcwq6M;$g*Oi>DS(E1q7wuy|4N;^HO6D~iL5Hx+L# zjw!|zGmDdoS;a^(yO>kVE#?&`7xRk+#iHWOVp(xsv8q^ITu^K&wierp9mQqEzT(Pa ze{oguH^tu;Un~B(_(@SQQ%q*EzGP`6>$=s58CG$%bm#iw;P_nUPQwgSIN6F5T zT_tfPxDr|ky@XxDDakF#D^ZoGOY%!JCE5~QiN3^8Vl1(g6qk5PDoVU12TBf>oG3Y2 za;oHX$@!AYB|n#3FL_(?TgkhU-%H+?d?@)?@~IRmg-cPT4NF^;wlD2a+Of1}X;|st z(jlcoONW(?Djiokt#o?n+R}BU>q|G3ZYDJQ7(ru+NrF%+=rKD1FDXSDI zWtVbF`K76)nWeJQyi!$Zd8w<^UFs>VDD{^5N-InKrB$WXr3Xuom7Xmsr>WEUaum*}$@qWuwYQ zmrX94QZ}z_e%XSug=I_2R+g9R9rXUoo&oiDpkcCqYI+2yh;Wmn67D!X0wxa>*U z)3RU7-Z)_=%87P{I2${gJKH(iJBK-kJ4ZN2I!8H2JI6T3I>$N3J101&IA=Q-JC`_@ zIwPEGoRQ9L&M4=0=MLv?C&5W{ikxXqu`}H%ab`HB&P=DwDR(NIIZmz9;2`XYmCk+6BhI7FW6rbAbIym(N6yF2C(ftNXU^x&7tWW?SI*bYx6V)HjmjIBHz{vj z-ln`;dH3=jr=$h%8%cEz|bt{twOu3fHJ*KXGySDXvyqPkcv#Km?A zU8yd)OX13LWxMiR8drhK;@a;z;5z6!7E&$nVwmm*`7I`xt@id6`pmT^_~r$Xitm> zBTjRjjYrP_eOMQ^n?rEfrfUwpYYf;426f#0o}5Vgfm+J>@;^J>xy=J?A~|z2Lp*z2yDgd&B#{`_TKy`-}Hi?;G!1?|UEQ zYwT;{Ywc^}>*DL->*?#`>+2in8|oYDo9LV5o8z17o9CPFTkKomTj^Wn+vMBq+v3~m z+wR-p+v#Kal6)*5;$!hIz24;s ztG=r`Rdu%Na@Ccpt5rW$-Kx4*^`h!!)vK!4Rqv`kR>Rees+(4aR=2KhS3R_PSoQGg z5!EBBM^%rm9#cKGdR+DR>Iu~ot0z@YuAWjowR&3h%<84p%c_@Guc%&Gy{dY3b$IoL z>gej2YE1Qx>Ydg2YC<)+I=Px(EvQbZ7FMUN=^Iaui#rdsfLcPWpirnS)M4H7@Zozf zbmB(vUi+M|wSA-GqKHI2)Ea7opb)ekY6rDPLfEKN$n?n2z7r;nn>}yLxLL#I&6+=Q z*x0#qM-H1fZ~XXSW9E(=J!jsSS@S219TgecZqeL%>#&49L|jxfW-d0GycZKssvEfr z)CU@Bfx1H7pzcr)s3#N#^@4hXI-7<_Bcw6X1Zj#iLz-KlzED4?KQsWm_We z#8@!Ox>yppjXHj390r_;4DAUT&Wa|1$F+A7CJAWpH#l~%qA}p#S6&c#;^SR(K z^`{y~hISblHZp9~*s&wSCQh0FKGuJk7}lgt5|f}g&`>Kh8JYr3g{DE%p&8IjXcjaZ zX^pf&+9K_c_DBb$Bhm@!Yy}dS2hE2TKntNo&|)Byr9cKrmq$@zcSZr$)*Pz;I*Wh-3~mitts%w6#gbw%#C5STq+K=57R3{B;9+%GP%K^7 ztiETk+2*ye80uWicJj`hKp3HImtpo|3G@YoDBP~kN9*QLKf)F;+`O3BTDo;tzaH8F z4K0E;KpUY=&}L{0v=xekwn0(Qb|@N(fiOr{q#M#5>4Ee_!jN7_Z=?^>7wH$M1S^7e zLc5??Xg9P6ii7q-@emfmL3oG&5kZmI7-T*|21Q?T#Do-s(yqhEDdc+u32>+DdQhd0 z84jkiB$hP1{?djo#qK0VhK{H|8;&ItqA|70Zq1@ETCT?6u*ATX0LDdzcB}94HN7A& zz{CC)5U^xiI3^D86g(Obbm;jP9cE*(d-j5Q^vKXY^(~fTNwLuwVvut1WBq)=>Z)lK ze4P`ACC7Z8Vr1yxdJ=zq9dmX?#qSJULRfv{uP>oqA0k70|3#Aspu5AD0frLdBSVM( zMWfkZCGEjsW8+E0n)w4IToD)Z*Rq%o@C2;T8m?ht>My!(*>E8tG}Hv~pk#;-380kE zMS&(L6(~kuNDQTe`oI?8ZzM7*Aoh0A06d~_L`=-07yyK^J7U4J8Y6?M4J2PbLQq<> z>EQW{Kn!4we0gp)xa%&SG(R?ugdqfxD%h$mhK7rZkNE@L-hb#@3q61Ysjlm}pbf}^ zvbD&Fb5IVH3*|wojWy684={6m%|{Gz>+`)P?yc~y&MO;9mZ0+m8#kQ14N%s{3gGeJRS zfaw9HuVW7hvzHhFY(u~_e8G+y2nAflEC(08GKvJa8y`+00DuPC1KQTDf){k%r znT?FDJ8>2IA#mb*WKQkS0FZ0eT-Z`e^n1Zq`%31!`aGso#a}K|{6L&r}~m zZ=j)e=n?c7dICL#oU4zXrlvpeo2iQ79PC~k=n!~3Yf$Wwp&h{r2!b>iC7u`yCJ@w201Dj$s}2mZ zB0i4(#Xz;w1Z!sxn8g=3P&-U*kJaS(crdNmaoFfR#6K+dP$(2tD?+#(+y&?p+#c=# zcZ55^ok895I%GYv0oiDRyTaW7vw_crY(lmI_C|vLfWZM@D>&t^7Jdy<%^?#A;2M@j zk>jIxh1Xo^YRnG6rTAz}5UECi-V38Bm__lx=10ZF(d($pS-Gaha)W8l*%ccX1NsDc z5gFQ}Zp1n*tPvW(qD29HjtuQr*I-s0K=~MYfN$~hv4rIq>dGiGfZHIUAU44R;K6$6 z5IhK(ifl%o`sU{Jspnv2~V6&wG#dB9izoTshWQAhLhIRpX~=MaKLq7YyQN7dWGueddQ z9t{&s4yf_GcuFh*8z1nzV|%57+wOdZ7IAA zUJibj4Ri`xuQkEhATbCA*|Bca*s#ECLtEA`ay1+dJQE+m!OM|dNG!5reZ;PSn8QYeHmE%d9fID1vr_>a?5OLoEqEv{a0nRr zsWAa(F^pKVCc^+qht-OHdJU$kVT?Xt(%P~<)%>fuh+S}OWavO}5nplf^A!O<3}`f9 zM-UqI@b16`{p!tTMu&yU5##njl> zTG(h!_`(ecDglB=2nex8ghY6u7TH_#ney4R!*nN;1q;{P!SqJM-mVQ zl87*oBrBW>?psWQ#c(<-fiqw!oQbf2=gdYp2)F)r3V=le>KFM}PGiu48vcdH7a7{? z?^*_d=PzB*8frDJdB49S0~`i&G>J?Ag8K_^wuV%VXZaW2Y)z9zL?YOlf_?VijrZAE z|J&gL?r~)3xOz%|>5SJ59e|<$24iu-t;K)sPyfSS+$iQ{PlmgZTaWz z&tFJq_*Z+4|6+qvXK)K(J2cb?TVN|}gA40!2r|M&umdiJi-LCsNx*Bsas9%&&!z_) zlb{7{y)=qQs&`vz{FM%C;&*)B5`59PQwEHG_2Qcjrd>H-)>=D6UHvs-C1COl#8ZQwUlDQ(Z zY|qo-q(Q?*EjPph!(MCsLqQmdG%FhHK!G6#aT&~3Vssz~vof&%1$Jx;F}SY< zd!K+apdB;o+e77h?$1rsH*ThH(zFj$`>)UbzBQlp&0F-D89y`lrO!-ZXz+u!aqF(b zr!85!X8op^y*N6jrYZ0?YyP#WeXo1t))?{L$^mpkQU5YJ8C=t?9XEWpc_5@^Vcti444e!gxcXE*M>)q8TGkckeT5i z7z502z4eZ)lk7?OTwqn6f=|O|;IoJV$wIObr4c?4Uw|*dm%yEBDnt$LR{MXoDu051 z4y?3mNUjdPj^zFAN?Xwy75~Qt)O3Ac3fNkM)v=*(RM7jt5F+}Lu(mgYvQFBTeNHy+PY2KcI`XVhDQI# zwiNLXOs1H1XpVj&`pLm?1z4M7^7>(ruimoK8SS_FNrTlXG4|7?q1 zw;9*>2>ZMr@6@7qA1%@Vbn4gtk9+ujJ;DI}fqis?K)|&@O%U>rbBU~p{>&o~umnJ4 z*l;lU&mII=U$y(0&u)Zq#K=)$|Jdq3J&Dg0{`1^tF9T`}0@7VTaAgoQ8kzuNkV~Oe zP&f$MMT6)Y8RCElh68MR&q9G6?q%pIbPaj{Jp}vC7tnjS0o(!(g*(GN;GS?VxIa7& z`0CT)nec4j@a};30FOfom%*oMv>a8Z{G;o%zUCc%_%ERHE_^?*fbSvsI`{#i`P&5? zfXXKTDxdumRBBg*zWL)y|KCF8S=6{?m;V+j@z;ab4WP19@Pn?^IiLsaBXD4cvH`@% zFtmjrsHSh*t}aLc#J4ndJNQ)#df0$jaoaJ30b%i25^%Z6@iC#$AApu8OjqU^_SLes zj^!O{zSqAVr~|5(@aq6yUme{n+08pC!0Z?>J*9W2)QDf$Y1Dy|eDF05`frEVS z8NiiBjoXCk+SWnRx%M48{uc!9g6^F|^-a5gxaXSqXzbp-u^?_96IPqj3HT}hn%d*H zEdjN#P<`88e?hHJ-+w)~xCMD-`T>LW0|(Ww=Fi^$kfC1ySjx!YGS&?TgO6xtXgd<* ztpDsU3=) zYFa?oCZQ&yrl6)GKBN-yBUMJ!bkq#gOw@Fw8rg^J2e1E++;-GL)S`d8nM5r^tq3UJ za^!#xwGuh_kIEMTlyB`nDc_+LtwWl8t$a(DMf}f|uQ;?FP`|bvyYvX_J7DmzQDY}g znLcaYLa##+cTBd!zPX&P|;*@?UfZy=Ke=Y!5}9n>}alzvxgqUers_b3W*~U~6sk zdCj64zAak3*bo;=0r_4VdKaje3H5j(UZ9k8Xf&jBbtYg6@Xy zh3@wUm|Xw0OM;$M2a_96TLUn;5w!`m8MOuZ2Kg2_f*cLFB->C?L6;=(i#z{cxQx3| zaRF4^gM6n$?L|)fBP!wnDuOWa--p;v{$B~PO^Y%A?Y^--#8zu$zw{>mO^B^ddK6S5 zNKvAwC>n~6NntuKSAxb4k?^^eLxNo!K)f0o<-GM$1_pt9?UDv_)8*>_YPO7&It9i>6(Ku#Z}MSjqs z^vI6^4t2(pF$DU`s6bsDh&>SlSWr{hR>yWT$_5QJpbAhHlok02xrY2~Koz3ws3PP# zas#;^AkrQTW+ z?^oAXfASBV>aV+o>M7LenuK>fV}c#O;-VgPCJ;ytq{aWHRm2X!)jl(EGlQ^LC)Nw7 z%g|6g>LTh=;0ML@;D=_fg4E%YfH(($OgRCVQ;@DFfM|MM30^QOG>-;~BLabjMRS2< zdwtb%4v5L`1l4z6wh1O5QP+aW$9g+dH;0?3+ky3X3wf>s#Rb8lg06v-Juy)0P+OG~ zuu3&4PhwrS2dKw^sXs(LLS7=T^a0fmDm|Eb`}*!nL6sMXs|M>H0%dNi>(A7hyFj^T zeKx6%^eZ$3>Qhj!QNN&mMZH12Mg4|)hx#4$9`ynB5%mfA1^E^H@Y-ACH{>1iJMtd+ zfP4f$!v;fkG>k@}(dZC#1L!Tf5wJ~7&`r_J(9PK}uzfAqa7#8klnoCDWW1p5VQBRAHz4i>qD)nU))8pmMw+I)MUpkQ!Kfl{ClC5jMB#0EeQ6S)QmzLxJ_ z(rZ-Seyp=Mc9pi=u&F^-icQxd2rmxSF}wO(}X8 zhSbm$&zP!$y9=-P;S zW(E^N!Ig;a4Q1=meb9Z`a0nZ2ij1fuG5|dU>R><*L=Qp_X2T8Ga6>lS$bcRS^+yk9 z!=S#H4L3oiZvh#Y&*Ayafp4FSZ$rV?fasP*?F2O~=`)jW`BMAP;mM-B%}r-9Z)CTnxwr#^OM=1nA%4t0qC} z0pt%2sS|Y!dM_w9M`O@C&^yt)(6Q*<=soB-Hr#~`cV)w18FgpFU>Wsf!(nW=SD@@X z@CORcYyN^z(*j&cpq?}E2UgpV0DtO|{xJYxh}b}VBqpjh{$1-Q1XpuS_4%K+j)>h0 z_D)fIabLF|{8!XhE}9zw&eb>}wZsD@iGNCb8HNNN^g)XHx_O{NhA(c+(3op*FFAn?)8@Ci%SiK>jcV1a{~atVZ(iOXdWBx z_jdr05&!@pI+YFgXTw821ArJU4QOOKT7u4C!vomxKsG$cfSwC9QVujIppk?BTL9=Y zlT-4Q+UKD)e>TXxnn6Nq2MLAFqs{07s1=$8w?K@jHVRVP6~zsty|- z9`qd0Hgw^pFHY*wb}0YL0~=T1FyM#l!EFU~78PBLE~)VpL!qzA*U;r?7upR^M^`{^ z+3+MbJeCblMX+p8=@$NFd3ud~sI9}RDI)t^sZqaXY7p2DFEpU5(ADUDY!=JqrC`X(?lu;~fb7#h$w&^N(C z`QlI@r~*n@F)@J}#Cc#}K(CSDZBXlozQcxRe%7A*=x5MSGx`DgA^H*eG5QJmDI1=} zhG(b(J#<1!Ru?NFB=ASX(1aW4tzj412FoP3)8yBaDqh&?v|;A zwzf6L76OL@c$wfJC~4hNb1Yz{MvWP=DPZZB0CzW7Ak!UyKRGTYU;MGk`*`+~3i?2z>Ssb_&KYqcH4X4-th>W9yu{+G>esu4XaQ2#u7kFhLSgDWOb} zVq?k@^QxL#o0R~<8YQ=ZEoEnAjo!qTv4^tdYz14%PGzUD)7cp;E``H@Ivl7YfQkck zBv4gA%>k+!s2ZRWo7mZsg~i5MjMvQ?&Q@okex56tSwJlSY8eLbq7`|xWJB)O-M2Kh zF;euG=ug-q{Y#Vq#dyciqN+y3N{?ShP=rJp@D#pk9^z?8kIxihsI-{1hjwN`8EF=R~?Xk!}Y&TUR$L}ofADX>j?isUY!izS^BPAS~lGG8=$)4wLdzM!G5 z2DJy;)M>4kV1`@~QkEix*`uh*?Q9cJ^W<=0wiTnl*~RP<@&Rf-P_@#}6^o3#(J4z# zb~y`Kwhs0rk5-Sn zz-HV_Ht+O^(#feTI?X!Rl`Pt9^*}YCuYz5*;wYdRR~$T>a7Pron3<%ABgsTEZd3@I z%c6s1GQK}@p|@(X^7&fh0zXneb!~$ShN?}E7J)qo>Teo>4!~HU-EKz z$Nn!rLM%y^GQ13by?n@5;qQNADB;s$M9pS8qski^*n|cei&C2HwGlZF8=i3 zR*d|$qP4LR_t86x`IKiAH0@wNz}-Ik4*M?q9*b7s=|G(U)GDCPT+e>Ue#Cyvegf24 zK;bUxY@qeTaFTS1(wQU=#N#^5s**<_{ZV!pk51`0_4&%Grg@2$T|TZ@Ws1sD3~v<5 zJ&h(V^_Wi%Au+p$WO6l2eW2OZ$9J}*@5)=zqaiht7TvdG(R~M)v#{s|_D9@~;HHHA ziT#=Vh5dDAm%0LK4IYmHbuQ2tp*5(>U>G^vyffseSKi&99I4yg7G%oJ`nlKsc+N%o-o0M&tp0Qyna|WDk173#`|i}Ix=x!?ds;SB zc43HJ?wPb|Qdb)puEehWag)WN52BOg&lP3LBCGr3vZZ0<1baP9~$ z&K=2BadWt8u7*o+bGdoke6E&Tz%AtJxJ6t&*T6M$M{!MDGuOhka*Meo+){2CcQkhl z*Tx;oE$5EoR&c-_&z-=X$eqNU%$>rW%B|#1<4)(!;8t;Ga%XX?xwE-*xO2JlxHTLu z*DHY90MtgHt_12Tpf&-u8K|p)x(28%K%vsQ4yfyax&f#gfw~E(n}NCos9S-$4XE3J zx&x>?fw~K*yMej~D0D#F2h>)e?g#1tpdJM3A)p=x>JgwG1?n-NP@6mf)RRD==6D*Y zXMlPZsONy%2GsLFy#UmUK)nRi%Rs#X)OMg=1?n}RUI*$8pxy-PEuh{8Y6np70QD|V z?*WD4@&lkg1nMK8J_ZT}<)=V>2Gr+3eF4;$Kz#+&*Fb#()VDyPt`g6ILg;2fXwt3;O)X3!RDl%<62(>ZwR6$U z5}$nJ)WY9eDn%QyNYDy-b32^cHKTw zkdONj^rT1@JW(Xd5VjH$6EYxCG=;1Tg}ZoUS6^M*SXC$5HVUx^39)gzCRS20xph%h zeK}^ik^>XW#aq@yPI?qNj}ST;yl@1gl!`6Z!|CDOJWdD&cRipkLS5@GnMY3%Dr0v| zMOwopwR4ge@3W+F2Jg6}qGz5yPudq`(mClBb@*c3fi+3q>Z#4R>sOAEl9udCgk}aW z9m`)3TRXOxcousjww(~mK-!d4?-M!)Wi%uVU#Y6@{S|yfD1|ej zgo|Mz=7|v(N}{Q^fqhEIW%NdseMocP1i$D9LHT&1Z-QSFf*HMn0xVon80~GQ-(}3W z0xaeb#aJRSwx>68KN4~iGkFh_rW9alqxza6^!oQk?H59=G81Z(6IFFB^CRdrLgiN{ z{R^v_G&I#TSIn$bO>M+;+unx8GlW_ODgaeU!=eN_ zb9Ts@l0*v$SniFQmQc&jfVO8SH`r8Ytf(HIKQF3*Eg~^p_P#UEXJB<4ft|e?#q>rhL`X$5K?IU&SWN8uUGVOpj0abNL7ELsDD2TxUR+hZtPCqSR4>CbKScse z=s&66=9y1OWw3R?sM*@4+TN(d2$hVME{4D+s^=4}P2%kOfb3*Ka&jgwph65^3fJHp zMKeR%we~j9DTL}FnNXdE`-=t=9EHJYnEi~UEAX(ZSM^&$=w`HzNt_BPMnR7Ez0FzEMn{!4i{Ija75xI-JT{sU);A@Jw{kN-Djo(3nnWcy`S-scJ=Q zGe&((uB|~=i$Y))A&|lDFo{4#3&yG{?GGpIGmvB0UOEgRk}IBNnJs*a^=| zMV}adB%znV-fLI%;{R;=t=&_rTz5Cft`+r`T|LN)_PrFxs>9?&a?%eT6vu)eXi zMcRNX!)+jRGt&J%4_BenMCfFovx>T=O+xGtoeCS#b%>|k)m<;7l@QDbQN8;5_@x=s zAo8MXEvJCu7(ychnKNBzLgfy|jcr7H{o0|YRXq$MFb z$C5lrJP=w#C=5{`Qf{bgsN_zpBS#*Q$??*7<;=2}@_tSv54)2dE>7SfAyKG9CHnzS zU9e#cUBTh}qFB7BFuy!pK2vFa3Td8~QS)d#zpw=M`#fW=7 z9w{xG880Zre<@8?lP0?*H|h3RlLwXO&Lz(c>-o9Tsg+nFGcLLPl?LahjYan1qes6a zip;~P-jd3~g2I^M(C05CO&rO6C{0Sj#a$!0ggiAoPDUH=aVVEdEt1c>B2&xD z#Zv+)S7)b#3ciE1*yRbCB*3pA&mJUhMuy_@6BikY0g_i5F)Z5JB1K_*U+D)VMX_nI zE?eqKLTUUiC{2n);*(+}vGQdmEQN}h#rdU0U9WXBA>~aaRfJ<}#Z5_D8=(;^ z5tp!dyn-vEU}{N(9NBbH*g`0b?TvyopQ#nGczLX%44dJJNYZM#o-_{h+!!$!88s?p z5RtO7cx*-_R+ch?n+OqizlfAqRu(D?@K)0N(A4JBtD1;7ZN@R+9%v|eTZAJBYH32# z!{sIMim4T4g^|M2sR)^3JiCb$Rw8gpx(-IA*M0{fe@Ld}3CBg^MBGFs$0Ab@yhTM7 z@yb#>+bS%nEKr7hH=#Q{jJ3&H$XRbyUBf&~MPAg1uI45jcGsy{xS}FfDGLA`UU3<+ zzr5=RtsBJ2@}ukJ-X{)T(JG>(>9Lb&DOo8qD$B!>%6P@}!h%Zic#l9mUYdVMWank~ zz(DAVgvfwJvQjTQE$4>`-HH7iFOEBg@#}aDxf8X=2(>a26<1q5G+bX*w+wTSkhfBe zMEs=!E1EXdwk%VYMYtqfG;uEZImQ;<7kAsW2j=6XUD+=lE?{3|NXBz{3j?wxcjsarboc&+{*k zP^-Ql>pAXR4$9zP;$OjR3jSrF4ek7Pz^XMnMOmaqEZ|uRTFDr1Jq=5#E~;ut3+Q6* zXZPUW=6A3|_;>mDSPbCslgMCtH=xZVGMEkk?btaonE#Ofs4FsM#T!%Br2BnV^pjV!vJLD;m#a9d@*J;Mr&(|FmY(a$TV3<6$y31 zBB7qeosDpm(6pik=m^j;phG0M75|kFbTlQnRcH}fi6j)33d?|=2=sxHB&5dyJt6s) zi=-HN~uB9Xz-Br^)8cessWR&WK@wue%z=XP;>co%l zs;<7D_?TGK1~2THKi=of^SJ#!UnmsF#k*|WN#A3A`SBjVH#Emr<;hK!+-J#>JB%qS za;`&tRr4a3!kVs}hjF5IRc>REq8}9YCh-EqxlE<(+s9V9!MZy(CdS5JDB3vq5 zCR{G86WWCip;K57bOF$q>x4;9g+Lzy^c0|rfG!3a0am(6*dR;qO;Q4cu!TtPGDUiq zD+v%ZslbmKIX$GmE26ZwY=M6hAjtksdaYwp6Cec4N^BSI2KrD%df$iAn}nT`|8U_; z|0$8H!Xv`tM5sP0JO(t%^~w(63E@egrvg1=@Fe$h!V5(1tQ0WVupa1XMDDyq7Vrk-jJF_u>lV_B6T z#xnG1EKgE~woui8B3D(XTBO2-cLLBS0)0}as!??m5xFM=eab&Ca#c&S460@6V)VWb zelX8_C7OH5mggoP;%Hk)M6Rk0pFKAH*{$a;Z(i)5QgQVcza6pH!{+-%V|l1#EF0|# zH;z}GBuZb^iK6s99i^`-LDUwcsV$5H#}n6<5u|vya>CY~H8-wCJ{=f0QWBzPU`~W; z70_p5M7wG=j`3{OIp}#trw_SoNK))cd1pYM1@sMR5}r6DROhQMV27wKOm;||4>aa1 zp+n;O9vl*?OI4S3OZYWFqrOopAxMK;PbB;mstu}*K%WEjxj>)SCE*9pAt8&uJ5&!5 z@pq@{F4f(tdsO$T?o(}5-LHB;^&rp}0KFFI3xUS9cQMeH0DURYmjQh_(Cap-9+t)5 z(r*VJOkd0lgXMt2@ z(x2_YLm;z2ZB*lxxtK1iMn@*vnb-BfwN%G|m@%u~O})ER11?2!p?|x2VTXDT;>RU* zm(sr^MFZtJ7jfxZWk5sJ!{x$H>V4G1UcIk+KW2&=y@0m@jcyJ!Y#+j! z8&b}7234NaE;U+Q>(yh_W7WB8H_*2MeLK*10Db5BEWDOas`7;Uq<^x=lfsAb>H;kB zq&`?ZK|N6&R_CiD>ZlsMEO!Ha5774leIL+UfxaK;2Y`O?-x5zXspOaIE@_tkGN4%hkuJSExaKy!r(7iRzQoC#z3UpQ>J|K23c((9Zz#EB;jUw!>vK-U%J2>hma$c2a|63n}m4$HJ)O%%j7;D;MBY_&HgXH#2n;F%2-~J$MWd_$3o5w=DG*)$`c8lck1ueKd66H|D^s|{fqin^>6Cm)qkk}%+AWDvT0zlfN=pc6_}a8v;cbpunz&} z2ku}n<$|dUOwC{}0PmIHy%u~k!FM?LmVobgqF$Y7dLG(}4#*^-t zCiSh9)x|qLb}on_ekG-VS7U+V#1fJ}T8-%r_1%S4`fgs)x`9yT?7y$~c()fWbX-wVj%lF~zmb z)#7^*xzjwga12Q}E-V%QxpSunc1<&dGuUV+TqW_Ud&u%U5vx6{9B~YjF+i8xe253Y z%0f-OEO)1F@OoS2Nm;ICJF@q|`+BpT*}G-$p1nu*p4oe456K>yy*DrvFbpspFaj`Y zU^Kw!fH44Lx+;5E_VDa|v-iv1KYK*>$m|2MM*))qj2)QWff)h}HXa7d{=kd`W)$8J z-)-4s=St$7p)uyVpNAH6NQH{Ab+vQE>*mJPEW=-uN&95d>|Z4vX=qA}sY)h2PA1J` zz+2{{CbdJA;qIH4o0mT12{K(3uCjsAO&w=crk9PfHgkI9VyTqEr^=wy2V5w3phbb2 zc?ZdiNT*pM)6@@`X8H@OkZIy=D+7OFp7gQKkm;HSJXUcbR4M42osE~4bYvfveK;@{ zV65n5%03d^>5NTO)5=yw0j&}X*nGJ14be5t;>II8f$m4~I9oZ$&aTa_Bh(jUF9gN` zjFV8WC)9WAKXtrrd?)HlvX3Uzmu4>mtk2HuNvO9G>U;H{I+lywiTX*|r>2elG(vso ziacq)tJ2z>oqb*!H_s<+_EFkgnAYaf>~*BgW!aYlGaQ(G$t*fZoBjGfi;Zd2H)n52 zo5gj6`Uqu2H>S0@HTw?ICWWtekv0b?ZSGBL^Fa2)Y5hD(+Kg7(JdxJsnd}$w%9ZSA zv!Bb}mi>J83&4y4CKs4IV7$QiugHEW`{nFcvbSfy3QQ1~3BbgFnF35%sziTFhQ!#o zu}TpMi>sQ(&J~L*G>=_))L3twKiJ${Q=jLq%k?Z<;#=GpSXQ4~Gd~yqZ(jY_%CRXL zR@9jb>lTzmj#f%AkC}(*KbRDkNEXWP$sOZuZiCqIqSDF!y7E3d{#fqVGpHTc%@1K| zojyDMLhcx^Cmh5XFZGv9sfhL2@walvfkEwf>io(6X_L}BmUdj(KV<)ej=}67feE!| z{|wByz5yu-h2L?RXa51rfh!ihsG-C<;m>Gj>Oc*v;WWHPn9(ZcOA&990k7E*D~zJM zos`zCz+ar7>i88y4_4;q*95!g7Xqe8mhhT`$Q*F>7N^f4 zUlUP%AkU!`n3BI`2EE7;aRyn-YHui2W-v)p*ad72vh+}81{f{Ut|`uo8B=1|2Wc+BLI*nUSIrHAl+g5-WXsQ`~XYjjet8 z;yiP5Lw>hg@i}R#H8m-Bd}-!sYDvHIftl5=Spdvosr@#{{mzaXmni-ABQDqN$ql$` z65ceIq}LPlhdcqVKQH7B=Av6RH6hxShGa4 zRD)(BTDeC669?uc)qe&s2|0W~b5>tbs+#jP7vlM}<^s)HVCDfcze978=3-!K zfvFp`&;iXlO(*H39Ydy=1terjvmQgHn1wxsOwnou9-A~<@H9=cS#!1K8ekRyQx8l- zr{-GCbr?OsGy-$fKOa4yxi!n6xh*{+;Ou*+&3EL*{y6cF<(15h6UUH{Db1bu>|N>4 zQd?V&ni&oUI!->n@SyABoA6nM1@~(17o!I>Sb_8yV487Tp;=E1@`Y(}Qc9CYH7{h1 z-mG~{^SI^-&6Ap^G*4@u;os9d$L=ls2}~<6OMpQPA+=+HISv>gCrZo-2IduDz6aI_tP9x5z*Ymh9N4v~0z@&X z7h{s9V*Zc>^S&=mA=`WTG6eae)1Ce)-`LRY2GS@d^ir(h(Z7yF=g(NIokgm%jK!|w zHE5rqH+O#0-aw;R%12|mUjOLJ6A|xgRi+{SBYhHzRovDuZ%Y!l#*%BB@ahs$X+{YJ zPM*b2vOHfNH%`lZ7HRGrc}lzL?RUAi6O#XPR<2W$#eO$Pq z6=dosrm<>LA6Nd6!KW@LOfn9St!b)S60fSR#t22JT+EpHjg2x)wb@!LM(1fYTCG;6 z)oTq}qt>J~Yjd>dzd0G0Q-C=Y7!;SM0dqPqD9={`b0#onZPMDL=sfLi+TFE#WDVEu zMbzDDIXaIy2bjx%xtyrIbs4C=o|VzRSs=Y;foMmge$~2wIa}7R+T6bMt2Uq|`Fq-+ z7H#ZvfjO^3d!Y6pVAcS$cF^>zHmoK2d+bVWgoNfX=cAg?77#UYL7JK{amOf2aEg}X z?`ey)#agtMF9Zg)>cySfGA+s9V=e*a(tlpRYB7ILJ2PEpK6=fxH%}=q+3n`nnl?Sw z7&?RKS1so6X%A0-_K30b?|7}Hc-Tev?K}45&Cg+q2IlYWlO_J2!iy@cl)tB~78PxK z9~@MgEYP+R1TWOqX%}hhwGG-v?NQn$ZL_uom`-5U19Js18-Upe%$2}g1ly+wOF;q$FzlW;rPBxvs-n}j=h*d!R& zD15t5`v8%ATeO&HfF|u-1h?3NG}}4vR%!B>77gT0+Q+p|XrI(RrF~lajP_aWbJ}g% z=YhEg@XA5vK47*2b3ZT-0P`R)4*~NqFpq4~z9{2%yNug62yP!$aQk={ZeRKrw|@g} zKP9;R44B6h+C>V3Nz1LPitj1d?^MerH(B2=M76Vco6dyK zn$w@%cJ`U&hjRsUPR%=R&$iRn?9mNdomJ;RKI?1*ws_q|eTU9TVEbYZur*PmWDx3x z==KqDtJ_<|?aPQ;os;19#olnM8=>z~ zfO#F5H-LE)7~HeI4a^Q;-r1z{O1RYpCEV%`BDj55!7X03A>A9teETnM2Oqb(LlC#R zDZsoZ<5pLKxYd>F%E$+p_ksC9`iU7WDrJ34)6FESYPxO)FdqT)affb}ZZmPF+Gbm!S6xV7~khK<^?%WPLg!Pd?=LgG?utJaO6d zHLEr~7{L2q5WPp?vrXyGet6^3J#Cj3*;h4uw(23>!i`DjZPhI$d|ph@i>cIz-em;6 z-}HoDx>|WV$LWrj&HiO5JI?({*R)R_V^vouyl?J6nev z)*pbu<2jVmKLhg%Fes&e1Lk*N{s89BO}g`B^sd!iNJ`e|EInpm#H{l!D$ZvespnDAsaqlC`Y6S$7**P`BuA1(pGp?ay8~DbSk2%8 z_g)=ZeVw}dbX#@z175((3c#v5br0$uLg2D$V6*=NfcqqZ@u_q$epg(z!*Ec^Ij0-S zj(uRwB)sJbf%_~z`&|07ci;bE-RS2gK6dT3dtWfmHT}LM;J%=HnLu!*4lkFg2Ugn$ z1cymm-7Mt_N8Ovc9TI%sCh%nqeY8~&|Do<10^g5xAL~BReX9FR_qpy1-IuzrbYBBr zRLq)z%>mW|tQA-ruy$Y_z&e55ZIkX>8NNU2e$xGn@cos*cXtK8djdNW*aHZDNBxW6 z!N;#2i%PWXvw_`1#;;z7_*EU6^%MC3eGDl%g+IEsyLyY>j*CNY)#H2I3)mqYdWRn0 zq4huxYIdD!cHSq8m79m?u=CcgB-XOX(Q$Buk-!{+ab3GDSDe0E&= zvzqmPUNGaxf|?T^`b_upZDS9@XNOH3E}_^sMB&B+eZGideON^CXhg9d8A!O;%hp#v zSzm!D))(pz(NEDA>5KIx`ci$F{!o26uw#H73v4d1Zea6(^#JPy)(5N~*uW-zrG#Sr z49SGnA4X6dR8TxlF`?Ole?j~=fOr7`@j_rj3W)0w#64fVtgMb!Ju&R`i}g!@JrLM~ zI`qr*M*}+^*vO#iVf}IX69^zz=s|xxum=M>0oaM1`V;jh5kQ84&HoPoG9&| z4*eP;$)chpTT3Jv)_zMvq45mmkn{e~o^N{#yNY`s;x$1ojYMrvO_7Y%#DUz?K4A2JE50mT%JEC`0#FshWfSP6FKu z1-es}Y7T7GztH^~p!*ns?&H8#D$sq3=-(cyIVdms1wAqB^e^gP0(Kg((>wI9=(htq z1K1-554dmY-yy(#OaHch2e31NodxXdPW`*=Mf&%FJq%F`?BS%ljITT2#pUJwzYl$z z{!;|wXX#+!f(?E+DHc%pl=XB_Q5@OgGNu;%x->pGq$UzVr)P`(>#-KIm40?mXU^JKvXg}8g zn*eq$u=9YO4{R;43xGwLUkB`>O$LhuVuM541RM4sAg)(H+}O1VZu=L+gAZZ@iR(0= z$=M)-*f54{g8xvJlFy1ttVbpNP|l1DK0^=}hrw?M0E=S1slyO5j03hA*u{fpL>nd; zhyiGrNLFwQS;2+~Q9Z3as2&ruP+5b8hGK-i;Sj?V1F8$O4iM_gIt?X;Qlhhu2KJbL zUS}JoWf=_9)8TyS37>6#uzBKyD_h#fz4rEvIO)aP472dr+3C+NcRq2``dg-~y{*~y z&XZSNU)rs+4M!NNBNsFm01LpP4RivqCjxsCuqOk13b3bcGBnG`T_Rb|hGPhFS1QOoy~}bw|6k<(4ai+d zkb4@irzyzAbf3O0XTy00V$m7a7|sXw3}9Dv7}gpt1oli|R}UU`FEfZ1;7S8pfatzC z3$+Kkif9k2vDY=Y(Xg2y_e#T6hE2ep4eU9L>ww9G(!E<>A(c3{ z8E(U8Z%==A@tn$sPd{vu`jVH!JNAG1A@ZyuyzVmGD4Zv>f zF#KTn5!fq%-9msdD6txb-;7xVhrb*CF#HMZRlp(|H+LGbrkN2v-dBrIyoPkwU-S$f za<>`PSq5WvI<|T!&$!Kq2gJr64v2dw`zZ6-Xfj%m&qgybJ@DX|)W9UhGwQ%}<5_95 zn{iJOyGA@cM(kdX*j1s$iw1Lg(MP4tFyjGPqc<3b8}~KtXWZX7!Z;Gx8-cwU*js_U z9oRd8y?cXklyS7tWgKH1Yee_ey};fF>{ej$WZ(f{A4~~NHp`i#ZGiC$Ukg7mf z#KBdQP)atqNO|@|Q(p-d-jF|(a3_)rj2PwIZuXYHNZ8}`_)`eW$=&R2e}%B8s@hu> z!n}&^;Avx2igji0_)CQ6Bm$nfDYev%a&|X+*Iyy*b%(03c6-W*^U|-#A zTx?uoTxwiqJlc4SvCVj_ak=q0Bifv=1N#B6UjX|9uzvu@1E&Yh2Hal2?FZbL)TMut z{JtN-r1RvZ-z=3IaW!HNcpt0Y?RHn^`BN(?8BddGJ~l9#9#0R;M=r(BJ~2R=J*}Mc z*VBaR@$8M?57T{IH>odh=WbkD19jOw;9oyxt^Jl^@pyEnS~Wa z(NBWmK9pm<@fGPmVBhQd{}l&|jyB_)#<$Q0e_u>vrp6j~bWmfnE>lRpYkZ%u3tN5I zZba$#(E!->iSaYSu1|sexZU_Uu%BeeuCI;X5q5oJ{1#Yj{25^vmf=EneLg7c`qhM% z<$8=m{)3rh~ zz+xy*CQHa!G5}tT~{kh$QXQ97j$di!iAi|SzrUQZf71-Z!otO?5 z*U9gL!jp(;@_=|!YC4qg1doRPY&Vqymo)&MOf$_OJedw0)oz*z9GxLg4mTZ1cyfd( z4jcmlVF%Yieso7#ahXULN)Oji<~Y%pyEE(bUZ;mIbEC)PpX$+f1NkSG0@v3Hv8COo+d zID5P49^f1USSRP@NW1AB;IODte@z$D2d0k*Pd)^0?{?G2z+v=C zMtbLS(^rHiUzolGZWwUG2~Y4YACxEi4hm0xH2pRZ?3fudhdeQ}!0q2|#vK`!XzDLd z%-Low^2CfHVPv~m2iyUf@x*L06Ss`nY)0UW0&X<&#B39Jf@hL{-JCP;ZXP<2bz9%?ALNI{==HG3OGVj0Mi!ZgvBgmmyDlW^xo~_L~F1d4ThxJTZ?G<%w@l zcrw8p9ndsY*1yAY9-NnKzrSHeX}jV!qaVo%wq64dxroH<@oX-(tSi ze4F`p^Bv|p&8VB!0Ecq;Pv8T<-vj)|AlN|22jK@$?E|X0pgITeZV|Nx)Qdp94%AP9 z`a8%T583k|`v$FSyYI##6z#CUp&Om3GS9M6CCvtl^gVO;~inHBYM4j%&EO0r!>lEz0^GkL6?X z-21h**4B)VMG6A3ys+ODjkw(|Z!G3><;UD!m$x7o2u5SUP&7ZbpG0uHJIS?aepv1} zzds%4VO^Sl)G_uO_QeWvU7;xU?sZ4pu3*R$cKLlCZy=l>%n!Qrm5!6^lA528JC63N z<2h)qL4Uq4>Io_{PGR+na>tYV)3MJR^vfMb zBk1LgMq{p!JBF-|c|)%JP$1%p`15=|cWy9}9|`o>@vCyjhxDgow+H`|SsjgpBZ1tQ zD;5m#Yd zek=zShy=rV-bkL(aVVM7a`_dmJZ_wmF{j;bUmzrPoS*B<%Znn00x>@-zA#QU6b^e_ z1zvw7FE8ec2BQ(BV|U7`mTR(bmHnEs*AtRovacYVpNpVzMSKy&aU|k(y&M$Cb4f_1BHyZQ$ zB3&J)%vdhl!p-PU#{rbXeu>v1U(8?N&G)%-aj7G(eI8dh7vHqcpBwg|NDIU~T`xJg z;~cr53pcBO9lJyFj04eVzQ>JX!xxO;5{u*^p2Crs%jfpx7leWZfe1d?gObRRYrSxX z^`~PWB2-oq0aOwJk2`?tI2VDO8_0L%qZD<8z5bxLAh*EnjrBZZtqkNN`qOb<$QSTR ztPXoUdES6G&sE?@@r9Brii<1H;|dg@Tt#dbMEpGhImaY-d}RMRcIV17b_aaczIpt!KNl}t?vd3tx#Kzg>ez=?sWju(Q$2K_RtV-a5{&l}ElMZ<1X5@?OMf>Dpx<;Inj zAIi^*xbu6S@ld&Ays9;GB@y!b6ayp_3>AcP!>)kak1%%Q%MPL4fhM~r6n2NhXcY7a z$$MyYDPTo);D68W@#N&&` z(DVp;0tlu+2u-~xYN$wFL0&AHk7_a3r*xc`A~8d9&yD?h$3A6kMT6m3IE(@_5=4G` z1Hlj)xBjRrh|3^9zrY_uRiSj8((l1?zfJvN^#Es_(s4xY7%$Ms-12b;^MbM+5Gp9Z z2^JKf`b9_K-)}f5$#(EZ*ljV-FkX_~-<0io;uWFQ&_#*uQR1BUd zQ4#o#@e&!AFW|?u?~COJJUw?@EO(4&Y?+G>Ptd1qoIJsT+-LwXROjbLqTwE2ak<!Q^q}=epg2ynHt@z2|-pllxuX zp9y>N0_b27x2U->U&Nb_;yKTQO39m#ODmj_0j0N=i(ec3cO(`f|D0hst^)l}m%^YPLfwp`olJ7^66-9CFjfV4ZZJ~-l zLk|%h!d+arXWi5&cYJbxI`;Y9Xj6#q*c0+cBKhtDBB^mvhhxP0h~hRP=)+yAKY|4z6jg*hh2i#7e!1N=IgWkMoD1!T%aBj~w^@(!F zXZEY(fq8sVR`p7`5h(qOu4UggkkXNXXl> z)_WRJ^6!rPN zxlwN{H#f<)m4ak)&d*tk-sPMNfIGiE=R)8vAl~Ji`3=n&lOlPgYVFxt_Kc@b^!M}xh<1>3%DJmgCVsw=*z5~ix(<2m(G9cA6$;r*1u5PSG+xN-6yrs8z#h9;E;#E{ZWU__z_^PXFO6PVH{<{YHSPnUD&3QcM z3E(yWx3MGVshp>QyArs2$v_RwDzkn*=d~=` z#+(;&Ud(wZ=jEJNa<=EZ3fxt|;R4$X+||Hc1KbwiuHBgPde-o);W=;NX9p%4aMy_y z%()w|HU@V$CKzDXyLC@qTFGOiHG@6JjsIUNnCE;(*5c>DT`$M|=X^!7?S7K}!%`K} ze@d=h&W}02kk|E7&d=O<<=EPea=lHsFZ!9*86Zy=pv^Yr05=Tlc3NK;S96i0aj3vtu%RZ#Z z7R%lwq zk}e7Gx`M*`#kI|~bLtYPG19xh%qp`HK(>_0K(G*u=JNL5VE(re#73Yq);D(*dT_IDtUC4 zC6=QJpO<3(4)+Sl-?1Ensl(j%o>GU6MGBt4Lc-M$&L@a)ehuMlIR+&Fw%fVljA&I@ zP9u{1K2-NB7Cnb!JQKJ##h_lxYRlQvN-9cP>*_iztFtbXo<5f>m-B#od&Qz*6N{yC zH_|t22^~Z*W`ZeWxx{iA+IJQ-&E9RdTn^lOyD$hXot7&|gZ03@-)=#*{z0Dxp=Fch zdNc?vn=MycuCZ*fTx-Fb(mw?5Bj7#;?i1iX1@5yAmK&&Rs0Q_F%PoX^pRZU&n1SZt zkI2XWVr$THA2sM-6Zag@d zWI!b89XBpqR@gjlTuoh7O-)m>iI`@2#*G!p1pICB_`F0tDaN0O;L=Of{H;GhrT`jpW zxEkXmP-yRBK+$9>o+K(u@bcWchK5FYG`k>Eo=he$iA+;NLreUq)uz@ZiSJ8*vxaWrd%D369stez^UEzOZ~nzWNe)s@?K6@O0nO>3hp> zL^}Oo`O)%|{BHTf@~3*Wl|t#ntAV!w?;-Mu_x*Rv zC#!~a2RJ!D_UctY&MD)nc^*pAEbQcrEZc;Pt>8fHwkf0^SUK4iQqmZ%( z5|=FfMo5njb&r$ZtnOHqmveUA9tv;*Y8n6bf zA?rBccLRQR;P(K2PvG|gehBbGH(C!OE)y&6w5+((0)B7NWx@}~ofe<_Kjbp8lAV^d z82EkUot9PEX<3z>7C%hfX^mIj*bFP#X<27lX917PV!saSVb;Te-ye7>*gTr(?aGP_ zTq;T@bF2xnVOVLcAua=c1a26t^Uy}-N2YBUOpf!FR&~}!+@Dz&S?jH+w{S&`2Hw?a zJ<8gI`!gPw)!2W2e`Z~lWw0KdzUNxexUIA#H06$S91Cu)UbFERvOlvPi_b1ke>T2g zuW9ZHrF*Te`SHV1%Ra|SFv|YS3RY>SWfgZ?yt@y^4W{EnG?1+120`l?zVD^_0V)#d`;Pt2}kQVb~TWmddpTRsJ_ zwgVsRGN7#MtsC$w>lMI<+N~Rb7q9v4)!%R3Y{hbl8?0Abud!~iUTeM1dOh$50)G(j z*LlZfX@d$0(=zs81MzaPXc~2@P)u10{j%RAcDyYA}_bCVa|f;3=NUN zJy(buQw$q-P#Q|rPKOl@jeTmco%V?CKwBg{Zk%YojT`Wt`g4?c0nz5raqAxUhAy1Rw(X*N>%c! zbE6Fx$56J}Qwzh5jdiuvRpdNlXnZa?Q;LWK%qN@TRKs131kTP=Ini8t5^+mX~jW&qGY~BTh zaVZpVAKFa;3H8}n(Mzvb-@r^C>vlxV{npokM}3P(LA;c#x4vn8%lfu;2k@o9F9iN1 z;MWmDizLu@outW!TFniuP1Sg-Yz=0??6h%j#w|o`_0Tes_}|csuVu_|V%?1xnbG(@ zuzpNb`iIt!fG-37&<^V-)=z;i2Yvw=OaF|pudF{2BkXJIH`Z^h-&w!6{$TwP_zK`F zfu9QeG~lNLKLhxg=oD?T{{N7>+eS*Q+i(LqTQZ9UXkf8dBOUugWW`2Ld)-2T+GVI!d1 z0JDv^O(cBVVw*r*-F$5ye8VyzGswBf7|eB>Qrj{{I+=|&RJW3n8Dq*4^QxL#o4e0z zT=MyTYQTbRlI;+(946aP*VX~QsKYiz{TA@`K#Mot^b5VVLv46{&PH3gt-@Amn`)b8 zn{Gp_qBY$JJih!U;G2PO0lpQ{YnzRq!|@ZB(7TubcPaUC!v7L_NsVlYQxe41iY7v;5{(|u5GYg zMc(E{+m*nd4E!k_woL?mSm1F0=)2B#8$sXowi|3W+HSJlY`evFEAT6UKMi<%C%Cm* z1^k)7pS96;J8@vx?!wPK#DTF|a$uZ8(0AGYkORX;%B0&K2VS{V*G9^u_ZstId%;GE zq}yJ!y#)NZz@OJ)d&RaL_%*-}-mSW}H*GseCvV{)DStlVufz5Zaim|+(;=x!sqJt3 z$o3h*-^aF3Y@Y&uA@GR0i#u(f+rA+9y9D_EfLnEK-y^1eNXOK|iMPGYZ@To32HGKX}d(O$~c)xRb68?U-XG!?`Q^eopM0vhLjE?l{ zh-Il|=k022Vi)Wx;BjN$(P7Uf`0E@9{_IA(1Mz1!+0FJGyTxv`+w6AW*8`8LEu}2A#ZUP?H z=RX~%VV{y^uotDHBYw-w6Gt6Uu=MzS*KW;!!K@`nvX|nsW$Dk(JuJIs`U_JwUsL?j zXLr5`Tf32Dudq)eNLp#1D(e4R5lQwL1WC80neQg%R0T|j+m96SXUBUD&>p#?k5;0C z&OR64zV!jz&MI#ojiCW~>?CqasL35y2F009p%F_z<)sK_iI06zuA5_k?6PBZ?)fMzukU^ z{Z2c&V4ns4IpDVe|2*(70RJNJFX4X1elLEu;^zTrKl3sX=G)1S_x^|WGxn#+8bNNq zqF{PkpAvn${dMxXUbVjl{Hwsf)?t6c{wDC~=6YxFB>KDd4~ay7&;Gvs1K<&e*uz_$ z_K)lz6N&yd@H_qkB>Gn(%Wwg`QKhQvFOU_zucia^5R-iqJM|aexLsA^x;(> ze|GGYy{^7N9pInztVxpSKiPjJeEyjjmGAa#RLV$lP!3iU=MF{`=kNDnP7V5DkOM<4 zB+(!*BZmS1p!*4rZo1^UBgbLwI+k&uH|vuwx$bZ}cE_(Ay8-`cyJHXFKkHMjJBB*; zN4f6U+p&*hm}9tOUkBP`p9B8|@LvM|74TmJ|IG%+2**gr0qWI`(L}C)3;g#Wn2B5$ zEdSkd-Qh>xIs(9dN91~n&wqen8_E(o&@moGyyGC?e`t5$@z#$7(*uizQAp-HVz??D z5eFU>{RI5a9gYHGvHvm{{$fm z1ZtyWDzVrdGw?GDEp~wxEp~xL`7Rj$hb(qSf~=LfATSCrYx|P#jz&i_d0j_2nn2({ z;5!^Gj#dx^5Ts(2gK^&PINEV6>Esv`Zi0#kH^*{>sG#m)$86k3Sx6^3PDQ2QILUFc z;}j4yAZS6*bvjl$PD7<2=s__2^Gd;Sc9y|$PP(91-?Q7-*HlDHj?a1Y_&fJDd_|Ok z1D#ur9-Lcu9&pRDho%*Ocgy0d7d_sB2Sr`S{f-MAmq-%+Vj|%M6H0i;ay0Xib3F!D zJ37eA?*!p5#I%W~x?>|DbR`H@a@u}?7{91o6YRL!v87wAUkif0Tdd#UxQU4M8$oci zJ8lNS*|%7~-Ekig>vuTrbll~*+i{QMUJ!NzVRsPr0AWuM_5xwZ2FF&%{f-AvtUpB7 z%uo>a0bznD)+hd#i}hy+lb;1)Zz9%H!r$DvZCwYMcnn$5n5f3&!Rkzo`y4MgULrF6 zMG%IyJ6;B1IFadnA2=$Id(H7C!RhM`)S3H&uwRGcEyvp+><_}h{kF{=?>jyxvik$a zhmMaNA3HvAeCqfNgb^T&1mOS>Mu9LI1Q!Tn&^C8`iJ!0W^Q~x`3uB4cc9S0m{SVpZ zjz7qPK#i6w%WfyF$nKs_3Y}`F7GIY$+lj(44+Kw#Q|Cmv=mlZipxNfm948(}b~-Ii zs}oBG`atl55a@I|oK7N!gCK!u9&s3TMRo#I7bmak0k2rK+!fIMl8 @LkNB&XYn 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 z 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%0Avo>E+pGK&m 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�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 + + + + SchemeUserState + + Pandios.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/src/pandios/Pandios/Assets.xcassets/AccentColor.colorset/Contents.json b/src/pandios/Pandios/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/src/pandios/Pandios/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/pandios/Pandios/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/pandios/Pandios/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..23058801 --- /dev/null +++ b/src/pandios/Pandios/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,35 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/pandios/Pandios/Assets.xcassets/Contents.json b/src/pandios/Pandios/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/src/pandios/Pandios/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/pandios/Pandios/ContentView.swift b/src/pandios/Pandios/ContentView.swift new file mode 100644 index 00000000..16a64f7c --- /dev/null +++ b/src/pandios/Pandios/ContentView.swift @@ -0,0 +1,95 @@ +import AlberDriver +import SwiftUI +import MetalKit +import Darwin + +var emulatorLock = NSLock() + +class DocumentViewController: UIViewController, DocumentDelegate { + var documentPicker: DocumentPicker! + + override func viewDidLoad() { + super.viewDidLoad() + + /// set up the document picker + documentPicker = DocumentPicker(presentationController: self, delegate: self) + /// When the view loads (ie user opens the app) show the file picker + show() + } + + /// callback from the document picker + func didPickDocument(document: Document?) { + if let pickedDoc = document { + let fileURL = pickedDoc.fileURL + + print("Loading ROM", fileURL) + emulatorLock.lock() + iosLoadROM(fileURL.path(percentEncoded: false)) + emulatorLock.unlock() + } + } + + func show() { + documentPicker.displayPicker() + } +} + +struct DocumentView: UIViewControllerRepresentable { + func makeUIViewController(context: Context) -> DocumentViewController { + return DocumentViewController() + } + + func updateUIViewController(_ uiViewController: DocumentViewController, context: Context) { + // No update needed + } +} + +struct ContentView: UIViewRepresentable { + @State var showFileImporter = true + + /* + func makeCoordinator() -> Renderer { + Renderer(self) + } + */ + + func makeUIView(context: UIViewRepresentableContext) -> MTKView { + let mtkView = MTKView() + mtkView.preferredFramesPerSecond = 60 + mtkView.enableSetNeedsDisplay = true + mtkView.isPaused = true + + if let metalDevice = MTLCreateSystemDefaultDevice() { + mtkView.device = metalDevice + } + + mtkView.framebufferOnly = false + mtkView.drawableSize = mtkView.frame.size + + let dispatchQueue = DispatchQueue(label: "QueueIdentification", qos: .background) + let metalLayer = mtkView.layer as! CAMetalLayer; + + dispatchQueue.async{ + iosCreateEmulator() + + while (true) { + emulatorLock.lock() + iosRunFrame(metalLayer); + emulatorLock.unlock() + } + } + + return mtkView + } + + func updateUIView(_ uiView: MTKView, context: UIViewRepresentableContext) { + print("Updating MTKView"); + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + DocumentView(); + ContentView(); + } +} diff --git a/src/pandios/Pandios/DocumentPicker.swift b/src/pandios/Pandios/DocumentPicker.swift new file mode 100644 index 00000000..a91b8b76 --- /dev/null +++ b/src/pandios/Pandios/DocumentPicker.swift @@ -0,0 +1,75 @@ +// From https://gist.github.com/aheze/dbc7f9b452e4f86f2d8fe278b3c5001f +// DocumentPicker.swift + +import UIKit +import MobileCoreServices +import UniformTypeIdentifiers + +protocol DocumentDelegate: AnyObject { + func didPickDocument(document: Document?) +} + +class Document: UIDocument { + var data: Data? + override func contents(forType typeName: String) throws -> Any { + guard let data = data else { return Data() } + return try NSKeyedArchiver.archivedData(withRootObject:data, + requiringSecureCoding: true) + } + override func load(fromContents contents: Any, ofType typeName: + String?) throws { + guard let data = contents as? Data else { return } + self.data = data + } +} + +open class DocumentPicker: NSObject { + private var pickerController: UIDocumentPickerViewController? + private weak var presentationController: UIViewController? + private weak var delegate: DocumentDelegate? + + private var pickedDocument: Document? + + init(presentationController: UIViewController, delegate: DocumentDelegate) { + super.init() + self.presentationController = presentationController + self.delegate = delegate + } + + public func displayPicker() { + self.pickerController = UIDocumentPickerViewController(forOpeningContentTypes: [UTType.data]) + self.pickerController!.delegate = self + self.presentationController?.present(self.pickerController!, animated: true) + } +} + +extension DocumentPicker: UIDocumentPickerDelegate { + /// delegate method, when the user selects a file + public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + guard let url = urls.first else { + return + } + documentFromURL(pickedURL: url) + delegate?.didPickDocument(document: pickedDocument) + } + + /// delegate method, when the user cancels + public func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) { + delegate?.didPickDocument(document: nil) + } + + private func documentFromURL(pickedURL: URL) { + /// start accessing the resource + let shouldStopAccessing = pickedURL.startAccessingSecurityScopedResource() + + defer { + if shouldStopAccessing { + pickedURL.stopAccessingSecurityScopedResource() + } + } + NSFileCoordinator().coordinate(readingItemAt: pickedURL, error: NSErrorPointer.none) { (readURL) in + let document = Document(fileURL: readURL) + pickedDocument = document + } + } +} diff --git a/src/pandios/Pandios/PandiosApp.swift b/src/pandios/Pandios/PandiosApp.swift new file mode 100644 index 00000000..63766574 --- /dev/null +++ b/src/pandios/Pandios/PandiosApp.swift @@ -0,0 +1,11 @@ +import SwiftUI + +@main +struct PandiosApp: App { + var body: some Scene { + WindowGroup { + ContentView() + DocumentView() + } + } +} diff --git a/src/pandios/Pandios/Preview Content/Preview Assets.xcassets/Contents.json b/src/pandios/Pandios/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/src/pandios/Pandios/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/pandios/build.sh b/src/pandios/build.sh new file mode 100755 index 00000000..63c954c3 --- /dev/null +++ b/src/pandios/build.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# Settings for the SwiftUI frontend +ARCH=arm64 +CONFIGURATION=Release +SDK=iphonesimulator + +# Settings for the emulator core +EMULATOR_BUILD_TYPE=Release + +# Simulator settings +RUN_SIMULATOR=false + +# Fail on error +set -e + +# Go to the parent directory and build the emulator core +cd ../.. +cmake -B build -DENABLE_VULKAN=OFF -DBUILD_HYDRA_CORE=ON -DENABLE_USER_BUILD=ON -DCMAKE_TOOLCHAIN_FILE=third_party/ios_toolchain/ios.toolchain.cmake -DPLATFORM=SIMULATORARM64 -DDEPLOYMENT_TARGET="13.0" +cmake --build build --config ${EMULATOR_BUILD_TYPE} + +# Copy the bridging header and emulator dylib to the iOS folder +cp ./include/ios_driver.h ./src/pandios/Alber/Headers/ios_driver.h +cp ./build/libAlber.dylib ./src/pandios/ + +# Come back to the iOS directory, build the SwiftUI xcode project and link them together +cd src/pandios +xcodebuild build -configuration ${CONFIGURATION} -sdk ${SDK} -arch ${ARCH} + +# To run the app in the simulator: +# Boot the iPhone, install the app on the iphone, then open the sim & launch the app +if [ "$RUN_SIMULATOR" = true ] ; then + xcrun simctl boot "iPhone 16 Pro" + xcrun simctl install "iPhone 16 Pro" "build/Release-iphonesimulator/Pandios.app" + open /Applications/Xcode.app/Contents/Developer/Applications/Simulator.app + xcrun simctl launch --console booted "Alber.Pandios" +fi diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/provider/AppDataDocumentProvider.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/provider/AppDataDocumentProvider.java index 397eef05..c260cb9f 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/provider/AppDataDocumentProvider.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/provider/AppDataDocumentProvider.java @@ -38,6 +38,7 @@ public class AppDataDocumentProvider extends DocumentsProvider { Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE, Document.COLUMN_LAST_MODIFIED, + Document.COLUMN_FLAGS, Document.COLUMN_SIZE }; @@ -101,7 +102,7 @@ public class AppDataDocumentProvider extends DocumentsProvider { } cursor.newRow() .add(Document.COLUMN_DOCUMENT_ID, obtainDocumentId(file)) - .add(Document.COLUMN_MIME_TYPE, file.isDirectory() ? Document.MIME_TYPE_DIR : "application/octect-stream") + .add(Document.COLUMN_MIME_TYPE, file.isDirectory() ? Document.MIME_TYPE_DIR : "application/octet-stream") .add(Document.COLUMN_FLAGS, flags) .add(Document.COLUMN_LAST_MODIFIED, file.lastModified()) .add(Document.COLUMN_DISPLAY_NAME, file.getName()) @@ -157,8 +158,13 @@ public class AppDataDocumentProvider extends DocumentsProvider { } } + @Override + public void removeDocument(String documentId, String parentDocumentId) throws FileNotFoundException { + deleteDocument(documentId); + } + @Override public ParcelFileDescriptor openDocument(String documentId, String mode, @Nullable CancellationSignal signal) throws FileNotFoundException { return ParcelFileDescriptor.open(obtainFile(documentId), ParcelFileDescriptor.parseMode(mode)); } -} \ No newline at end of file +} diff --git a/src/renderer.cpp b/src/renderer.cpp index 6a18df85..390a3fa6 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -3,6 +3,8 @@ #include #include +#include "PICA/gpu.hpp" + Renderer::Renderer(GPU& gpu, const std::array& internalRegs, const std::array& externalRegs) : gpu(gpu), regs(internalRegs), externalRegs(externalRegs) {} Renderer::~Renderer() {} @@ -39,3 +41,39 @@ const char* Renderer::typeToString(RendererType rendererType) { default: return "Invalid"; } } + +void Renderer::doSoftwareTextureCopy(u32 inputAddr, u32 outputAddr, u32 copySize, u32 inputWidth, u32 inputGap, u32 outputWidth, u32 outputGap) { + u8* inputPointer = gpu.getPointerPhys(inputAddr); + u8* outputPointer = gpu.getPointerPhys(outputAddr); + + if (inputPointer == nullptr || outputPointer == nullptr) { + return; + } + + u32 inputBytesLeft = inputWidth; + u32 outputBytesLeft = outputWidth; + u32 copyBytesLeft = copySize; + + while (copyBytesLeft > 0) { + const u32 bytes = std::min({inputBytesLeft, outputBytesLeft, copyBytesLeft}); + std::memcpy(outputPointer, inputPointer, bytes); + + inputPointer += bytes; + outputPointer += bytes; + + inputBytesLeft -= bytes; + outputBytesLeft -= bytes; + copyBytesLeft -= bytes; + + // Apply input and output gap when an input or output line ends + if (inputBytesLeft == 0) { + inputBytesLeft = inputWidth; + inputPointer += inputGap; + } + + if (outputBytesLeft == 0) { + outputBytesLeft = outputWidth; + outputPointer += outputGap; + } + } +} diff --git a/third_party/SDL2 b/third_party/SDL2 index 379d4780..f48a96a9 160000 --- a/third_party/SDL2 +++ b/third_party/SDL2 @@ -1 +1 @@ -Subproject commit 379d4780559690a9836444aeb5637f60953947be +Subproject commit f48a96a976b50d1faae70598e71bfaf8f4526347 diff --git a/third_party/cryptopp/CMakeLists.txt b/third_party/cryptopp/CMakeLists.txt index 9c410050..aa915e3f 100644 --- a/third_party/cryptopp/CMakeLists.txt +++ b/third_party/cryptopp/CMakeLists.txt @@ -209,7 +209,10 @@ function(DumpMachine output pattern) set(${output} 0 PARENT_SCOPE) else () - if(CMAKE_SYSTEM_PROCESSOR MATCHES ${pattern}) + if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "" AND CMAKE_SYSTEM_PROCESSOR MATCHES ${pattern}) + set(${output} TRUE PARENT_SCOPE) + endif() + if(CMAKE_OSX_ARCHITECTURES MATCHES ${pattern}) set(${output} TRUE PARENT_SCOPE) endif() endif() diff --git a/third_party/cryptoppwin b/third_party/cryptoppwin deleted file mode 160000 index bc3441dd..00000000 --- a/third_party/cryptoppwin +++ /dev/null @@ -1 +0,0 @@ -Subproject commit bc3441dd2d6a9728e747dc0180bc8b9065a2923c diff --git a/third_party/cryptoppwin/CMakeLists.txt b/third_party/cryptoppwin/CMakeLists.txt new file mode 100644 index 00000000..926fb483 --- /dev/null +++ b/third_party/cryptoppwin/CMakeLists.txt @@ -0,0 +1,7 @@ +add_library(cryptoppwin SHARED IMPORTED GLOBAL) + +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set_target_properties(cryptoppwin PROPERTIES IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/lib/cryptlibd.lib") +else() + set_target_properties(cryptoppwin PROPERTIES IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/lib/cryptlib.lib") +endif() \ No newline at end of file diff --git a/third_party/cryptoppwin/README.md b/third_party/cryptoppwin/README.md new file mode 100644 index 00000000..3a32b2c9 --- /dev/null +++ b/third_party/cryptoppwin/README.md @@ -0,0 +1,7 @@ +# ext-cryptoppwin + +cryptopp library for windows + +This is the place for crypopp static library for linking with windows when using clang compiler with msvc since it is not supported + + diff --git a/third_party/cryptoppwin/include/cryptopp/3way.h b/third_party/cryptoppwin/include/cryptopp/3way.h new file mode 100644 index 00000000..868fa8ca --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/3way.h @@ -0,0 +1,63 @@ +// 3way.h - originally written and placed in the public domain by Wei Dai + +/// \file 3way.h +/// \brief Classes for the 3-Way block cipher + +#ifndef CRYPTOPP_THREEWAY_H +#define CRYPTOPP_THREEWAY_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ThreeWay block cipher information +struct ThreeWay_Info : public FixedBlockSize<12>, public FixedKeyLength<12>, public VariableRounds<11> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "3-Way";} +}; + +/// \brief ThreeWay block cipher +/// \sa 3-Way +class ThreeWay : public ThreeWay_Info, public BlockCipherDocumentation +{ + /// \brief Class specific implementation and overrides used to operate the cipher. + /// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + + protected: + unsigned int m_rounds; + FixedSizeSecBlock m_k; + }; + + /// \brief Class specific methods used to operate the cipher in the forward direction. + /// \details Implementations and overrides in \p Enc apply to \p ENCRYPTION. + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Class specific methods used to operate the cipher in the reverse direction. + /// \details Implementations and overrides in \p Dec apply to \p DECRYPTION. + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef ThreeWay::Encryption ThreeWayEncryption; +typedef ThreeWay::Decryption ThreeWayDecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/adler32.h b/third_party/cryptoppwin/include/cryptopp/adler32.h new file mode 100644 index 00000000..39f8deb5 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/adler32.h @@ -0,0 +1,33 @@ +// adler32.h - originally written and placed in the public domain by Wei Dai + +/// \file adler32.h +/// \brief Class file for ADLER-32 checksum calculations + +#ifndef CRYPTOPP_ADLER32_H +#define CRYPTOPP_ADLER32_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// ADLER-32 checksum calculations +class Adler32 : public HashTransformation +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = 4); + Adler32() {Reset();} + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *hash, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Adler32";} + std::string AlgorithmName() const {return StaticAlgorithmName();} + +private: + void Reset() {m_s1 = 1; m_s2 = 0;} + + word16 m_s1, m_s2; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/adv_simd.h b/third_party/cryptoppwin/include/cryptopp/adv_simd.h new file mode 100644 index 00000000..963d58ee --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/adv_simd.h @@ -0,0 +1,1281 @@ +// adv_simd.h - written and placed in the public domain by Jeffrey Walton + +/// \file adv_simd.h +/// \brief Template for AdvancedProcessBlocks and SIMD processing + +// The SIMD based implementations for ciphers that use SSE, NEON and Power7 +// have a common pattern. Namely, they have a specialized implementation of +// AdvancedProcessBlocks which processes multiple block using hardware +// acceleration. After several implementations we noticed a lot of copy and +// paste occurring. adv_simd.h provides a template to avoid the copy and paste. +// +// There are 6 templates provided in this file. The number following the +// function name, 128, is the block size in bits. The name following the +// block size is the arrangement and acceleration. For example 4x1_SSE means +// Intel SSE using two encrypt (or decrypt) functions: one that operates on +// 4 SIMD words, and one that operates on 1 SIMD words. +// +// * AdvancedProcessBlocks128_4x1_SSE +// * AdvancedProcessBlocks128_6x2_SSE +// * AdvancedProcessBlocks128_4x1_NEON +// * AdvancedProcessBlocks128_6x1_NEON +// * AdvancedProcessBlocks128_4x1_ALTIVEC +// * AdvancedProcessBlocks128_6x1_ALTIVEC +// +// If an arrangement ends in 2, like 6x2, then the template will handle the +// single block case by padding with 0's and using the two SIMD word +// function. This happens at most one time when processing multiple blocks. +// The extra processing of a zero block is trivial and worth the tradeoff. +// +// The MAYBE_CONST macro present on x86 is a SunCC workaround. Some versions +// of SunCC lose/drop the const-ness in the F1 and F4 functions. It eventually +// results in a failed link due to the const/non-const mismatch. +// +// In July 2020 the library stopped using 64-bit block version of +// AdvancedProcessBlocks. Testing showed unreliable results and failed +// self tests on occasion. Also see Issue 945 and +// https://github.com/weidai11/cryptopp/commit/dd7598e638bb. + +#ifndef CRYPTOPP_ADVANCED_SIMD_TEMPLATES +#define CRYPTOPP_ADVANCED_SIMD_TEMPLATES + +#include "config.h" +#include "misc.h" +#include "stdcpp.h" + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE) +# include +# include +#endif + +// SunCC needs CRYPTOPP_SSSE3_AVAILABLE, too +#if (CRYPTOPP_SSSE3_AVAILABLE) +# include +# include +# include +#endif + +#if defined(__ALTIVEC__) +# include "ppc_simd.h" +#endif + +// ************************ All block ciphers *********************** // + +ANONYMOUS_NAMESPACE_BEGIN + +using CryptoPP::BlockTransformation; + +CRYPTOPP_CONSTANT(BT_XorInput = BlockTransformation::BT_XorInput); +CRYPTOPP_CONSTANT(BT_AllowParallel = BlockTransformation::BT_AllowParallel); +CRYPTOPP_CONSTANT(BT_InBlockIsCounter = BlockTransformation::BT_InBlockIsCounter); +CRYPTOPP_CONSTANT(BT_ReverseDirection = BlockTransformation::BT_ReverseDirection); +CRYPTOPP_CONSTANT(BT_DontIncrementInOutPointers = BlockTransformation::BT_DontIncrementInOutPointers); + +ANONYMOUS_NAMESPACE_END + +// *************************** ARM NEON ************************** // + +#if (CRYPTOPP_ARM_NEON_AVAILABLE) || (CRYPTOPP_ARM_ASIMD_AVAILABLE) || \ + defined(CRYPTOPP_DOXYGEN_PROCESSING) +NAMESPACE_BEGIN(CryptoPP) + +/// \brief AdvancedProcessBlocks for 1 and 6 blocks +/// \tparam F1 function to process 1 128-bit block +/// \tparam F6 function to process 6 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_6x1_NEON processes 6 and 2 NEON SIMD words +/// at a time. +/// \details The subkey type is usually word32 or word64. F1 and F6 must use the +/// same word type. +template +inline size_t AdvancedProcessBlocks128_6x1_NEON(F1 func1, F6 func6, + const W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + + const unsigned int w_one[] = {0, 0<<24, 0, 1<<24}; + const uint32x4_t s_one = vld1q_u32(w_one); + + const size_t blockSize = 16; + // const size_t neonBlockSize = 16; + + size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput)); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput)); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*blockSize) + { + uint64x2_t block0, block1, block2, block3, block4, block5; + if (flags & BT_InBlockIsCounter) + { + const uint64x2_t one = vreinterpretq_u64_u32(s_one); + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + block1 = vaddq_u64(block0, one); + block2 = vaddq_u64(block1, one); + block3 = vaddq_u64(block2, one); + block4 = vaddq_u64(block3, one); + block5 = vaddq_u64(block4, one); + vst1q_u8(const_cast(inBlocks), + vreinterpretq_u8_u64(vaddq_u64(block5, one))); + } + else + { + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block4 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block5 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block0)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block1)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block2)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block3)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block4)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block5)); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 6*blockSize; + } + } + + while (length >= blockSize) + { + uint64x2_t block; + block = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + + if (xorInput) + block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, static_cast(rounds)); + + if (xorOutput) + block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block)); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +/// \brief AdvancedProcessBlocks for 1 and 4 blocks +/// \tparam F1 function to process 1 128-bit block +/// \tparam F4 function to process 4 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_4x1_NEON processes 4 and 1 NEON SIMD words +/// at a time. +/// \details The subkey type is usually word32 or word64. V is the vector type and it is +/// usually uint32x4_t or uint32x4_t. F1, F4, and W must use the same word and +/// vector type. +template +inline size_t AdvancedProcessBlocks128_4x1_NEON(F1 func1, F4 func4, + const W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + + const unsigned int w_one[] = {0, 0<<24, 0, 1<<24}; + const uint32x4_t s_one = vld1q_u32(w_one); + + const size_t blockSize = 16; + // const size_t neonBlockSize = 16; + + size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput)); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput)); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 4*blockSize) + { + uint32x4_t block0, block1, block2, block3; + if (flags & BT_InBlockIsCounter) + { + const uint32x4_t one = s_one; + block0 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + block1 = vreinterpretq_u32_u64(vaddq_u64(vreinterpretq_u64_u32(block0), vreinterpretq_u64_u32(one))); + block2 = vreinterpretq_u32_u64(vaddq_u64(vreinterpretq_u64_u32(block1), vreinterpretq_u64_u32(one))); + block3 = vreinterpretq_u32_u64(vaddq_u64(vreinterpretq_u64_u32(block2), vreinterpretq_u64_u32(one))); + vst1q_u8(const_cast(inBlocks), vreinterpretq_u8_u64(vaddq_u64( + vreinterpretq_u64_u32(block3), vreinterpretq_u64_u32(one)))); + } + else + { + block0 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = veorq_u32(block0, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u32(block1, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = veorq_u32(block2, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = veorq_u32(block3, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func4(block0, block1, block2, block3, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u32(block0, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u32(block1, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = veorq_u32(block2, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = veorq_u32(block3, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block0)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block1)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block2)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block3)); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 4*blockSize; + } + } + + while (length >= blockSize) + { + uint32x4_t block = vreinterpretq_u32_u8(vld1q_u8(inBlocks)); + + if (xorInput) + block = veorq_u32(block, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, static_cast(rounds)); + + if (xorOutput) + block = veorq_u32(block, vreinterpretq_u32_u8(vld1q_u8(xorBlocks))); + + vst1q_u8(outBlocks, vreinterpretq_u8_u32(block)); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +/// \brief AdvancedProcessBlocks for 2 and 6 blocks +/// \tparam F2 function to process 2 128-bit blocks +/// \tparam F6 function to process 6 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_6x2_NEON processes 6 and 2 NEON SIMD words +/// at a time. For a single block the template uses F2 with a zero block. +/// \details The subkey type is usually word32 or word64. F2 and F6 must use the +/// same word type. +template +inline size_t AdvancedProcessBlocks128_6x2_NEON(F2 func2, F6 func6, + const W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + + const unsigned int w_one[] = {0, 0<<24, 0, 1<<24}; + const uint32x4_t s_one = vld1q_u32(w_one); + + const size_t blockSize = 16; + // const size_t neonBlockSize = 16; + + size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput)); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput)); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*blockSize) + { + uint64x2_t block0, block1, block2, block3, block4, block5; + if (flags & BT_InBlockIsCounter) + { + const uint64x2_t one = vreinterpretq_u64_u32(s_one); + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + block1 = vaddq_u64(block0, one); + block2 = vaddq_u64(block1, one); + block3 = vaddq_u64(block2, one); + block4 = vaddq_u64(block3, one); + block5 = vaddq_u64(block4, one); + vst1q_u8(const_cast(inBlocks), + vreinterpretq_u8_u64(vaddq_u64(block5, one))); + } + else + { + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block4 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block5 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = veorq_u64(block2, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = veorq_u64(block3, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = veorq_u64(block4, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = veorq_u64(block5, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block0)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block1)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block2)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block3)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block4)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block5)); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 6*blockSize; + } + + while (length >= 2*blockSize) + { + uint64x2_t block0, block1; + if (flags & BT_InBlockIsCounter) + { + const uint64x2_t one = vreinterpretq_u64_u32(s_one); + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + block1 = vaddq_u64(block0, one); + vst1q_u8(const_cast(inBlocks), + vreinterpretq_u8_u64(vaddq_u64(block1, one))); + } + else + { + block0 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func2(block0, block1, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = veorq_u64(block0, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = veorq_u64(block1, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block0)); + outBlocks = PtrAdd(outBlocks, outIncrement); + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block1)); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 2*blockSize; + } + } + + while (length >= blockSize) + { + uint64x2_t block, zero = {0,0}; + block = vreinterpretq_u64_u8(vld1q_u8(inBlocks)); + + if (xorInput) + block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func2(block, zero, subKeys, static_cast(rounds)); + + if (xorOutput) + block = veorq_u64(block, vreinterpretq_u64_u8(vld1q_u8(xorBlocks))); + + vst1q_u8(outBlocks, vreinterpretq_u8_u64(block)); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_ARM_NEON_AVAILABLE + +// *************************** Intel SSE ************************** // + +#if defined(CRYPTOPP_SSSE3_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief SunCC workaround +/// \details SunCC loses the const on AES_Enc_Block and AES_Dec_Block +/// \sa Issue +/// 224, SunCC and failed compile for rijndael.cpp +# define MAYBE_CONST const +/// \brief SunCC workaround +/// \details SunCC loses the const on AES_Enc_Block and AES_Dec_Block +/// \sa Issue +/// 224, SunCC and failed compile for rijndael.cpp +# define MAYBE_UNCONST_CAST(T, x) (x) +#elif (__SUNPRO_CC >= 0x5130) +# define MAYBE_CONST +# define MAYBE_UNCONST_CAST(T, x) const_cast(x) +#else +# define MAYBE_CONST const +# define MAYBE_UNCONST_CAST(T, x) (x) +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Clang workaround +/// \details Clang issues spurious alignment warnings +/// \sa Issue +/// 20670, _mm_loadu_si128 parameter has wrong type +# define M128_CAST(x) ((__m128i *)(void *)(x)) +/// \brief Clang workaround +/// \details Clang issues spurious alignment warnings +/// \sa Issue +/// 20670, _mm_loadu_si128 parameter has wrong type +# define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) +#else +# ifndef M128_CAST +# define M128_CAST(x) ((__m128i *)(void *)(x)) +# endif +# ifndef CONST_M128_CAST +# define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief AdvancedProcessBlocks for 2 and 6 blocks +/// \tparam F2 function to process 2 128-bit blocks +/// \tparam F6 function to process 6 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_6x2_SSE processes 6 and 2 SSE SIMD words +/// at a time. For a single block the template uses F2 with a zero block. +/// \details The subkey type is usually word32 or word64. F2 and F6 must use the +/// same word type. +template +inline size_t AdvancedProcessBlocks128_6x2_SSE(F2 func2, F6 func6, + MAYBE_CONST W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + + const size_t blockSize = 16; + // const size_t xmmBlockSize = 16; + + size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput)); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput)); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*blockSize) + { + __m128i block0, block1, block2, block3, block4, block5; + if (flags & BT_InBlockIsCounter) + { + // Increment of 1 in big-endian compatible with the ctr byte array. + const __m128i s_one = _mm_set_epi32(1<<24, 0, 0, 0); + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + block1 = _mm_add_epi32(block0, s_one); + block2 = _mm_add_epi32(block1, s_one); + block3 = _mm_add_epi32(block2, s_one); + block4 = _mm_add_epi32(block3, s_one); + block5 = _mm_add_epi32(block4, s_one); + _mm_storeu_si128(M128_CAST(inBlocks), _mm_add_epi32(block5, s_one)); + } + else + { + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block4 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block5 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = _mm_xor_si128(block4, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = _mm_xor_si128(block5, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = _mm_xor_si128(block4, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = _mm_xor_si128(block5, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + _mm_storeu_si128(M128_CAST(outBlocks), block0); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block1); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block2); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block3); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block4); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block5); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 6*blockSize; + } + + while (length >= 2*blockSize) + { + __m128i block0, block1; + if (flags & BT_InBlockIsCounter) + { + // Increment of 1 in big-endian compatible with the ctr byte array. + const __m128i s_one = _mm_set_epi32(1<<24, 0, 0, 0); + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + block1 = _mm_add_epi32(block0, s_one); + _mm_storeu_si128(M128_CAST(inBlocks), _mm_add_epi32(block1, s_one)); + } + else + { + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func2(block0, block1, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + _mm_storeu_si128(M128_CAST(outBlocks), block0); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block1); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 2*blockSize; + } + } + + while (length >= blockSize) + { + __m128i block, zero = _mm_setzero_si128(); + block = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + + if (xorInput) + block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func2(block, zero, subKeys, static_cast(rounds)); + + if (xorOutput) + block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + + _mm_storeu_si128(M128_CAST(outBlocks), block); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +/// \brief AdvancedProcessBlocks for 1 and 4 blocks +/// \tparam F1 function to process 1 128-bit block +/// \tparam F4 function to process 4 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_4x1_SSE processes 4 and 1 SSE SIMD words +/// at a time. +/// \details The subkey type is usually word32 or word64. F1 and F4 must use the +/// same word type. +template +inline size_t AdvancedProcessBlocks128_4x1_SSE(F1 func1, F4 func4, + MAYBE_CONST W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + + const size_t blockSize = 16; + // const size_t xmmBlockSize = 16; + + size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput)); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput)); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 4*blockSize) + { + __m128i block0, block1, block2, block3; + if (flags & BT_InBlockIsCounter) + { + // Increment of 1 in big-endian compatible with the ctr byte array. + const __m128i s_one = _mm_set_epi32(1<<24, 0, 0, 0); + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + block1 = _mm_add_epi32(block0, s_one); + block2 = _mm_add_epi32(block1, s_one); + block3 = _mm_add_epi32(block2, s_one); + _mm_storeu_si128(M128_CAST(inBlocks), _mm_add_epi32(block3, s_one)); + } + else + { + block0 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func4(block0, block1, block2, block3, subKeys, static_cast(rounds)); + + if (xorOutput) + { + block0 = _mm_xor_si128(block0, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = _mm_xor_si128(block1, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = _mm_xor_si128(block2, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = _mm_xor_si128(block3, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + _mm_storeu_si128(M128_CAST(outBlocks), block0); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block1); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block2); + outBlocks = PtrAdd(outBlocks, outIncrement); + _mm_storeu_si128(M128_CAST(outBlocks), block3); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 4*blockSize; + } + } + + while (length >= blockSize) + { + __m128i block = _mm_loadu_si128(CONST_M128_CAST(inBlocks)); + + if (xorInput) + block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, static_cast(rounds)); + + if (xorOutput) + block = _mm_xor_si128(block, _mm_loadu_si128(CONST_M128_CAST(xorBlocks))); + + _mm_storeu_si128(M128_CAST(outBlocks), block); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_SSSE3_AVAILABLE + +// ************************** Altivec/Power 4 ************************** // + +#if defined(__ALTIVEC__) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief AdvancedProcessBlocks for 1 and 4 blocks +/// \tparam F1 function to process 1 128-bit block +/// \tparam F4 function to process 4 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_4x1_ALTIVEC processes 4 and 1 Altivec SIMD words +/// at a time. +/// \details The subkey type is usually word32 or word64. F1 and F4 must use the +/// same word type. +template +inline size_t AdvancedProcessBlocks128_4x1_ALTIVEC(F1 func1, F4 func4, + const W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + +#if (CRYPTOPP_LITTLE_ENDIAN) + const uint32x4_p s_one = {1,0,0,0}; +#else + const uint32x4_p s_one = {0,0,0,1}; +#endif + + const size_t blockSize = 16; + // const size_t simdBlockSize = 16; + + size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput)); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput)); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 4*blockSize) + { + uint32x4_p block0, block1, block2, block3; + + if (flags & BT_InBlockIsCounter) + { + block0 = VecLoadBE(inBlocks); + block1 = VecAdd(block0, s_one); + block2 = VecAdd(block1, s_one); + block3 = VecAdd(block2, s_one); + + // Hack due to big-endian loads used by POWER8 (and maybe ARM-BE). + // CTR_ModePolicy::OperateKeystream is wired such that after + // returning from this function CTR_ModePolicy will detect wrap on + // on the last counter byte and increment the next to last byte. + // The problem is, with a big-endian load, inBlocks[15] is really + // located at index 15. The vector addition using a 32-bit element + // generates a carry into inBlocks[14] and then CTR_ModePolicy + // increments inBlocks[14] too. + const_cast(inBlocks)[15] += 6; + } + else + { + block0 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = VecXor(block0, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = VecXor(block1, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = VecXor(block2, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = VecXor(block3, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func4(block0, block1, block2, block3, subKeys, rounds); + + if (xorOutput) + { + block0 = VecXor(block0, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = VecXor(block1, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = VecXor(block2, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = VecXor(block3, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + VecStoreBE(block0, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block1, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block2, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block3, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 4*blockSize; + } + } + + while (length >= blockSize) + { + uint32x4_p block = VecLoadBE(inBlocks); + + if (xorInput) + block = VecXor(block, VecLoadBE(xorBlocks)); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, rounds); + + if (xorOutput) + block = VecXor(block, VecLoadBE(xorBlocks)); + + VecStoreBE(block, outBlocks); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +/// \brief AdvancedProcessBlocks for 1 and 6 blocks +/// \tparam F1 function to process 1 128-bit block +/// \tparam F6 function to process 6 128-bit blocks +/// \tparam W word type of the subkey table +/// \details AdvancedProcessBlocks128_6x1_ALTIVEC processes 6 and 1 Altivec SIMD words +/// at a time. +/// \details The subkey type is usually word32 or word64. F1 and F6 must use the +/// same word type. +template +inline size_t AdvancedProcessBlocks128_6x1_ALTIVEC(F1 func1, F6 func6, + const W *subKeys, size_t rounds, const byte *inBlocks, + const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) +{ + CRYPTOPP_ASSERT(subKeys); + CRYPTOPP_ASSERT(inBlocks); + CRYPTOPP_ASSERT(outBlocks); + CRYPTOPP_ASSERT(length >= 16); + +#if (CRYPTOPP_LITTLE_ENDIAN) + const uint32x4_p s_one = {1,0,0,0}; +#else + const uint32x4_p s_one = {0,0,0,1}; +#endif + + const size_t blockSize = 16; + // const size_t simdBlockSize = 16; + + size_t inIncrement = (flags & (EnumToInt(BT_InBlockIsCounter)|EnumToInt(BT_DontIncrementInOutPointers))) ? 0 : blockSize; + size_t xorIncrement = (xorBlocks != NULLPTR) ? blockSize : 0; + size_t outIncrement = (flags & EnumToInt(BT_DontIncrementInOutPointers)) ? 0 : blockSize; + + // Clang and Coverity are generating findings using xorBlocks as a flag. + const bool xorInput = (xorBlocks != NULLPTR) && (flags & EnumToInt(BT_XorInput)); + const bool xorOutput = (xorBlocks != NULLPTR) && !(flags & EnumToInt(BT_XorInput)); + + if (flags & BT_ReverseDirection) + { + inBlocks = PtrAdd(inBlocks, length - blockSize); + xorBlocks = PtrAdd(xorBlocks, length - blockSize); + outBlocks = PtrAdd(outBlocks, length - blockSize); + inIncrement = 0-inIncrement; + xorIncrement = 0-xorIncrement; + outIncrement = 0-outIncrement; + } + + if (flags & BT_AllowParallel) + { + while (length >= 6*blockSize) + { + uint32x4_p block0, block1, block2, block3, block4, block5; + + if (flags & BT_InBlockIsCounter) + { + block0 = VecLoadBE(inBlocks); + block1 = VecAdd(block0, s_one); + block2 = VecAdd(block1, s_one); + block3 = VecAdd(block2, s_one); + block4 = VecAdd(block3, s_one); + block5 = VecAdd(block4, s_one); + + // Hack due to big-endian loads used by POWER8 (and maybe ARM-BE). + // CTR_ModePolicy::OperateKeystream is wired such that after + // returning from this function CTR_ModePolicy will detect wrap on + // on the last counter byte and increment the next to last byte. + // The problem is, with a big-endian load, inBlocks[15] is really + // located at index 15. The vector addition using a 32-bit element + // generates a carry into inBlocks[14] and then CTR_ModePolicy + // increments inBlocks[14] too. + // + // To find this bug we needed a test case with a ctr of 0xNN...FA. + // The last octet is 0xFA and adding 6 creates the wrap to trigger + // the issue. If the last octet was 0xFC then 4 would trigger it. + // We dumb-lucked into the test with SPECK-128. The test case of + // interest is the one with IV 348ECA9766C09F04 826520DE47A212FA. + uint8x16_p temp = VecAdd((uint8x16_p)block5, (uint8x16_p)s_one); + VecStoreBE(temp, const_cast(inBlocks)); + } + else + { + block0 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block1 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block2 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block3 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block4 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + block5 = VecLoadBE(inBlocks); + inBlocks = PtrAdd(inBlocks, inIncrement); + } + + if (xorInput) + { + block0 = VecXor(block0, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = VecXor(block1, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = VecXor(block2, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = VecXor(block3, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = VecXor(block4, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = VecXor(block5, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + func6(block0, block1, block2, block3, block4, block5, subKeys, rounds); + + if (xorOutput) + { + block0 = VecXor(block0, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block1 = VecXor(block1, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block2 = VecXor(block2, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block3 = VecXor(block3, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block4 = VecXor(block4, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + block5 = VecXor(block5, VecLoadBE(xorBlocks)); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + } + + VecStoreBE(block0, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block1, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block2, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block3, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block4, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + VecStoreBE(block5, outBlocks); + outBlocks = PtrAdd(outBlocks, outIncrement); + + length -= 6*blockSize; + } + } + + while (length >= blockSize) + { + uint32x4_p block = VecLoadBE(inBlocks); + + if (xorInput) + block = VecXor(block, VecLoadBE(xorBlocks)); + + if (flags & BT_InBlockIsCounter) + const_cast(inBlocks)[15]++; + + func1(block, subKeys, rounds); + + if (xorOutput) + block = VecXor(block, VecLoadBE(xorBlocks)); + + VecStoreBE(block, outBlocks); + + inBlocks = PtrAdd(inBlocks, inIncrement); + outBlocks = PtrAdd(outBlocks, outIncrement); + xorBlocks = PtrAdd(xorBlocks, xorIncrement); + length -= blockSize; + } + + return length; +} + +NAMESPACE_END // CryptoPP + +#endif // __ALTIVEC__ + +#endif // CRYPTOPP_ADVANCED_SIMD_TEMPLATES diff --git a/third_party/cryptoppwin/include/cryptopp/aes.h b/third_party/cryptoppwin/include/cryptopp/aes.h new file mode 100644 index 00000000..bcc5cf7e --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/aes.h @@ -0,0 +1,30 @@ +// aes.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Class file for the AES cipher (Rijndael) +/// \details AES is a typdef for Rijndael classes. All key sizes are supported. +/// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0 + +#ifndef CRYPTOPP_AES_H +#define CRYPTOPP_AES_H + +#include "rijndael.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief AES block cipher (Rijndael) +/// \details AES is a typdef for Rijndael classes. All key sizes are supported. +/// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks +/// \sa AES winner, announced on 10/2/2000 +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0 +DOCUMENTED_TYPEDEF(Rijndael, AES); + +typedef RijndaelEncryption AESEncryption; +typedef RijndaelDecryption AESDecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/aes_armv4.h b/third_party/cryptoppwin/include/cryptopp/aes_armv4.h new file mode 100644 index 00000000..000dfec9 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/aes_armv4.h @@ -0,0 +1,30 @@ +/* Header file for use with Cryptogam's ARMv4 AES. */ +/* Also see http://www.openssl.org/~appro/cryptogams/ and */ +/* https://wiki.openssl.org/index.php?title=Cryptogams_AES */ + +#ifndef CRYPTOGAMS_AES_ARMV4_H +#define CRYPTOGAMS_AES_ARMV4_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define AES_MAXNR 14 +//typedef struct AES_KEY_st { +// unsigned int rd_key[4 * (AES_MAXNR + 1)]; +// int rounds; +//} AES_KEY; + +// Instead of AES_KEY we use a 'word32 rkey[4*15+4]'. It has space for +// both the AES_MAXNR round keys and the number of rounds in the tail. + +int cryptogams_AES_set_encrypt_key(const unsigned char *userKey, const int bits, unsigned int *rkey); +int cryptogams_AES_set_decrypt_key(const unsigned char *userKey, const int bits, unsigned int *rkey); +void cryptogams_AES_encrypt_block(const unsigned char *in, unsigned char *out, const unsigned int *rkey); +void cryptogams_AES_decrypt_block(const unsigned char *in, unsigned char *out, const unsigned int *rkey); + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTOGAMS_AES_ARMV4_H */ diff --git a/third_party/cryptoppwin/include/cryptopp/algebra.h b/third_party/cryptoppwin/include/cryptopp/algebra.h new file mode 100644 index 00000000..1e04dfff --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/algebra.h @@ -0,0 +1,453 @@ +// algebra.h - originally written and placed in the public domain by Wei Dai + +/// \file algebra.h +/// \brief Classes for performing mathematics over different fields + +#ifndef CRYPTOPP_ALGEBRA_H +#define CRYPTOPP_ALGEBRA_H + +#include "config.h" +#include "integer.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +class Integer; + +/// \brief Abstract group +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///

    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class CRYPTOPP_NO_VTABLE AbstractGroup +{ +public: + typedef T Element; + + virtual ~AbstractGroup() {} + + /// \brief Compare two elements for equality + /// \param a first element + /// \param b second element + /// \return true if the elements are equal, false otherwise + /// \details Equal() tests the elements for equality using a==b + virtual bool Equal(const Element &a, const Element &b) const =0; + + /// \brief Provides the Identity element + /// \return the Identity element + virtual const Element& Identity() const =0; + + /// \brief Adds elements in the group + /// \param a first element + /// \param b second element + /// \return the sum of a and b + virtual const Element& Add(const Element &a, const Element &b) const =0; + + /// \brief Inverts the element in the group + /// \param a first element + /// \return the inverse of the element + virtual const Element& Inverse(const Element &a) const =0; + + /// \brief Determine if inversion is fast + /// \return true if inversion is fast, false otherwise + virtual bool InversionIsFast() const {return false;} + + /// \brief Doubles an element in the group + /// \param a the element + /// \return the element doubled + virtual const Element& Double(const Element &a) const; + + /// \brief Subtracts elements in the group + /// \param a first element + /// \param b second element + /// \return the difference of a and b. The element a must provide a Subtract member function. + virtual const Element& Subtract(const Element &a, const Element &b) const; + + /// \brief TODO + /// \param a first element + /// \param b second element + /// \return TODO + virtual Element& Accumulate(Element &a, const Element &b) const; + + /// \brief Reduces an element in the congruence class + /// \param a element to reduce + /// \param b the congruence class + /// \return the reduced element + virtual Element& Reduce(Element &a, const Element &b) const; + + /// \brief Performs a scalar multiplication + /// \param a multiplicand + /// \param e multiplier + /// \return the product + virtual Element ScalarMultiply(const Element &a, const Integer &e) const; + + /// \brief TODO + /// \param x first multiplicand + /// \param e1 the first multiplier + /// \param y second multiplicand + /// \param e2 the second multiplier + /// \return TODO + virtual Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const; + + /// \brief Multiplies a base to multiple exponents in a group + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousMultiply() multiplies the base to each exponent in the exponents array and stores the + /// result at the respective position in the results array. + /// \details SimultaneousMultiply() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + virtual void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; +}; + +/// \brief Abstract ring +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class CRYPTOPP_NO_VTABLE AbstractRing : public AbstractGroup +{ +public: + typedef T Element; + + /// \brief Construct an AbstractRing + AbstractRing() {m_mg.m_pRing = this;} + + /// \brief Copy construct an AbstractRing + /// \param source other AbstractRing + AbstractRing(const AbstractRing &source) + {CRYPTOPP_UNUSED(source); m_mg.m_pRing = this;} + + /// \brief Assign an AbstractRing + /// \param source other AbstractRing + AbstractRing& operator=(const AbstractRing &source) + {CRYPTOPP_UNUSED(source); return *this;} + + /// \brief Determines whether an element is a unit in the group + /// \param a the element + /// \return true if the element is a unit after reduction, false otherwise. + virtual bool IsUnit(const Element &a) const =0; + + /// \brief Retrieves the multiplicative identity + /// \return the multiplicative identity + virtual const Element& MultiplicativeIdentity() const =0; + + /// \brief Multiplies elements in the group + /// \param a the multiplicand + /// \param b the multiplier + /// \return the product of a and b + virtual const Element& Multiply(const Element &a, const Element &b) const =0; + + /// \brief Calculate the multiplicative inverse of an element in the group + /// \param a the element + virtual const Element& MultiplicativeInverse(const Element &a) const =0; + + /// \brief Square an element in the group + /// \param a the element + /// \return the element squared + virtual const Element& Square(const Element &a) const; + + /// \brief Divides elements in the group + /// \param a the dividend + /// \param b the divisor + /// \return the quotient + virtual const Element& Divide(const Element &a, const Element &b) const; + + /// \brief Raises a base to an exponent in the group + /// \param a the base + /// \param e the exponent + /// \return the exponentiation + virtual Element Exponentiate(const Element &a, const Integer &e) const; + + /// \brief TODO + /// \param x first element + /// \param e1 first exponent + /// \param y second element + /// \param e2 second exponent + /// \return TODO + virtual Element CascadeExponentiate(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const; + + /// \brief Exponentiates a base to multiple exponents in the Ring + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the + /// result at the respective position in the results array. + /// \details SimultaneousExponentiate() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + virtual void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + + /// \brief Retrieves the multiplicative group + /// \return the multiplicative group + virtual const AbstractGroup& MultiplicativeGroup() const + {return m_mg;} + +private: + class MultiplicativeGroupT : public AbstractGroup + { + public: + const AbstractRing& GetRing() const + {return *m_pRing;} + + bool Equal(const Element &a, const Element &b) const + {return GetRing().Equal(a, b);} + + const Element& Identity() const + {return GetRing().MultiplicativeIdentity();} + + const Element& Add(const Element &a, const Element &b) const + {return GetRing().Multiply(a, b);} + + Element& Accumulate(Element &a, const Element &b) const + {return a = GetRing().Multiply(a, b);} + + const Element& Inverse(const Element &a) const + {return GetRing().MultiplicativeInverse(a);} + + const Element& Subtract(const Element &a, const Element &b) const + {return GetRing().Divide(a, b);} + + Element& Reduce(Element &a, const Element &b) const + {return a = GetRing().Divide(a, b);} + + const Element& Double(const Element &a) const + {return GetRing().Square(a);} + + Element ScalarMultiply(const Element &a, const Integer &e) const + {return GetRing().Exponentiate(a, e);} + + Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const + {return GetRing().CascadeExponentiate(x, e1, y, e2);} + + void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const + {GetRing().SimultaneousExponentiate(results, base, exponents, exponentsCount);} + + const AbstractRing *m_pRing; + }; + + MultiplicativeGroupT m_mg; +}; + +// ******************************************************** + +/// \brief Base and exponent +/// \tparam T base class or type +/// \tparam E exponent class or type +template +struct BaseAndExponent +{ +public: + BaseAndExponent() {} + BaseAndExponent(const T &base, const E &exponent) : base(base), exponent(exponent) {} + bool operator<(const BaseAndExponent &rhs) const {return exponent < rhs.exponent;} + T base; + E exponent; +}; + +// VC60 workaround: incomplete member template support +template + Element GeneralCascadeMultiplication(const AbstractGroup &group, Iterator begin, Iterator end); +template + Element GeneralCascadeExponentiation(const AbstractRing &ring, Iterator begin, Iterator end); + +// ******************************************************** + +/// \brief Abstract Euclidean domain +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class CRYPTOPP_NO_VTABLE AbstractEuclideanDomain : public AbstractRing +{ +public: + typedef T Element; + + /// \brief Performs the division algorithm on two elements in the ring + /// \param r the remainder + /// \param q the quotient + /// \param a the dividend + /// \param d the divisor + virtual void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const =0; + + /// \brief Performs a modular reduction in the ring + /// \param a the element + /// \param b the modulus + /// \return the result of a%b. + virtual const Element& Mod(const Element &a, const Element &b) const =0; + + /// \brief Calculates the greatest common denominator in the ring + /// \param a the first element + /// \param b the second element + /// \return the greatest common denominator of a and b. + virtual const Element& Gcd(const Element &a, const Element &b) const; + +protected: + mutable Element result; +}; + +// ******************************************************** + +/// \brief Euclidean domain +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class EuclideanDomainOf : public AbstractEuclideanDomain +{ +public: + typedef T Element; + + EuclideanDomainOf() {} + + bool Equal(const Element &a, const Element &b) const + {return a==b;} + + const Element& Identity() const + {return Element::Zero();} + + const Element& Add(const Element &a, const Element &b) const + {return result = a+b;} + + Element& Accumulate(Element &a, const Element &b) const + {return a+=b;} + + const Element& Inverse(const Element &a) const + {return result = -a;} + + const Element& Subtract(const Element &a, const Element &b) const + {return result = a-b;} + + Element& Reduce(Element &a, const Element &b) const + {return a-=b;} + + const Element& Double(const Element &a) const + {return result = a.Doubled();} + + const Element& MultiplicativeIdentity() const + {return Element::One();} + + const Element& Multiply(const Element &a, const Element &b) const + {return result = a*b;} + + const Element& Square(const Element &a) const + {return result = a.Squared();} + + bool IsUnit(const Element &a) const + {return a.IsUnit();} + + const Element& MultiplicativeInverse(const Element &a) const + {return result = a.MultiplicativeInverse();} + + const Element& Divide(const Element &a, const Element &b) const + {return result = a/b;} + + const Element& Mod(const Element &a, const Element &b) const + {return result = a%b;} + + void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const + {Element::Divide(r, q, a, d);} + + bool operator==(const EuclideanDomainOf &rhs) const + {CRYPTOPP_UNUSED(rhs); return true;} + +private: + mutable Element result; +}; + +/// \brief Quotient ring +/// \tparam T element class or type +/// \details const Element& returned by member functions are references +/// to internal data members. Since each object may have only +/// one such data member for holding results, the following code +/// will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+template class QuotientRing : public AbstractRing +{ +public: + typedef T EuclideanDomain; + typedef typename T::Element Element; + + QuotientRing(const EuclideanDomain &domain, const Element &modulus) + : m_domain(domain), m_modulus(modulus) {} + + const EuclideanDomain & GetDomain() const + {return m_domain;} + + const Element& GetModulus() const + {return m_modulus;} + + bool Equal(const Element &a, const Element &b) const + {return m_domain.Equal(m_domain.Mod(m_domain.Subtract(a, b), m_modulus), m_domain.Identity());} + + const Element& Identity() const + {return m_domain.Identity();} + + const Element& Add(const Element &a, const Element &b) const + {return m_domain.Add(a, b);} + + Element& Accumulate(Element &a, const Element &b) const + {return m_domain.Accumulate(a, b);} + + const Element& Inverse(const Element &a) const + {return m_domain.Inverse(a);} + + const Element& Subtract(const Element &a, const Element &b) const + {return m_domain.Subtract(a, b);} + + Element& Reduce(Element &a, const Element &b) const + {return m_domain.Reduce(a, b);} + + const Element& Double(const Element &a) const + {return m_domain.Double(a);} + + bool IsUnit(const Element &a) const + {return m_domain.IsUnit(m_domain.Gcd(a, m_modulus));} + + const Element& MultiplicativeIdentity() const + {return m_domain.MultiplicativeIdentity();} + + const Element& Multiply(const Element &a, const Element &b) const + {return m_domain.Mod(m_domain.Multiply(a, b), m_modulus);} + + const Element& Square(const Element &a) const + {return m_domain.Mod(m_domain.Square(a), m_modulus);} + + const Element& MultiplicativeInverse(const Element &a) const; + + bool operator==(const QuotientRing &rhs) const + {return m_domain == rhs.m_domain && m_modulus == rhs.m_modulus;} + +protected: + EuclideanDomain m_domain; + Element m_modulus; +}; + +NAMESPACE_END + +#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#include "algebra.cpp" +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/algparam.h b/third_party/cryptoppwin/include/cryptopp/algparam.h new file mode 100644 index 00000000..72dae198 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/algparam.h @@ -0,0 +1,520 @@ +// algparam.h - originally written and placed in the public domain by Wei Dai + +/// \file algparam.h +/// \brief Classes for working with NameValuePairs + +#ifndef CRYPTOPP_ALGPARAM_H +#define CRYPTOPP_ALGPARAM_H + +#include "config.h" +#include "cryptlib.h" + +#include "smartptr.h" +#include "secblock.h" +#include "integer.h" +#include "misc.h" + +#include +#include +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Used to pass byte array input as part of a NameValuePairs object +class ConstByteArrayParameter +{ +public: + /// \brief Construct a ConstByteArrayParameter + /// \param data a C-String + /// \param deepCopy flag indicating whether the data should be copied + /// \details The deepCopy option is used when the NameValuePairs object can't + /// keep a copy of the data available + ConstByteArrayParameter(const char *data = NULLPTR, bool deepCopy = false) + : m_deepCopy(false), m_data(NULLPTR), m_size(0) + { + Assign(reinterpret_cast(data), data ? strlen(data) : 0, deepCopy); + } + + /// \brief Construct a ConstByteArrayParameter + /// \param data a memory buffer + /// \param size the length of the memory buffer + /// \param deepCopy flag indicating whether the data should be copied + /// \details The deepCopy option is used when the NameValuePairs object can't + /// keep a copy of the data available + ConstByteArrayParameter(const byte *data, size_t size, bool deepCopy = false) + : m_deepCopy(false), m_data(NULLPTR), m_size(0) + { + Assign(data, size, deepCopy); + } + + /// \brief Construct a ConstByteArrayParameter + /// \tparam T a std::basic_string or std::vector class + /// \param string a std::basic_string or std::vector object + /// \param deepCopy flag indicating whether the data should be copied + /// \details The deepCopy option is used when the NameValuePairs object can't + /// keep a copy of the data available + template ConstByteArrayParameter(const T &string, bool deepCopy = false) + : m_deepCopy(false), m_data(NULLPTR), m_size(0) + { + CRYPTOPP_COMPILE_ASSERT(sizeof(typename T::value_type) == 1); + Assign(reinterpret_cast(&string[0]), string.size(), deepCopy); + } + + /// \brief Assign contents from a memory buffer + /// \param data a memory buffer + /// \param size the length of the memory buffer + /// \param deepCopy flag indicating whether the data should be copied + /// \details The deepCopy option is used when the NameValuePairs object can't + /// keep a copy of the data available + void Assign(const byte *data, size_t size, bool deepCopy) + { + // This fires, which means: no data with a size, or data with no size. + // CRYPTOPP_ASSERT((data && size) || !(data || size)); + if (deepCopy) + m_block.Assign(data, size); + else + { + m_data = data; + m_size = size; + } + m_deepCopy = deepCopy; + } + + /// \brief Pointer to the first byte in the memory block + const byte *begin() const {return m_deepCopy ? m_block.begin() : m_data;} + /// \brief Pointer beyond the last byte in the memory block + const byte *end() const {return m_deepCopy ? m_block.end() : m_data + m_size;} + /// \brief Length of the memory block + size_t size() const {return m_deepCopy ? m_block.size() : m_size;} + +private: + bool m_deepCopy; + const byte *m_data; + size_t m_size; + SecByteBlock m_block; +}; + +/// \brief Used to pass byte array input as part of a NameValuePairs object +class ByteArrayParameter +{ +public: + /// \brief Construct a ByteArrayParameter + /// \param data a memory buffer + /// \param size the length of the memory buffer + ByteArrayParameter(byte *data = NULLPTR, unsigned int size = 0) + : m_data(data), m_size(size) {} + + /// \brief Construct a ByteArrayParameter + /// \param block a SecByteBlock + ByteArrayParameter(SecByteBlock &block) + : m_data(block.begin()), m_size(block.size()) {} + + /// \brief Pointer to the first byte in the memory block + byte *begin() const {return m_data;} + /// \brief Pointer beyond the last byte in the memory block + byte *end() const {return m_data + m_size;} + /// \brief Length of the memory block + size_t size() const {return m_size;} + +private: + byte *m_data; + size_t m_size; +}; + +/// \brief Combines two sets of NameValuePairs +/// \details CombinedNameValuePairs allows you to provide two sets of of NameValuePairs. +/// If a name is not found in the first set, then the second set is searched for the +/// name and value pair. The second set of NameValuePairs often provides default values. +class CRYPTOPP_DLL CombinedNameValuePairs : public NameValuePairs +{ +public: + /// \brief Construct a CombinedNameValuePairs + /// \param pairs1 reference to the first set of NameValuePairs + /// \param pairs2 reference to the second set of NameValuePairs + CombinedNameValuePairs(const NameValuePairs &pairs1, const NameValuePairs &pairs2) + : m_pairs1(pairs1), m_pairs2(pairs2) {} + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + +private: + const NameValuePairs &m_pairs1, &m_pairs2; +}; + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +template +class GetValueHelperClass +{ +public: + GetValueHelperClass(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst) + : m_pObject(pObject), m_name(name), m_valueType(&valueType), m_pValue(pValue), m_found(false), m_getValueNames(false) + { + if (strcmp(m_name, "ValueNames") == 0) + { + m_found = m_getValueNames = true; + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(std::string), *m_valueType); + if (searchFirst) + searchFirst->GetVoidValue(m_name, valueType, pValue); + if (typeid(T) != typeid(BASE)) + pObject->BASE::GetVoidValue(m_name, valueType, pValue); + ((*reinterpret_cast(m_pValue) += "ThisPointer:") += typeid(T).name()) += ';'; + } + + if (!m_found && strncmp(m_name, "ThisPointer:", 12) == 0 && strcmp(m_name+12, typeid(T).name()) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T *), *m_valueType); + *reinterpret_cast(pValue) = pObject; + m_found = true; + return; + } + + if (!m_found && searchFirst) + m_found = searchFirst->GetVoidValue(m_name, valueType, pValue); + + if (!m_found && typeid(T) != typeid(BASE)) + m_found = pObject->BASE::GetVoidValue(m_name, valueType, pValue); + } + + operator bool() const {return m_found;} + + template + GetValueHelperClass & operator()(const char *name, const R & (T::*pm)() const) + { + if (m_getValueNames) + (*reinterpret_cast(m_pValue) += name) += ";"; + if (!m_found && strcmp(name, m_name) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(name, typeid(R), *m_valueType); + *reinterpret_cast(m_pValue) = (m_pObject->*pm)(); + m_found = true; + } + return *this; + } + + GetValueHelperClass &Assignable() + { +#ifndef __INTEL_COMPILER // ICL 9.1 workaround: Intel compiler copies the vTable pointer for some reason + if (m_getValueNames) + ((*reinterpret_cast(m_pValue) += "ThisObject:") += typeid(T).name()) += ';'; + if (!m_found && strncmp(m_name, "ThisObject:", 11) == 0 && strcmp(m_name+11, typeid(T).name()) == 0) + { + NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T), *m_valueType); + *reinterpret_cast(m_pValue) = *m_pObject; + m_found = true; + } +#endif + return *this; + } + +private: + const T *m_pObject; + const char *m_name; + const std::type_info *m_valueType; + void *m_pValue; + bool m_found, m_getValueNames; +}; + +template +GetValueHelperClass GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR) +{ + return GetValueHelperClass(pObject, name, valueType, pValue, searchFirst); +} + +template +GetValueHelperClass GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR) +{ + return GetValueHelperClass(pObject, name, valueType, pValue, searchFirst); +} + +// ******************************************************** + +template +class AssignFromHelperClass +{ +public: + AssignFromHelperClass(T *pObject, const NameValuePairs &source) + : m_pObject(pObject), m_source(source), m_done(false) + { + if (source.GetThisObject(*pObject)) + m_done = true; + else if (typeid(BASE) != typeid(T)) + pObject->BASE::AssignFrom(source); + } + + template + AssignFromHelperClass & operator()(const char *name, void (T::*pm)(const R&)) + { + if (!m_done) + { + R value; + if (!m_source.GetValue(name, value)) + throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name + "'"); + (m_pObject->*pm)(value); + } + return *this; + } + + template + AssignFromHelperClass & operator()(const char *name1, const char *name2, void (T::*pm)(const R&, const S&)) + { + if (!m_done) + { + R value1; + if (!m_source.GetValue(name1, value1)) + throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name1 + "'"); + S value2; + if (!m_source.GetValue(name2, value2)) + throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name2 + "'"); + (m_pObject->*pm)(value1, value2); + } + return *this; + } + +private: + T *m_pObject; + const NameValuePairs &m_source; + bool m_done; +}; + +template +AssignFromHelperClass AssignFromHelper(T *pObject, const NameValuePairs &source) +{ + return AssignFromHelperClass(pObject, source); +} + +template +AssignFromHelperClass AssignFromHelper(T *pObject, const NameValuePairs &source) +{ + return AssignFromHelperClass(pObject, source); +} + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +// ******************************************************** + +#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER +// Allow the linker to discard Integer code if not needed. +// Also see http://github.com/weidai11/cryptopp/issues/389. +CRYPTOPP_DLL bool AssignIntToInteger(const std::type_info &valueType, void *pInteger, const void *pInt); +#endif + +CRYPTOPP_DLL const std::type_info & CRYPTOPP_API IntegerTypeId(); + +/// \brief Base class for AlgorithmParameters +class CRYPTOPP_DLL AlgorithmParametersBase +{ +public: + /// \brief Exception thrown when an AlgorithmParameter is unused + class ParameterNotUsed : public Exception + { + public: + ParameterNotUsed(const char *name) : Exception(OTHER_ERROR, std::string("AlgorithmParametersBase: parameter \"") + name + "\" not used") {} + }; + + virtual ~AlgorithmParametersBase() CRYPTOPP_THROW + { + +#if defined(CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS) + if (std::uncaught_exceptions() == 0) +#elif defined(CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION) + if (std::uncaught_exception() == false) +#else + try +#endif + { + if (m_throwIfNotUsed && !m_used) + throw ParameterNotUsed(m_name); + } +#if !defined(CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION) +# if !defined(CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS) + catch(const Exception&) + { + } +# endif +#endif + } + + // this is actually a move, not a copy + AlgorithmParametersBase(const AlgorithmParametersBase &x) + : m_name(x.m_name), m_throwIfNotUsed(x.m_throwIfNotUsed), m_used(x.m_used) + { + m_next.reset(const_cast(x).m_next.release()); + x.m_used = true; + } + + /// \brief Construct a AlgorithmParametersBase + /// \param name the parameter name + /// \param throwIfNotUsed flags indicating whether an exception should be thrown + /// \details If throwIfNotUsed is true, then a ParameterNotUsed exception + /// will be thrown in the destructor if the parameter is not not retrieved. + AlgorithmParametersBase(const char *name, bool throwIfNotUsed) + : m_name(name), m_throwIfNotUsed(throwIfNotUsed), m_used(false) {} + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + +protected: + friend class AlgorithmParameters; + void operator=(const AlgorithmParametersBase& rhs); // assignment not allowed, declare this for VC60 + + virtual void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const =0; + virtual void MoveInto(void *p) const =0; // not really const + + const char *m_name; + bool m_throwIfNotUsed; + mutable bool m_used; + member_ptr m_next; +}; + +/// \brief Template base class for AlgorithmParameters +/// \tparam T the class or type +template +class AlgorithmParametersTemplate : public AlgorithmParametersBase +{ +public: + /// \brief Construct an AlgorithmParametersTemplate + /// \param name the name of the value + /// \param value a reference to the value + /// \param throwIfNotUsed flags indicating whether an exception should be thrown + /// \details If throwIfNotUsed is true, then a ParameterNotUsed exception + /// will be thrown in the destructor if the parameter is not not retrieved. + AlgorithmParametersTemplate(const char *name, const T &value, bool throwIfNotUsed) + : AlgorithmParametersBase(name, throwIfNotUsed), m_value(value) + { + } + + void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const + { +#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER + // Special case for retrieving an Integer parameter when an int was passed in + if (!(typeid(T) == typeid(int) && AssignIntToInteger(valueType, pValue, &m_value))) +#endif + { + NameValuePairs::ThrowIfTypeMismatch(name, typeid(T), valueType); + *reinterpret_cast(pValue) = m_value; + } + } + +#if defined(DEBUG_NEW) && (CRYPTOPP_MSC_VERSION >= 1300) +# pragma push_macro("new") +# undef new +#endif + + void MoveInto(void *buffer) const + { + AlgorithmParametersTemplate* p = new(buffer) AlgorithmParametersTemplate(*this); + CRYPTOPP_UNUSED(p); // silence warning + } + +#if defined(DEBUG_NEW) && (CRYPTOPP_MSC_VERSION >= 1300) +# pragma pop_macro("new") +#endif + +protected: + T m_value; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate; +CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate; +CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate; + +/// \brief An object that implements NameValuePairs +/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by +/// repeatedly using operator() on the object returned by MakeParameters, for example: +///
+///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+///   
+class CRYPTOPP_DLL AlgorithmParameters : public NameValuePairs +{ +public: + /// \brief Construct a AlgorithmParameters + /// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by + /// repeatedly using operator() on the object returned by MakeParameters, for example: + ///
+	///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+	///   
+ AlgorithmParameters(); + +#ifdef __BORLANDC__ + /// \brief Construct a AlgorithmParameters + /// \tparam T the class or type + /// \param name the name of the object or value to retrieve + /// \param value reference to a variable that receives the value + /// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed + /// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(), + /// such as MSVC 7.0 and earlier. + /// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by + /// repeatedly using operator() on the object returned by MakeParameters, for example: + ///
+	///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+	///   
+ template + AlgorithmParameters(const char *name, const T &value, bool throwIfNotUsed=true) + : m_next(new AlgorithmParametersTemplate(name, value, throwIfNotUsed)) + , m_defaultThrowIfNotUsed(throwIfNotUsed) + { + } +#endif + + AlgorithmParameters(const AlgorithmParameters &x); + + AlgorithmParameters & operator=(const AlgorithmParameters &x); + + /// \tparam T the class or type + /// \param name the name of the object or value to retrieve + /// \param value reference to a variable that receives the value + /// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed + template + AlgorithmParameters & operator()(const char *name, const T &value, bool throwIfNotUsed) + { + member_ptr p(new AlgorithmParametersTemplate(name, value, throwIfNotUsed)); + p->m_next.reset(m_next.release()); + m_next.reset(p.release()); + m_defaultThrowIfNotUsed = throwIfNotUsed; + return *this; + } + + /// \brief Appends a NameValuePair to a collection of NameValuePairs + /// \tparam T the class or type + /// \param name the name of the object or value to retrieve + /// \param value reference to a variable that receives the value + template + AlgorithmParameters & operator()(const char *name, const T &value) + { + return operator()(name, value, m_defaultThrowIfNotUsed); + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + +protected: + member_ptr m_next; + bool m_defaultThrowIfNotUsed; +}; + +/// \brief Create an object that implements NameValuePairs +/// \tparam T the class or type +/// \param name the name of the object or value to retrieve +/// \param value reference to a variable that receives the value +/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed +/// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(), +/// such as MSVC 7.0 and earlier. +/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by +/// repeatedly using \p operator() on the object returned by \p MakeParameters, for example: +///
+///     AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
+///   
+#ifdef __BORLANDC__ +typedef AlgorithmParameters MakeParameters; +#else +template +AlgorithmParameters MakeParameters(const char *name, const T &value, bool throwIfNotUsed = true) +{ + return AlgorithmParameters()(name, value, throwIfNotUsed); +} +#endif + +#define CRYPTOPP_GET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Get##name) +#define CRYPTOPP_SET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Set##name) +#define CRYPTOPP_SET_FUNCTION_ENTRY2(name1, name2) (Name::name1(), Name::name2(), &ThisClass::Set##name1##And##name2) + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/allocate.h b/third_party/cryptoppwin/include/cryptopp/allocate.h new file mode 100644 index 00000000..b106b078 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/allocate.h @@ -0,0 +1,74 @@ +// allocate.h - written and placed in the public domain by Jeffrey Walton + +// The functions in allocate.h and allocate.cpp were originally in misc.h +// and misc.cpp. They were extracted in September 2019 to sidestep a circular +// dependency with misc.h and secblock.h. + +/// \file allocate.h +/// \brief Functions for allocating aligned buffers + +#ifndef CRYPTOPP_ALLOCATE_H +#define CRYPTOPP_ALLOCATE_H + +#include "config.h" +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Attempts to reclaim unused memory +/// \throw bad_alloc +/// \details In the normal course of running a program, a request for memory +/// normally succeeds. If a call to AlignedAllocate or UnalignedAllocate fails, +/// then CallNewHandler is called in n effort to recover. Internally, +/// CallNewHandler calls set_new_handler(nullptr) in an effort to free memory. +/// There is no guarantee CallNewHandler will be able to obtain more memory so +/// an allocation succeeds. If the call to set_new_handler fails, then CallNewHandler +/// throws a bad_alloc exception. +/// \throw bad_alloc on failure +/// \since Crypto++ 5.0 +/// \sa AlignedAllocate, AlignedDeallocate, UnalignedAllocate, UnalignedDeallocate +CRYPTOPP_DLL void CRYPTOPP_API CallNewHandler(); + +/// \brief Allocates a buffer on 16-byte boundary +/// \param size the size of the buffer +/// \details AlignedAllocate is primarily used when the data will be +/// processed by SSE, NEON, ARMv8 or PowerPC instructions. The assembly +/// language routines rely on the alignment. If the alignment is not +/// respected, then a SIGBUS could be generated on Unix and Linux, and an +/// EXCEPTION_DATATYPE_MISALIGNMENT could be generated on Windows. +/// \details Formerly, AlignedAllocate and AlignedDeallocate were only +/// available on certain platforms when CRYTPOPP_DISABLE_ASM was not in +/// effect. However, Android and iOS debug simulator builds got into a +/// state where the aligned allocator was not available and caused link +/// failures. +/// \since AlignedAllocate for SIMD since Crypto++ 1.0, AlignedAllocate +/// for all builds since Crypto++ 8.1 +/// \sa AlignedDeallocate, UnalignedAllocate, UnalignedDeallocate, CallNewHandler, +/// Issue 779 +CRYPTOPP_DLL void* CRYPTOPP_API AlignedAllocate(size_t size); + +/// \brief Frees a buffer allocated with AlignedAllocate +/// \param ptr the buffer to free +/// \since AlignedDeallocate for SIMD since Crypto++ 1.0, AlignedAllocate +/// for all builds since Crypto++ 8.1 +/// \sa AlignedAllocate, UnalignedAllocate, UnalignedDeallocate, CallNewHandler, +/// Issue 779 +CRYPTOPP_DLL void CRYPTOPP_API AlignedDeallocate(void *ptr); + +/// \brief Allocates a buffer +/// \param size the size of the buffer +/// \since Crypto++ 1.0 +/// \sa AlignedAllocate, AlignedDeallocate, UnalignedDeallocate, CallNewHandler, +/// Issue 779 +CRYPTOPP_DLL void * CRYPTOPP_API UnalignedAllocate(size_t size); + +/// \brief Frees a buffer allocated with UnalignedAllocate +/// \param ptr the buffer to free +/// \since Crypto++ 1.0 +/// \sa AlignedAllocate, AlignedDeallocate, UnalignedAllocate, CallNewHandler, +/// Issue 779 +CRYPTOPP_DLL void CRYPTOPP_API UnalignedDeallocate(void *ptr); + +NAMESPACE_END + +#endif // CRYPTOPP_ALLOCATE_H diff --git a/third_party/cryptoppwin/include/cryptopp/arc4.h b/third_party/cryptoppwin/include/cryptopp/arc4.h new file mode 100644 index 00000000..ca444ce4 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/arc4.h @@ -0,0 +1,89 @@ +// arc4.h - originally written and placed in the public domain by Wei Dai + +/// \file arc4.h +/// \brief Classes for ARC4 cipher +/// \since Crypto++ 3.1 + +#ifndef CRYPTOPP_ARC4_H +#define CRYPTOPP_ARC4_H + +#include "cryptlib.h" +#include "strciphr.h" +#include "secblock.h" +#include "smartptr.h" + +NAMESPACE_BEGIN(CryptoPP) + +namespace Weak1 { + +/// \brief ARC4 base class +/// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions +/// \since Crypto++ 3.1 +class CRYPTOPP_NO_VTABLE ARC4_Base : public VariableKeyLength<16, 1, 256>, public RandomNumberGenerator, public SymmetricCipher, public SymmetricCipherDocumentation +{ +public: + ~ARC4_Base(); + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ARC4";} + + void GenerateBlock(byte *output, size_t size); + void DiscardBytes(size_t n); + + void ProcessData(byte *outString, const byte *inString, size_t length); + + bool IsRandomAccess() const {return false;} + bool IsSelfInverting() const {return true;} + bool IsForwardTransformation() const {return true;} + + typedef SymmetricCipherFinal Encryption; + typedef SymmetricCipherFinal Decryption; + +protected: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + virtual unsigned int GetDefaultDiscardBytes() const {return 0;} + + FixedSizeSecBlock m_state; + byte m_x, m_y; +}; + +/// \brief Alleged RC4 +/// \sa Alleged RC4 +/// \since Crypto++ 3.1 +DOCUMENTED_TYPEDEF(SymmetricCipherFinal, ARC4); + +/// \brief MARC4 base class +/// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions +/// \details MARC4 discards the first 256 bytes of keystream, which may be weaker than the rest +/// \since Crypto++ 3.1 +class CRYPTOPP_NO_VTABLE MARC4_Base : public ARC4_Base +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MARC4";} + + typedef SymmetricCipherFinal Encryption; + typedef SymmetricCipherFinal Decryption; + +protected: + unsigned int GetDefaultDiscardBytes() const {return 256;} +}; + +/// \brief Modified Alleged RC4 +/// \sa Alleged RC4 +/// \since Crypto++ 3.1 +DOCUMENTED_TYPEDEF(SymmetricCipherFinal, MARC4); + +} +#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1 +namespace Weak {using namespace Weak1;} // import Weak1 into CryptoPP::Weak +#else +using namespace Weak1; // import Weak1 into CryptoPP with warning +#ifdef __GNUC__ +#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning." +#else +#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.") +#endif +#endif + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/argnames.h b/third_party/cryptoppwin/include/cryptopp/argnames.h new file mode 100644 index 00000000..4f929d5d --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/argnames.h @@ -0,0 +1,99 @@ +// argnames.h - originally written and placed in the public domain by Wei Dai + +/// \file argnames.h +/// \brief Standard names for retrieving values by name when working with \p NameValuePairs + +#ifndef CRYPTOPP_ARGNAMES_H +#define CRYPTOPP_ARGNAMES_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +DOCUMENTED_NAMESPACE_BEGIN(Name) + +#define CRYPTOPP_DEFINE_NAME_STRING(name) inline const char *name() {return #name;} + +CRYPTOPP_DEFINE_NAME_STRING(ValueNames) ///< string, a list of value names with a semicolon (';') after each name +CRYPTOPP_DEFINE_NAME_STRING(Version) ///< int +CRYPTOPP_DEFINE_NAME_STRING(Seed) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Key) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(IV) ///< ConstByteArrayParameter, also accepts const byte * for backwards compatibility +CRYPTOPP_DEFINE_NAME_STRING(StolenIV) ///< byte * +CRYPTOPP_DEFINE_NAME_STRING(Nonce) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Rounds) ///< int +CRYPTOPP_DEFINE_NAME_STRING(FeedbackSize) ///< int +CRYPTOPP_DEFINE_NAME_STRING(WordSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(BlockSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(EffectiveKeyLength) ///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(KeySize) ///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(ModulusSize) ///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(SubgroupOrderSize) ///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(PrivateExponentSize)///< int, in bits +CRYPTOPP_DEFINE_NAME_STRING(Modulus) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(PublicExponent) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(PrivateExponent) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(PublicElement) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(SubgroupOrder) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(Cofactor) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(SubgroupGenerator) ///< Integer, ECP::Point, or EC2N::Point +CRYPTOPP_DEFINE_NAME_STRING(Curve) ///< ECP or EC2N +CRYPTOPP_DEFINE_NAME_STRING(GroupOID) ///< OID +CRYPTOPP_DEFINE_NAME_STRING(PointerToPrimeSelector) ///< const PrimeSelector * +CRYPTOPP_DEFINE_NAME_STRING(Prime1) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(Prime2) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(ModPrime1PrivateExponent) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(ModPrime2PrivateExponent) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(MultiplicativeInverseOfPrime2ModPrime1) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(QuadraticResidueModPrime1) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(QuadraticResidueModPrime2) ///< Integer +CRYPTOPP_DEFINE_NAME_STRING(PutMessage) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(TruncatedDigestSize) ///< int +CRYPTOPP_DEFINE_NAME_STRING(BlockPaddingScheme) ///< StreamTransformationFilter::BlockPaddingScheme +CRYPTOPP_DEFINE_NAME_STRING(HashVerificationFilterFlags) ///< word32 +CRYPTOPP_DEFINE_NAME_STRING(AuthenticatedDecryptionFilterFlags) ///< word32 +CRYPTOPP_DEFINE_NAME_STRING(SignatureVerificationFilterFlags) ///< word32 +CRYPTOPP_DEFINE_NAME_STRING(InputBuffer) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(OutputBuffer) ///< ByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(InputFileName) ///< const char * +CRYPTOPP_DEFINE_NAME_STRING(InputFileNameWide) ///< const wchar_t * +CRYPTOPP_DEFINE_NAME_STRING(InputStreamPointer) ///< std::istream * +CRYPTOPP_DEFINE_NAME_STRING(InputBinaryMode) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(OutputFileName) ///< const char * +CRYPTOPP_DEFINE_NAME_STRING(OutputFileNameWide) ///< const wchar_t * +CRYPTOPP_DEFINE_NAME_STRING(OutputStreamPointer) ///< std::ostream * +CRYPTOPP_DEFINE_NAME_STRING(OutputBinaryMode) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(EncodingParameters) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(KeyDerivationParameters) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Separator) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Terminator) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Uppercase) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(GroupSize) ///< int +CRYPTOPP_DEFINE_NAME_STRING(Pad) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(PaddingByte) ///< byte +CRYPTOPP_DEFINE_NAME_STRING(Log2Base) ///< int +CRYPTOPP_DEFINE_NAME_STRING(EncodingLookupArray) ///< const byte * +CRYPTOPP_DEFINE_NAME_STRING(DecodingLookupArray) ///< const byte * +CRYPTOPP_DEFINE_NAME_STRING(InsertLineBreaks) ///< bool +CRYPTOPP_DEFINE_NAME_STRING(MaxLineLength) ///< int +CRYPTOPP_DEFINE_NAME_STRING(DigestSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(L1KeyLength) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(TableSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(Blinding) ///< bool, timing attack mitigations, ON by default +CRYPTOPP_DEFINE_NAME_STRING(DerivedKey) ///< ByteArrayParameter, key derivation, derived key +CRYPTOPP_DEFINE_NAME_STRING(DerivedKeyLength) ///< int, key derivation, derived key length in bytes +CRYPTOPP_DEFINE_NAME_STRING(Personalization) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(PersonalizationSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(Salt) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(Tweak) ///< ConstByteArrayParameter +CRYPTOPP_DEFINE_NAME_STRING(SaltSize) ///< int, in bytes +CRYPTOPP_DEFINE_NAME_STRING(TreeMode) ///< byte +CRYPTOPP_DEFINE_NAME_STRING(FileName) ///< const char * +CRYPTOPP_DEFINE_NAME_STRING(FileTime) ///< int +CRYPTOPP_DEFINE_NAME_STRING(Comment) ///< const char * +CRYPTOPP_DEFINE_NAME_STRING(Identity) ///< ConstByteArrayParameter +DOCUMENTED_NAMESPACE_END + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/aria.h b/third_party/cryptoppwin/include/cryptopp/aria.h new file mode 100644 index 00000000..da623a16 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/aria.h @@ -0,0 +1,71 @@ +// aria.h - written and placed in the public domain by Jeffrey Walton + +/// \file aria.h +/// \brief Classes for the ARIA block cipher +/// \details The Crypto++ ARIA implementation is based on the 32-bit implementation by Aaram Yun +/// from the National Security Research Institute, KOREA. Aaram Yun's implementation is based on +/// the 8-bit implementation by Jin Hong. The source files are available in ARIA.zip from the Korea +/// Internet & Security Agency website. +/// \sa RFC 5794, A Description of the ARIA Encryption Algorithm, +/// Korea +/// Internet & Security Agency homepage + +#ifndef CRYPTOPP_ARIA_H +#define CRYPTOPP_ARIA_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ARIA block cipher information +/// \since Crypto++ 6.0 +struct ARIA_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ARIA";} +}; + +/// \brief ARIA block cipher +/// \details The Crypto++ ARIA implementation is based on the 32-bit implementation by Aaram Yun +/// from the National Security Research Institute, KOREA. Aaram Yun's implementation is based on +/// the 8-bit implementation by Jin Hong. The source files are available in ARIA.zip from the Korea +/// Internet & Security Agency website. +/// \sa RFC 5794, A Description of the ARIA Encryption Algorithm, +/// Korea +/// Internet & Security Agency homepage +/// \sa ARIA +/// \since Crypto++ 6.0 +class ARIA : public ARIA_Info, public BlockCipherDocumentation +{ +public: + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + Base() : m_rounds(0) {} + + protected: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + private: + // Reference implementation allocates a table of 17 round keys. + typedef SecBlock > AlignedByteBlock; + typedef SecBlock > AlignedWordBlock; + + AlignedWordBlock m_rk; // round keys + AlignedWordBlock m_w; // w0, w1, w2, w3, t and u + unsigned int m_rounds; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef ARIA::Encryption ARIAEncryption; +typedef ARIA::Decryption ARIADecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/arm_simd.h b/third_party/cryptoppwin/include/cryptopp/arm_simd.h new file mode 100644 index 00000000..b8eabe15 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/arm_simd.h @@ -0,0 +1,427 @@ +// arm_simd.h - written and placed in public domain by Jeffrey Walton + +/// \file arm_simd.h +/// \brief Support functions for ARM and vector operations + +#ifndef CRYPTOPP_ARM_SIMD_H +#define CRYPTOPP_ARM_SIMD_H + +#include "config.h" + +#if (CRYPTOPP_ARM_NEON_HEADER) +# include +# include +#endif + +#if (CRYPTOPP_ARM_ACLE_HEADER) +# include +# include +#endif + +#if (CRYPTOPP_ARM_CRC32_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \name CRC32 checksum +//@{ + +/// \brief CRC32 checksum +/// \param crc the starting crc value +/// \param val the value to checksum +/// \return CRC32 value +/// \since Crypto++ 8.6 +inline uint32_t CRC32B (uint32_t crc, uint8_t val) +{ +#if defined(CRYPTOPP_MSC_VERSION) + return __crc32b(crc, val); +#else + __asm__ ("crc32b %w0, %w0, %w1 \n\t" + :"+r" (crc) : "r" (val) ); + return crc; +#endif +} + +/// \brief CRC32 checksum +/// \param crc the starting crc value +/// \param val the value to checksum +/// \return CRC32 value +/// \since Crypto++ 8.6 +inline uint32_t CRC32W (uint32_t crc, uint32_t val) +{ +#if defined(CRYPTOPP_MSC_VERSION) + return __crc32w(crc, val); +#else + __asm__ ("crc32w %w0, %w0, %w1 \n\t" + :"+r" (crc) : "r" (val) ); + return crc; +#endif +} + +/// \brief CRC32 checksum +/// \param crc the starting crc value +/// \param vals the values to checksum +/// \return CRC32 value +/// \since Crypto++ 8.6 +inline uint32_t CRC32Wx4 (uint32_t crc, const uint32_t vals[4]) +{ +#if defined(CRYPTOPP_MSC_VERSION) + return __crc32w(__crc32w(__crc32w(__crc32w( + crc, vals[0]), vals[1]), vals[2]), vals[3]); +#else + __asm__ ("crc32w %w0, %w0, %w1 \n\t" + "crc32w %w0, %w0, %w2 \n\t" + "crc32w %w0, %w0, %w3 \n\t" + "crc32w %w0, %w0, %w4 \n\t" + :"+r" (crc) : "r" (vals[0]), "r" (vals[1]), + "r" (vals[2]), "r" (vals[3])); + return crc; +#endif +} + +//@} +/// \name CRC32-C checksum + +/// \brief CRC32-C checksum +/// \param crc the starting crc value +/// \param val the value to checksum +/// \return CRC32-C value +/// \since Crypto++ 8.6 +inline uint32_t CRC32CB (uint32_t crc, uint8_t val) +{ +#if defined(CRYPTOPP_MSC_VERSION) + return __crc32cb(crc, val); +#else + __asm__ ("crc32cb %w0, %w0, %w1 \n\t" + :"+r" (crc) : "r" (val) ); + return crc; +#endif +} + +/// \brief CRC32-C checksum +/// \param crc the starting crc value +/// \param val the value to checksum +/// \return CRC32-C value +/// \since Crypto++ 8.6 +inline uint32_t CRC32CW (uint32_t crc, uint32_t val) +{ +#if defined(CRYPTOPP_MSC_VERSION) + return __crc32cw(crc, val); +#else + __asm__ ("crc32cw %w0, %w0, %w1 \n\t" + :"+r" (crc) : "r" (val) ); + return crc; +#endif +} + +/// \brief CRC32-C checksum +/// \param crc the starting crc value +/// \param vals the values to checksum +/// \return CRC32-C value +/// \since Crypto++ 8.6 +inline uint32_t CRC32CWx4 (uint32_t crc, const uint32_t vals[4]) +{ +#if defined(CRYPTOPP_MSC_VERSION) + return __crc32cw(__crc32cw(__crc32cw(__crc32cw( + crc, vals[0]), vals[1]), vals[2]), vals[3]); +#else + __asm__ ("crc32cw %w0, %w0, %w1 \n\t" + "crc32cw %w0, %w0, %w2 \n\t" + "crc32cw %w0, %w0, %w3 \n\t" + "crc32cw %w0, %w0, %w4 \n\t" + :"+r" (crc) : "r" (vals[0]), "r" (vals[1]), + "r" (vals[2]), "r" (vals[3])); + return crc; +#endif +} +//@} +#endif // CRYPTOPP_ARM_CRC32_AVAILABLE + +#if (CRYPTOPP_ARM_PMULL_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \name Polynomial multiplication +//@{ + +/// \brief Polynomial multiplication +/// \param a the first value +/// \param b the second value +/// \return vector product +/// \details PMULL_00() performs polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x00). +/// The 0x00 indicates the low 64-bits of a and b +/// are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the rightmost bit is LSB and +/// numbered 0. +/// \since Crypto++ 8.0 +inline uint64x2_t PMULL_00(const uint64x2_t a, const uint64x2_t b) +{ +#if defined(CRYPTOPP_MSC_VERSION) + const __n64 x = { vgetq_lane_u64(a, 0) }; + const __n64 y = { vgetq_lane_u64(b, 0) }; + return vmull_p64(x, y); +#elif defined(__GNUC__) + uint64x2_t r; + __asm__ ("pmull %0.1q, %1.1d, %2.1d \n\t" + :"=w" (r) : "w" (a), "w" (b) ); + return r; +#else + return (uint64x2_t)(vmull_p64( + vgetq_lane_u64(vreinterpretq_u64_u8(a),0), + vgetq_lane_u64(vreinterpretq_u64_u8(b),0))); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first value +/// \param b the second value +/// \return vector product +/// \details PMULL_01 performs() polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x01). +/// The 0x01 indicates the low 64-bits of a and high +/// 64-bits of b are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the rightmost bit is LSB and +/// numbered 0. +/// \since Crypto++ 8.0 +inline uint64x2_t PMULL_01(const uint64x2_t a, const uint64x2_t b) +{ +#if defined(CRYPTOPP_MSC_VERSION) + const __n64 x = { vgetq_lane_u64(a, 0) }; + const __n64 y = { vgetq_lane_u64(b, 1) }; + return vmull_p64(x, y); +#elif defined(__GNUC__) + uint64x2_t r; + __asm__ ("pmull %0.1q, %1.1d, %2.1d \n\t" + :"=w" (r) : "w" (a), "w" (vget_high_u64(b)) ); + return r; +#else + return (uint64x2_t)(vmull_p64( + vgetq_lane_u64(vreinterpretq_u64_u8(a),0), + vgetq_lane_u64(vreinterpretq_u64_u8(b),1))); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first value +/// \param b the second value +/// \return vector product +/// \details PMULL_10() performs polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x10). +/// The 0x10 indicates the high 64-bits of a and low +/// 64-bits of b are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the rightmost bit is LSB and +/// numbered 0. +/// \since Crypto++ 8.0 +inline uint64x2_t PMULL_10(const uint64x2_t a, const uint64x2_t b) +{ +#if defined(CRYPTOPP_MSC_VERSION) + const __n64 x = { vgetq_lane_u64(a, 1) }; + const __n64 y = { vgetq_lane_u64(b, 0) }; + return vmull_p64(x, y); +#elif defined(__GNUC__) + uint64x2_t r; + __asm__ ("pmull %0.1q, %1.1d, %2.1d \n\t" + :"=w" (r) : "w" (vget_high_u64(a)), "w" (b) ); + return r; +#else + return (uint64x2_t)(vmull_p64( + vgetq_lane_u64(vreinterpretq_u64_u8(a),1), + vgetq_lane_u64(vreinterpretq_u64_u8(b),0))); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first value +/// \param b the second value +/// \return vector product +/// \details PMULL_11() performs polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x11). +/// The 0x11 indicates the high 64-bits of a and b +/// are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the rightmost bit is LSB and +/// numbered 0. +/// \since Crypto++ 8.0 +inline uint64x2_t PMULL_11(const uint64x2_t a, const uint64x2_t b) +{ +#if defined(CRYPTOPP_MSC_VERSION) + const __n64 x = { vgetq_lane_u64(a, 1) }; + const __n64 y = { vgetq_lane_u64(b, 1) }; + return vmull_p64(x, y); +#elif defined(__GNUC__) + uint64x2_t r; + __asm__ ("pmull2 %0.1q, %1.2d, %2.2d \n\t" + :"=w" (r) : "w" (a), "w" (b) ); + return r; +#else + return (uint64x2_t)(vmull_p64( + vgetq_lane_u64(vreinterpretq_u64_u8(a),1), + vgetq_lane_u64(vreinterpretq_u64_u8(b),1))); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first value +/// \param b the second value +/// \return vector product +/// \details PMULL() performs vmull_p64(). PMULL is provided as +/// GCC inline assembly due to Clang and lack of support for the intrinsic. +/// \since Crypto++ 8.0 +inline uint64x2_t PMULL(const uint64x2_t a, const uint64x2_t b) +{ +#if defined(CRYPTOPP_MSC_VERSION) + const __n64 x = { vgetq_lane_u64(a, 0) }; + const __n64 y = { vgetq_lane_u64(b, 0) }; + return vmull_p64(x, y); +#elif defined(__GNUC__) + uint64x2_t r; + __asm__ ("pmull %0.1q, %1.1d, %2.1d \n\t" + :"=w" (r) : "w" (a), "w" (b) ); + return r; +#else + return (uint64x2_t)(vmull_p64( + vgetq_lane_u64(vreinterpretq_u64_u8(a),0), + vgetq_lane_u64(vreinterpretq_u64_u8(b),0))); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first value +/// \param b the second value +/// \return vector product +/// \details PMULL_HIGH() performs vmull_high_p64(). PMULL_HIGH is provided as +/// GCC inline assembly due to Clang and lack of support for the intrinsic. +/// \since Crypto++ 8.0 +inline uint64x2_t PMULL_HIGH(const uint64x2_t a, const uint64x2_t b) +{ +#if defined(CRYPTOPP_MSC_VERSION) + const __n64 x = { vgetq_lane_u64(a, 1) }; + const __n64 y = { vgetq_lane_u64(b, 1) }; + return vmull_p64(x, y); +#elif defined(__GNUC__) + uint64x2_t r; + __asm__ ("pmull2 %0.1q, %1.2d, %2.2d \n\t" + :"=w" (r) : "w" (a), "w" (b) ); + return r; +#else + return (uint64x2_t)(vmull_p64( + vgetq_lane_u64(vreinterpretq_u64_u8(a),1), + vgetq_lane_u64(vreinterpretq_u64_u8(b),1)))); +#endif +} + +/// \brief Vector extraction +/// \tparam C the byte count +/// \param a the first value +/// \param b the second value +/// \return vector +/// \details VEXT_U8() extracts the first C bytes of vector +/// a and the remaining bytes in b. VEXT_U8 is provided +/// as GCC inline assembly due to Clang and lack of support for the intrinsic. +/// \since Crypto++ 8.0 +template +inline uint64x2_t VEXT_U8(uint64x2_t a, uint64x2_t b) +{ + // https://github.com/weidai11/cryptopp/issues/366 +#if defined(CRYPTOPP_MSC_VERSION) + return vreinterpretq_u64_u8(vextq_u8( + vreinterpretq_u8_u64(a), vreinterpretq_u8_u64(b), C)); +#else + uint64x2_t r; + __asm__ ("ext %0.16b, %1.16b, %2.16b, %3 \n\t" + :"=w" (r) : "w" (a), "w" (b), "I" (C) ); + return r; +#endif +} + +//@} +#endif // CRYPTOPP_ARM_PMULL_AVAILABLE + +#if CRYPTOPP_ARM_SHA3_AVAILABLE || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \name ARMv8.2 operations +//@{ + +/// \brief Three-way XOR +/// \param a the first value +/// \param b the second value +/// \param c the third value +/// \return three-way exclusive OR of the values +/// \details VEOR3() performs veor3q_u64(). VEOR3 is provided as GCC inline assembly due +/// to Clang and lack of support for the intrinsic. +/// \details VEOR3 requires ARMv8.2. +/// \since Crypto++ 8.6 +inline uint64x2_t VEOR3(uint64x2_t a, uint64x2_t b, uint64x2_t c) +{ +#if defined(CRYPTOPP_MSC_VERSION) + return veor3q_u64(a, b, c); +#else + uint64x2_t r; + __asm__ ("eor3 %0.16b, %1.16b, %2.16b, %3.16b \n\t" + :"=w" (r) : "w" (a), "w" (b), "w" (c)); + return r; +#endif +} + +/// \brief XOR and rotate +/// \param a the first value +/// \param b the second value +/// \param c the third value +/// \return two-way exclusive OR of the values, then rotated by c +/// \details VXARQ() performs vxarq_u64(). VXARQ is provided as GCC inline assembly due +/// to Clang and lack of support for the intrinsic. +/// \details VXARQ requires ARMv8.2. +/// \since Crypto++ 8.6 +inline uint64x2_t VXAR(uint64x2_t a, uint64x2_t b, const int c) +{ +#if defined(CRYPTOPP_MSC_VERSION) + return vxarq_u64(a, b, c); +#else + uint64x2_t r; + __asm__ ("xar %0.2d, %1.2d, %2.2d, %3 \n\t" + :"=w" (r) : "w" (a), "w" (b), "I" (c)); + return r; +#endif +} + +/// \brief XOR and rotate +/// \tparam C the rotate amount +/// \param a the first value +/// \param b the second value +/// \return two-way exclusive OR of the values, then rotated by C +/// \details VXARQ() performs vxarq_u64(). VXARQ is provided as GCC inline assembly due +/// to Clang and lack of support for the intrinsic. +/// \details VXARQ requires ARMv8.2. +/// \since Crypto++ 8.6 +template +inline uint64x2_t VXAR(uint64x2_t a, uint64x2_t b) +{ +#if defined(CRYPTOPP_MSC_VERSION) + return vxarq_u64(a, b, C); +#else + uint64x2_t r; + __asm__ ("xar %0.2d, %1.2d, %2.2d, %3 \n\t" + :"=w" (r) : "w" (a), "w" (b), "I" (C)); + return r; +#endif +} + +/// \brief XOR and rotate +/// \param a the first value +/// \param b the second value +/// \return two-way exclusive OR of the values, then rotated 1-bit +/// \details VRAX1() performs vrax1q_u64(). VRAX1 is provided as GCC inline assembly due +/// to Clang and lack of support for the intrinsic. +/// \details VRAX1 requires ARMv8.2. +/// \since Crypto++ 8.6 +inline uint64x2_t VRAX1(uint64x2_t a, uint64x2_t b) +{ +#if defined(CRYPTOPP_MSC_VERSION) + return vrax1q_u64(a, b); +#else + uint64x2_t r; + __asm__ ("rax1 %0.2d, %1.2d, %2.2d \n\t" + :"=w" (r) : "w" (a), "w" (b)); + return r; +#endif +} +//@} +#endif // CRYPTOPP_ARM_SHA3_AVAILABLE + +#endif // CRYPTOPP_ARM_SIMD_H diff --git a/third_party/cryptoppwin/include/cryptopp/asn.h b/third_party/cryptoppwin/include/cryptopp/asn.h new file mode 100644 index 00000000..beb20cd0 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/asn.h @@ -0,0 +1,974 @@ +// asn.h - originally written and placed in the public domain by Wei Dai + +/// \file asn.h +/// \brief Classes and functions for working with ANS.1 objects + +#ifndef CRYPTOPP_ASN_H +#define CRYPTOPP_ASN_H + +#include "cryptlib.h" +#include "filters.h" +#include "smartptr.h" +#include "stdcpp.h" +#include "queue.h" +#include "misc.h" + +#include + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ASN.1 types +/// \note These tags are not complete +enum ASNTag +{ + /// \brief ASN.1 Boolean + BOOLEAN = 0x01, + /// \brief ASN.1 Integer + INTEGER = 0x02, + /// \brief ASN.1 Bit string + BIT_STRING = 0x03, + /// \brief ASN.1 Octet string + OCTET_STRING = 0x04, + /// \brief ASN.1 Null + TAG_NULL = 0x05, + /// \brief ASN.1 Object identifier + OBJECT_IDENTIFIER = 0x06, + /// \brief ASN.1 Object descriptor + OBJECT_DESCRIPTOR = 0x07, + /// \brief ASN.1 External reference + EXTERNAL = 0x08, + /// \brief ASN.1 Real integer + REAL = 0x09, + /// \brief ASN.1 Enumerated value + ENUMERATED = 0x0a, + /// \brief ASN.1 UTF-8 string + UTF8_STRING = 0x0c, + /// \brief ASN.1 Sequence + SEQUENCE = 0x10, + /// \brief ASN.1 Set + SET = 0x11, + /// \brief ASN.1 Numeric string + NUMERIC_STRING = 0x12, + /// \brief ASN.1 Printable string + PRINTABLE_STRING = 0x13, + /// \brief ASN.1 T61 string + T61_STRING = 0x14, + /// \brief ASN.1 Videotext string + VIDEOTEXT_STRING = 0x15, + /// \brief ASN.1 IA5 string + IA5_STRING = 0x16, + /// \brief ASN.1 UTC time + UTC_TIME = 0x17, + /// \brief ASN.1 Generalized time + GENERALIZED_TIME = 0x18, + /// \brief ASN.1 Graphic string + GRAPHIC_STRING = 0x19, + /// \brief ASN.1 Visible string + VISIBLE_STRING = 0x1a, + /// \brief ASN.1 General string + GENERAL_STRING = 0x1b, + /// \brief ASN.1 Universal string + UNIVERSAL_STRING = 0x1c, + /// \brief ASN.1 BMP string + BMP_STRING = 0x1e +}; + +/// \brief ASN.1 flags +/// \note These flags are not complete +enum ASNIdFlag +{ + /// \brief ASN.1 Universal class + UNIVERSAL = 0x00, + // DATA = 0x01, + // HEADER = 0x02, + /// \brief ASN.1 Primitive flag + PRIMITIVE = 0x00, + /// \brief ASN.1 Constructed flag + CONSTRUCTED = 0x20, + /// \brief ASN.1 Application class + APPLICATION = 0x40, + /// \brief ASN.1 Context specific class + CONTEXT_SPECIFIC = 0x80, + /// \brief ASN.1 Private class + PRIVATE = 0xc0 +}; + +/// \brief Raises a BERDecodeErr +inline void BERDecodeError() {throw BERDecodeErr();} + +/// \brief Exception thrown when an unknown object identifier is encountered +class CRYPTOPP_DLL UnknownOID : public BERDecodeErr +{ +public: + /// \brief Construct an UnknownOID + UnknownOID() : BERDecodeErr("BER decode error: unknown object identifier") {} + /// \brief Construct an UnknownOID + /// \param err error message to use for the exception + UnknownOID(const char *err) : BERDecodeErr(err) {} +}; + +/// \brief DER encode a length +/// \param bt BufferedTransformation object for writing +/// \param length the size to encode +/// \return the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API DERLengthEncode(BufferedTransformation &bt, lword length); + +/// \brief BER decode a length +/// \param bt BufferedTransformation object for reading +/// \param length the decoded size +/// \return true if the value was decoded +/// \throw BERDecodeError if the value fails to decode or is too large for size_t +/// \details BERLengthDecode() returns false if the encoding is indefinite length. +CRYPTOPP_DLL bool CRYPTOPP_API BERLengthDecode(BufferedTransformation &bt, size_t &length); + +/// \brief DER encode NULL +/// \param bt BufferedTransformation object for writing +CRYPTOPP_DLL void CRYPTOPP_API DEREncodeNull(BufferedTransformation &bt); + +/// \brief BER decode NULL +/// \param bt BufferedTransformation object for reading +CRYPTOPP_DLL void CRYPTOPP_API BERDecodeNull(BufferedTransformation &bt); + +/// \brief DER encode octet string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param strLen the length of the string +/// \return the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeOctetString(BufferedTransformation &bt, const byte *str, size_t strLen); + +/// \brief DER encode octet string +/// \param bt BufferedTransformation object for reading +/// \param str the string to encode +/// \return the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeOctetString(BufferedTransformation &bt, const SecByteBlock &str); + +/// \brief BER decode octet string +/// \param bt BufferedTransformation object for reading +/// \param str the decoded string +/// \return the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeOctetString(BufferedTransformation &bt, SecByteBlock &str); + +/// \brief BER decode octet string +/// \param bt BufferedTransformation object for reading +/// \param str the decoded string +/// \return the number of octets used for the encoding +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeOctetString(BufferedTransformation &bt, BufferedTransformation &str); + +/// \brief DER encode text string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param strLen the length of the string, in bytes +/// \param asnTag the ASN.1 identifier +/// \return the number of octets used for the encoding +/// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +/// \since Crypto++ 8.3 +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeTextString(BufferedTransformation &bt, const byte* str, size_t strLen, byte asnTag); + +/// \brief DER encode text string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param asnTag the ASN.1 identifier +/// \return the number of octets used for the encoding +/// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +/// \since Crypto++ 8.3 +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeTextString(BufferedTransformation &bt, const SecByteBlock &str, byte asnTag); + +/// \brief DER encode text string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param asnTag the ASN.1 identifier +/// \return the number of octets used for the encoding +/// \details DEREncodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +/// \since Crypto++ 6.0 +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeTextString(BufferedTransformation &bt, const std::string &str, byte asnTag); + +/// \brief BER decode text string +/// \param bt BufferedTransformation object for reading +/// \param str the string to decode +/// \param asnTag the ASN.1 identifier +/// \details BERDecodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +/// \since Crypto++ 8.3 +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeTextString(BufferedTransformation &bt, SecByteBlock &str, byte asnTag); + +/// \brief BER decode text string +/// \param bt BufferedTransformation object for reading +/// \param str the string to decode +/// \param asnTag the ASN.1 identifier +/// \details BERDecodeTextString() can be used for UTF8_STRING, PRINTABLE_STRING, and IA5_STRING +/// \since Crypto++ 6.0 +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeTextString(BufferedTransformation &bt, std::string &str, byte asnTag); + +/// \brief DER encode date +/// \param bt BufferedTransformation object for writing +/// \param str the date to encode +/// \param asnTag the ASN.1 identifier +/// \return the number of octets used for the encoding +/// \details BERDecodeDate() can be used for UTC_TIME and GENERALIZED_TIME +/// \since Crypto++ 8.3 +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeDate(BufferedTransformation &bt, const SecByteBlock &str, byte asnTag); + +/// \brief BER decode date +/// \param bt BufferedTransformation object for reading +/// \param str the date to decode +/// \param asnTag the ASN.1 identifier +/// \details BERDecodeDate() can be used for UTC_TIME and GENERALIZED_TIME +/// \since Crypto++ 8.3 +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeDate(BufferedTransformation &bt, SecByteBlock &str, byte asnTag); + +/// \brief DER encode bit string +/// \param bt BufferedTransformation object for writing +/// \param str the string to encode +/// \param strLen the length of the string +/// \param unusedBits the number of unused bits +/// \return the number of octets used for the encoding +/// \details The caller is responsible for shifting octets if unusedBits is +/// not 0. For example, to DER encode a web server X.509 key usage, the 101b +/// bit mask is often used (digitalSignature and keyEncipherment). In this +/// case str is one octet with a value=0xa0 and unusedBits=5. The +/// value 0xa0 is 101b << 5. +CRYPTOPP_DLL size_t CRYPTOPP_API DEREncodeBitString(BufferedTransformation &bt, const byte *str, size_t strLen, unsigned int unusedBits=0); + +/// \brief DER decode bit string +/// \param bt BufferedTransformation object for reading +/// \param str the decoded string +/// \param unusedBits the number of unused bits +/// \details The caller is responsible for shifting octets if unusedBits is +/// not 0. For example, to DER encode a web server X.509 key usage, the 101b +/// bit mask is often used (digitalSignature and keyEncipherment). In this +/// case str is one octet with a value=0xa0 and unusedBits=5. The +/// value 0xa0 is 101b << 5. +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodeBitString(BufferedTransformation &bt, SecByteBlock &str, unsigned int &unusedBits); + +/// \brief BER decode and DER re-encode +/// \param bt BufferedTransformation object for writing +/// \param dest BufferedTransformation object +CRYPTOPP_DLL void CRYPTOPP_API DERReencode(BufferedTransformation &bt, BufferedTransformation &dest); + +/// \brief BER decode size +/// \param bt BufferedTransformation object for reading +/// \return the length of the ASN.1 value, in bytes +/// \details BERDecodePeekLength() determines the length of a value without +/// consuming octets in the stream. The stream must use definite length encoding. +/// If indefinite length encoding is used or an error occurs, then 0 is returned. +/// \since Crypto++ 8.3 +CRYPTOPP_DLL size_t CRYPTOPP_API BERDecodePeekLength(const BufferedTransformation &bt); + +/// \brief Object Identifier +class CRYPTOPP_DLL OID +{ +public: + virtual ~OID() {} + + /// \brief Construct an OID + OID() {} + + /// \brief Construct an OID + /// \param v value to initialize the OID + OID(word32 v) : m_values(1, v) {} + + /// \brief Construct an OID + /// \param bt BufferedTransformation object + OID(BufferedTransformation &bt) { + BERDecode(bt); + } + + /// \brief Append a value to an OID + /// \param rhs the value to append + inline OID & operator+=(word32 rhs) { + m_values.push_back(rhs); return *this; + } + + /// \brief DER encode this OID + /// \param bt BufferedTransformation object + void DEREncode(BufferedTransformation &bt) const; + + /// \brief BER decode an OID + /// \param bt BufferedTransformation object + void BERDecode(BufferedTransformation &bt); + + /// \brief BER decode an OID + /// \param bt BufferedTransformation object + /// \throw BERDecodeErr() if decoded value doesn't match an expected OID + /// \details BERDecodeAndCheck() can be used to parse an OID and verify it matches an expected. + ///
+	///   BERSequenceDecoder key(bt);
+	///   ...
+	///   BERSequenceDecoder algorithm(key);
+	///   GetAlgorithmID().BERDecodeAndCheck(algorithm);
+	/// 
+ void BERDecodeAndCheck(BufferedTransformation &bt) const; + + /// \brief Determine if OID is empty + /// \return true if OID has 0 elements, false otherwise + /// \since Crypto++ 8.0 + bool Empty() const { + return m_values.empty(); + } + + /// \brief Retrieve OID value array + /// \return OID value vector + /// \since Crypto++ 8.0 + const std::vector& GetValues() const { + return m_values; + } + + /// \brief Print an OID + /// \param out ostream object + /// \return ostream reference + /// \details Print() writes the OID in a customary format, like + /// 1.2.840.113549.1.1.11. The caller is reposnsible to convert the + /// OID to a friendly name, like sha256WithRSAEncryption. + /// \since Crypto++ 8.3 + std::ostream& Print(std::ostream& out) const; + +protected: + friend bool operator==(const OID &lhs, const OID &rhs); + friend bool operator!=(const OID &lhs, const OID &rhs); + friend bool operator< (const OID &lhs, const OID &rhs); + friend bool operator> (const OID &lhs, const OID &rhs); + friend bool operator<=(const OID &lhs, const OID &rhs); + friend bool operator>=(const OID &lhs, const OID &rhs); + + std::vector m_values; + +private: + static void EncodeValue(BufferedTransformation &bt, word32 v); + static size_t DecodeValue(BufferedTransformation &bt, word32 &v); +}; + +/// \brief ASN.1 encoded object filter +class EncodedObjectFilter : public Filter +{ +public: + enum Flag {PUT_OBJECTS=1, PUT_MESSANGE_END_AFTER_EACH_OBJECT=2, PUT_MESSANGE_END_AFTER_ALL_OBJECTS=4, PUT_MESSANGE_SERIES_END_AFTER_ALL_OBJECTS=8}; + enum State {IDENTIFIER, LENGTH, BODY, TAIL, ALL_DONE} m_state; + + virtual ~EncodedObjectFilter() {} + + /// \brief Construct an EncodedObjectFilter + /// \param attachment a BufferedTrasformation to attach to this object + /// \param nObjects the number of objects + /// \param flags bitwise OR of EncodedObjectFilter::Flag + EncodedObjectFilter(BufferedTransformation *attachment = NULLPTR, unsigned int nObjects = 1, word32 flags = 0); + + /// \brief Input a byte buffer for processing + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + void Put(const byte *inString, size_t length); + + unsigned int GetNumberOfCompletedObjects() const {return m_nCurrentObject;} + unsigned long GetPositionOfObject(unsigned int i) const {return m_positions[i];} + +private: + BufferedTransformation & CurrentTarget(); + + ByteQueue m_queue; + std::vector m_positions; + lword m_lengthRemaining; + word32 m_nObjects, m_nCurrentObject, m_level, m_flags; + byte m_id; +}; + +/// \brief BER General Decoder +class CRYPTOPP_DLL BERGeneralDecoder : public Store +{ +public: + /// \brief Default ASN.1 tag + enum {DefaultTag = SEQUENCE | EnumToInt(CONSTRUCTED)}; + + virtual ~BERGeneralDecoder(); + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \details BERGeneralDecoder uses DefaultTag + explicit BERGeneralDecoder(BufferedTransformation &inQueue); + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \param asnTag ASN.1 tag + explicit BERGeneralDecoder(BufferedTransformation &inQueue, byte asnTag); + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \param asnTag ASN.1 tag + explicit BERGeneralDecoder(BERGeneralDecoder &inQueue, byte asnTag); + + /// \brief Determine length encoding + /// \return true if the ASN.1 object is definite length encoded, false otherwise + bool IsDefiniteLength() const { + return m_definiteLength; + } + + /// \brief Determine remaining length + /// \return number of octets that remain to be consumed + /// \details RemainingLength() is only valid if IsDefiniteLength() + /// returns true. + lword RemainingLength() const { + CRYPTOPP_ASSERT(m_definiteLength); + return IsDefiniteLength() ? m_length : 0; + } + + /// \brief Determine end of stream + /// \return true if all octets have been consumed, false otherwise + bool EndReached() const; + + /// \brief Determine next octet + /// \return next octet in the stream + /// \details PeekByte does not consume the octet. + /// \throw BERDecodeError if there are no octets remaining + byte PeekByte() const; + + /// \brief Determine next octet + /// \details CheckByte reads the next byte in the stream and verifies + /// the octet matches b. + /// \throw BERDecodeError if the next octet is not b + void CheckByte(byte b); + + /// \brief Transfer bytes to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param transferBytes the number of bytes to transfer + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when + /// processing input + /// \return the number of bytes that remain in the transfer block + /// (i.e., bytes not transferred) + /// \details TransferTo2() removes bytes and moves + /// them to the destination. Transfer begins at the index position + /// in the current stream, and not from an absolute position in the + /// stream. + /// \details transferBytes is an \a IN and \a OUT parameter. When + /// the call is made, transferBytes is the requested size of the + /// transfer. When the call returns, transferBytes is the number + /// of bytes that were transferred. + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + + /// \brief Copy bytes to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param begin the 0-based index of the first byte to copy in + /// the stream + /// \param end the 0-based index of the last byte to copy in + /// the stream + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when + /// processing input + /// \return the number of bytes that remain in the copy block + /// (i.e., bytes not copied) + /// \details CopyRangeTo2 copies bytes to the + /// destination. The bytes are not removed from this object. Copying + /// begins at the index position in the current stream, and not from + /// an absolute position in the stream. + /// \details begin is an \a IN and \a OUT parameter. When the call is + /// made, begin is the starting position of the copy. When the call + /// returns, begin is the position of the first byte that was \a not + /// copied (which may be different than end). begin can be used for + /// subsequent calls to CopyRangeTo2(). + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + /// \brief Signals the end of messages to the object + /// \details Call this to denote end of sequence + void MessageEnd(); + +protected: + BufferedTransformation &m_inQueue; + lword m_length; + bool m_finished, m_definiteLength; + +private: + void Init(byte asnTag); + void StoreInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); CRYPTOPP_ASSERT(false);} + lword ReduceLength(lword delta); +}; + +/// \brief DER General Encoder +class CRYPTOPP_DLL DERGeneralEncoder : public ByteQueue +{ +public: + /// \brief Default ASN.1 tag + enum {DefaultTag = SEQUENCE | EnumToInt(CONSTRUCTED)}; + + virtual ~DERGeneralEncoder(); + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \details DERGeneralEncoder uses DefaultTag + explicit DERGeneralEncoder(BufferedTransformation &outQueue); + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \param asnTag ASN.1 tag + explicit DERGeneralEncoder(BufferedTransformation &outQueue, byte asnTag); + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \param asnTag ASN.1 tag + explicit DERGeneralEncoder(DERGeneralEncoder &outQueue, byte asnTag); + + /// \brief Signals the end of messages to the object + /// \details Call this to denote end of sequence + void MessageEnd(); + +private: + BufferedTransformation &m_outQueue; + byte m_asnTag; + bool m_finished; +}; + +/// \brief BER Sequence Decoder +class CRYPTOPP_DLL BERSequenceDecoder : public BERGeneralDecoder +{ +public: + /// \brief Default ASN.1 tag + enum {DefaultTag = SEQUENCE | EnumToInt(CONSTRUCTED)}; + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \details BERSequenceDecoder uses DefaultTag + explicit BERSequenceDecoder(BufferedTransformation &inQueue) + : BERGeneralDecoder(inQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \param asnTag ASN.1 tag + explicit BERSequenceDecoder(BufferedTransformation &inQueue, byte asnTag) + : BERGeneralDecoder(inQueue, asnTag) {} + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \details BERSequenceDecoder uses DefaultTag + explicit BERSequenceDecoder(BERSequenceDecoder &inQueue) + : BERGeneralDecoder(inQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \param asnTag ASN.1 tag + explicit BERSequenceDecoder(BERSequenceDecoder &inQueue, byte asnTag) + : BERGeneralDecoder(inQueue, asnTag) {} +}; + +/// \brief DER Sequence Encoder +class CRYPTOPP_DLL DERSequenceEncoder : public DERGeneralEncoder +{ +public: + /// \brief Default ASN.1 tag + enum {DefaultTag = SEQUENCE | EnumToInt(CONSTRUCTED)}; + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \details DERSequenceEncoder uses DefaultTag + explicit DERSequenceEncoder(BufferedTransformation &outQueue) + : DERGeneralEncoder(outQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \param asnTag ASN.1 tag + explicit DERSequenceEncoder(BufferedTransformation &outQueue, byte asnTag) + : DERGeneralEncoder(outQueue, asnTag) {} + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \details DERSequenceEncoder uses DefaultTag + explicit DERSequenceEncoder(DERSequenceEncoder &outQueue) + : DERGeneralEncoder(outQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \param asnTag ASN.1 tag + explicit DERSequenceEncoder(DERSequenceEncoder &outQueue, byte asnTag) + : DERGeneralEncoder(outQueue, asnTag) {} +}; + +/// \brief BER Set Decoder +class CRYPTOPP_DLL BERSetDecoder : public BERGeneralDecoder +{ +public: + /// \brief Default ASN.1 tag + enum {DefaultTag = SET | EnumToInt(CONSTRUCTED)}; + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \details BERSetDecoder uses DefaultTag + explicit BERSetDecoder(BufferedTransformation &inQueue) + : BERGeneralDecoder(inQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \param asnTag ASN.1 tag + explicit BERSetDecoder(BufferedTransformation &inQueue, byte asnTag) + : BERGeneralDecoder(inQueue, asnTag) {} + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \details BERSetDecoder uses DefaultTag + explicit BERSetDecoder(BERSetDecoder &inQueue) + : BERGeneralDecoder(inQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 decoder + /// \param inQueue input byte queue + /// \param asnTag ASN.1 tag + explicit BERSetDecoder(BERSetDecoder &inQueue, byte asnTag) + : BERGeneralDecoder(inQueue, asnTag) {} +}; + +/// \brief DER Set Encoder +class CRYPTOPP_DLL DERSetEncoder : public DERGeneralEncoder +{ +public: + /// \brief Default ASN.1 tag + enum {DefaultTag = SET | EnumToInt(CONSTRUCTED)}; + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \details DERSetEncoder uses DefaultTag + explicit DERSetEncoder(BufferedTransformation &outQueue) + : DERGeneralEncoder(outQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \param asnTag ASN.1 tag + explicit DERSetEncoder(BufferedTransformation &outQueue, byte asnTag) + : DERGeneralEncoder(outQueue, asnTag) {} + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \details DERSetEncoder uses DefaultTag + explicit DERSetEncoder(DERSetEncoder &outQueue) + : DERGeneralEncoder(outQueue, DefaultTag) {} + + /// \brief Construct an ASN.1 encoder + /// \param outQueue output byte queue + /// \param asnTag ASN.1 tag + explicit DERSetEncoder(DERSetEncoder &outQueue, byte asnTag) + : DERGeneralEncoder(outQueue, asnTag) {} +}; + +/// \brief Optional data encoder and decoder +/// \tparam T class or type +template +class ASNOptional : public member_ptr +{ +public: + /// \brief BER decode optional data + /// \param seqDecoder sequence with the optional ASN.1 data + /// \param tag ASN.1 tag to match as optional data + /// \param mask the mask to apply when matching the tag + /// \sa ASNTag and ASNIdFlag + void BERDecode(BERSequenceDecoder &seqDecoder, byte tag, byte mask = ~CONSTRUCTED) + { + byte b; + if (seqDecoder.Peek(b) && (b & mask) == tag) + reset(new T(seqDecoder)); + } + + /// \brief DER encode optional data + /// \param out BufferedTransformation object + void DEREncode(BufferedTransformation &out) + { + if (this->get() != NULLPTR) + this->get()->DEREncode(out); + } +}; + +/// \brief Encode and decode ASN.1 objects with additional information +/// \tparam BASE base class or type +/// \details Encodes and decodes public keys, private keys and group +/// parameters with OID identifying the algorithm or scheme. +template +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ASN1CryptoMaterial : public ASN1Object, public BASE +{ +public: + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPublicKeyInfo and privateKeyInfo parts. + void Save(BufferedTransformation &bt) const + {BEREncode(bt);} + + /// \brief BER decode ASN.1 object + /// \param bt BufferedTransformation object + void Load(BufferedTransformation &bt) + {BERDecode(bt);} +}; + +/// \brief Encodes and decodes subjectPublicKeyInfo +class CRYPTOPP_DLL X509PublicKey : public ASN1CryptoMaterial +{ +public: + virtual ~X509PublicKey() {} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Retrieves the OID of the algorithm + /// \return OID of the algorithm + virtual OID GetAlgorithmID() const =0; + + /// \brief Decode algorithm parameters + /// \param bt BufferedTransformation object + /// \sa BERDecodePublicKey, RFC + /// 2459, section 7.3.1 + virtual bool BERDecodeAlgorithmParameters(BufferedTransformation &bt) + {BERDecodeNull(bt); return false;} + + /// \brief Encode algorithm parameters + /// \param bt BufferedTransformation object + /// \sa DEREncodePublicKey, RFC + /// 2459, section 7.3.1 + virtual bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const + {DEREncodeNull(bt); return false;} + + /// \brief Decode subjectPublicKey part of subjectPublicKeyInfo + /// \param bt BufferedTransformation object + /// \param parametersPresent flag indicating if algorithm parameters are present + /// \param size number of octets to read for the parameters, in bytes + /// \details BERDecodePublicKey() the decodes subjectPublicKey part of + /// subjectPublicKeyInfo, without the BIT STRING header. + /// \details When parametersPresent = true then BERDecodePublicKey() calls + /// BERDecodeAlgorithmParameters() to parse algorithm parameters. + /// \sa BERDecodeAlgorithmParameters + virtual void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size) =0; + + /// \brief Encode subjectPublicKey part of subjectPublicKeyInfo + /// \param bt BufferedTransformation object + /// \details DEREncodePublicKey() encodes the subjectPublicKey part of + /// subjectPublicKeyInfo, without the BIT STRING header. + /// \sa DEREncodeAlgorithmParameters + virtual void DEREncodePublicKey(BufferedTransformation &bt) const =0; +}; + +/// \brief Encodes and Decodes privateKeyInfo +class CRYPTOPP_DLL PKCS8PrivateKey : public ASN1CryptoMaterial +{ +public: + virtual ~PKCS8PrivateKey() {} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Retrieves the OID of the algorithm + /// \return OID of the algorithm + virtual OID GetAlgorithmID() const =0; + + /// \brief Decode optional parameters + /// \param bt BufferedTransformation object + /// \sa BERDecodePrivateKey, RFC + /// 2459, section 7.3.1 + virtual bool BERDecodeAlgorithmParameters(BufferedTransformation &bt) + {BERDecodeNull(bt); return false;} + + /// \brief Encode optional parameters + /// \param bt BufferedTransformation object + /// \sa DEREncodePrivateKey, RFC + /// 2459, section 7.3.1 + virtual bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const + {DEREncodeNull(bt); return false;} + + /// \brief Decode privateKey part of privateKeyInfo + /// \param bt BufferedTransformation object + /// \param parametersPresent flag indicating if algorithm parameters are present + /// \param size number of octets to read for the parameters, in bytes + /// \details BERDecodePrivateKey() the decodes privateKey part of privateKeyInfo, + /// without the OCTET STRING header. + /// \details When parametersPresent = true then BERDecodePrivateKey() calls + /// BERDecodeAlgorithmParameters() to parse algorithm parameters. + /// \sa BERDecodeAlgorithmParameters + virtual void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size) =0; + + /// \brief Encode privateKey part of privateKeyInfo + /// \param bt BufferedTransformation object + /// \details DEREncodePrivateKey() encodes the privateKey part of privateKeyInfo, + /// without the OCTET STRING header. + /// \sa DEREncodeAlgorithmParameters + virtual void DEREncodePrivateKey(BufferedTransformation &bt) const =0; + + /// \brief Decode optional attributes + /// \param bt BufferedTransformation object + /// \details BERDecodeOptionalAttributes() decodes optional attributes including + /// context-specific tag. + /// \sa BERDecodeAlgorithmParameters, DEREncodeOptionalAttributes + /// \note default implementation stores attributes to be output using + /// DEREncodeOptionalAttributes + virtual void BERDecodeOptionalAttributes(BufferedTransformation &bt); + + /// \brief Encode optional attributes + /// \param bt BufferedTransformation object + /// \details DEREncodeOptionalAttributes() encodes optional attributes including + /// context-specific tag. + /// \sa BERDecodeAlgorithmParameters + virtual void DEREncodeOptionalAttributes(BufferedTransformation &bt) const; + +protected: + ByteQueue m_optionalAttributes; +}; + +// ******************************************************** + +/// \brief DER Encode unsigned value +/// \tparam T class or type +/// \param out BufferedTransformation object +/// \param w unsigned value to encode +/// \param asnTag the ASN.1 identifier +/// \details DEREncodeUnsigned() can be used with INTEGER, BOOLEAN, and ENUM +template +size_t DEREncodeUnsigned(BufferedTransformation &out, T w, byte asnTag = INTEGER) +{ + byte buf[sizeof(w)+1]; + unsigned int bc; + if (asnTag == BOOLEAN) + { + buf[sizeof(w)] = w ? 0xff : 0; + bc = 1; + } + else + { + buf[0] = 0; + for (unsigned int i=0; i> (sizeof(w)-1-i)*8); + bc = sizeof(w); + while (bc > 1 && buf[sizeof(w)+1-bc] == 0) + --bc; + if (buf[sizeof(w)+1-bc] & 0x80) + ++bc; + } + out.Put(asnTag); + size_t lengthBytes = DERLengthEncode(out, bc); + out.Put(buf+sizeof(w)+1-bc, bc); + return 1+lengthBytes+bc; +} + +/// \brief BER Decode unsigned value +/// \tparam T fundamental C++ type +/// \param in BufferedTransformation object +/// \param w the decoded value +/// \param asnTag the ASN.1 identifier +/// \param minValue the minimum expected value +/// \param maxValue the maximum expected value +/// \throw BERDecodeErr() if the value cannot be parsed or the decoded value is not within range. +/// \details DEREncodeUnsigned() can be used with INTEGER, BOOLEAN, and ENUM +template +void BERDecodeUnsigned(BufferedTransformation &in, T &w, byte asnTag = INTEGER, + T minValue = 0, T maxValue = T(0xffffffff)) +{ + byte b; + if (!in.Get(b) || b != asnTag) + BERDecodeError(); + + size_t bc; + bool definite = BERLengthDecode(in, bc); + if (!definite) + BERDecodeError(); + if (bc > in.MaxRetrievable()) // Issue 346 + BERDecodeError(); + if (asnTag == BOOLEAN && bc != 1) // X.690, 8.2.1 + BERDecodeError(); + if ((asnTag == INTEGER || asnTag == ENUMERATED) && bc == 0) // X.690, 8.3.1 and 8.4 + BERDecodeError(); + + SecByteBlock buf(bc); + + if (bc != in.Get(buf, bc)) + BERDecodeError(); + + // This consumes leading 0 octets. According to X.690, 8.3.2, it could be non-conforming behavior. + // X.690, 8.3.2 says "the bits of the first octet and bit 8 of the second octet ... (a) shall + // not all be ones and (b) shall not all be zeros ... These rules ensure that an integer value + // is always encoded in the smallest possible number of octet". + // We invented AER (Alternate Encoding Rules), which is more relaxed than BER, CER, and DER. + const byte *ptr = buf; + while (bc > sizeof(w) && *ptr == 0) + { + bc--; + ptr++; + } + if (bc > sizeof(w)) + BERDecodeError(); + + w = 0; + for (unsigned int i=0; i maxValue) + BERDecodeError(); +} + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Compare two OIDs for equality +/// \param lhs the first OID +/// \param rhs the second OID +/// \return true if the OIDs are equal, false otherwise +inline bool operator==(const OID &lhs, const OID &rhs); +/// \brief Compare two OIDs for inequality +/// \param lhs the first OID +/// \param rhs the second OID +/// \return true if the OIDs are not equal, false otherwise +inline bool operator!=(const OID &lhs, const OID &rhs); +/// \brief Compare two OIDs for ordering +/// \param lhs the first OID +/// \param rhs the second OID +/// \return true if the first OID is less than the second OID, false otherwise +/// \details operator<() calls std::lexicographical_compare() on the values. +inline bool operator<(const OID &lhs, const OID &rhs); +/// \brief Compare two OIDs for ordering +/// \param lhs the first OID +/// \param rhs the second OID +/// \return true if the first OID is greater than the second OID, false otherwise +/// \details operator>() is implemented in terms of operator==() and operator<(). +/// \since Crypto++ 8.3 +inline bool operator>(const OID &lhs, const OID &rhs); +/// \brief Compare two OIDs for ordering +/// \param lhs the first OID +/// \param rhs the second OID +/// \return true if the first OID is less than or equal to the second OID, false otherwise +/// \details operator<=() is implemented in terms of operator==() and operator<(). +/// \since Crypto++ 8.3 +inline bool operator<=(const OID &lhs, const OID &rhs); +/// \brief Compare two OIDs for ordering +/// \param lhs the first OID +/// \param rhs the second OID +/// \return true if the first OID is greater than or equal to the second OID, false otherwise +/// \details operator>=() is implemented in terms of operator<(). +/// \since Crypto++ 8.3 +inline bool operator>=(const OID &lhs, const OID &rhs); +/// \brief Append a value to an OID +/// \param lhs the OID +/// \param rhs the value to append +inline OID operator+(const OID &lhs, unsigned long rhs); +/// \brief Print a OID value +/// \param out the output stream +/// \param oid the OID +inline std::ostream& operator<<(std::ostream& out, const OID &oid); +#else +inline bool operator==(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return lhs.m_values == rhs.m_values;} +inline bool operator!=(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return lhs.m_values != rhs.m_values;} +inline bool operator<(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return std::lexicographical_compare(lhs.m_values.begin(), lhs.m_values.end(), rhs.m_values.begin(), rhs.m_values.end());} +inline bool operator>(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return ! (lhs=(const ::CryptoPP::OID &lhs, const ::CryptoPP::OID &rhs) + {return ! (lhsThe EAX +/// Mode of Operation. The EAX paper suggested a basic API to help standardize AEAD +/// schemes in software and promote adoption of the modes. +/// \sa Authenticated +/// Encryption on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_AUTHENC_H +#define CRYPTOPP_AUTHENC_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Base class for authenticated encryption modes of operation +/// \details AuthenticatedSymmetricCipherBase() serves as a base implementation for one direction +/// (encryption or decryption) of a stream cipher or block cipher mode with authentication. +/// \details Crypto++ provides four authenticated encryption modes of operation - CCM, EAX, GCM +/// and OCB mode. All modes derive from AuthenticatedSymmetricCipherBase() and the +/// motivation for the API, like calling AAD a "header", can be found in Bellare, +/// Rogaway and Wagner's The EAX +/// Mode of Operation. The EAX paper suggested a basic API to help standardize AEAD +/// schemes in software and promote adoption of the modes. +/// \sa Authenticated +/// Encryption on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedSymmetricCipherBase : public AuthenticatedSymmetricCipher +{ +public: + AuthenticatedSymmetricCipherBase() : m_totalHeaderLength(0), m_totalMessageLength(0), + m_totalFooterLength(0), m_bufferedDataLength(0), m_state(State_Start) {} + + // StreamTransformation interface + bool IsRandomAccess() const {return false;} + bool IsSelfInverting() const {return true;} + + void SetKey(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Restart() {if (m_state > State_KeySet) m_state = State_KeySet;} + void Resynchronize(const byte *iv, int length=-1); + void Update(const byte *input, size_t length); + void ProcessData(byte *outString, const byte *inString, size_t length); + void TruncatedFinal(byte *mac, size_t macSize); + +protected: + void UncheckedSetKey(const byte * key, unsigned int length,const CryptoPP::NameValuePairs ¶ms) + {CRYPTOPP_UNUSED(key), CRYPTOPP_UNUSED(length), CRYPTOPP_UNUSED(params); CRYPTOPP_ASSERT(false);} + + void AuthenticateData(const byte *data, size_t len); + const SymmetricCipher & GetSymmetricCipher() const + {return const_cast(this)->AccessSymmetricCipher();} + + virtual SymmetricCipher & AccessSymmetricCipher() =0; + virtual bool AuthenticationIsOnPlaintext() const =0; + virtual unsigned int AuthenticationBlockSize() const =0; + virtual void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms) =0; + virtual void Resync(const byte *iv, size_t len) =0; + virtual size_t AuthenticateBlocks(const byte *data, size_t len) =0; + virtual void AuthenticateLastHeaderBlock() =0; + virtual void AuthenticateLastConfidentialBlock() {} + virtual void AuthenticateLastFooterBlock(byte *mac, size_t macSize) =0; + + // State_AuthUntransformed: authentication is applied to plain text (Authenticate-then-Encrypt) + // State_AuthTransformed: authentication is applied to cipher text (Encrypt-then-Authenticate) + enum State {State_Start, State_KeySet, State_IVSet, State_AuthUntransformed, State_AuthTransformed, State_AuthFooter}; + + AlignedSecByteBlock m_buffer; + lword m_totalHeaderLength, m_totalMessageLength, m_totalFooterLength; + unsigned int m_bufferedDataLength; + State m_state; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/base32.h b/third_party/cryptoppwin/include/cryptopp/base32.h new file mode 100644 index 00000000..80a64ed8 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/base32.h @@ -0,0 +1,158 @@ +// base32.h - written and placed in the public domain by Frank Palazzolo, based on hex.cpp by Wei Dai +// extended hex alphabet added by JW in November, 2017. + +/// \file base32.h +/// \brief Classes for Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + +#ifndef CRYPTOPP_BASE32_H +#define CRYPTOPP_BASE32_H + +#include "cryptlib.h" +#include "basecode.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Base32 encodes data using DUDE encoding +/// \details Converts data to base32 using DUDE encoding. The default code is based on Differential Unicode Domain Encoding (DUDE) (draft-ietf-idn-dude-02.txt). +/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder +class Base32Encoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a Base32Encoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param uppercase a flag indicating uppercase output + /// \param groupSize the size of the grouping + /// \param separator the separator to use between groups + /// \param terminator the terminator appeand after processing + /// \details Base32Encoder() constructs a default encoder. The constructor lacks fields for padding and + /// line breaks. You must use IsolatedInitialize() to change the default padding character or suppress it. + /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + Base32Encoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "") + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::Uppercase(), uppercase)(Name::GroupSize(), groupSize)(Name::Separator(), ConstByteArrayParameter(separator))(Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The following code modifies the padding and line break parameters for an encoder: + ///
+	///     Base32Encoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	///     encoder.IsolatedInitialize(params);
+ /// \details You can change the encoding to RFC 4648, Base + /// 32 Encoding with Extended Hex Alphabet by performing the following: + ///
+	///     Base32Encoder encoder;
+	///     const byte ALPHABET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+	///     AlgorithmParameters params = MakeParameters(Name::EncodingLookupArray(),(const byte *)ALPHABET);
+	///     encoder.IsolatedInitialize(params);
+ /// \details If you change the encoding alphabet, then you will need to change the decoding alphabet \a and + /// the decoder's lookup table. + /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Base32 decodes data using DUDE encoding +/// \details Converts data from base32 using DUDE encoding. The default code is based on Differential Unicode Domain Encoding (DUDE) (draft-ietf-idn-dude-02.txt). +/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder +class Base32Decoder : public BaseN_Decoder +{ +public: + /// \brief Construct a Base32Decoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \sa IsolatedInitialize() for an example of modifying a Base32Decoder after construction. + Base32Decoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDefaultDecodingLookupArray(), 5, attachment) {} + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details You can change the encoding to RFC 4648, Base + /// 32 Encoding with Extended Hex Alphabet by performing the following: + ///
+	///     int lookup[256];
+	///     const byte ALPHABET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+	///     Base32Decoder::InitializeDecodingLookupArray(lookup, ALPHABET, 32, true /*insensitive*/);
+	///
+	///     Base32Decoder decoder;
+	///     AlgorithmParameters params = MakeParameters(Name::DecodingLookupArray(),(const int *)lookup);
+	///     decoder.IsolatedInitialize(params);
+ /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + /// \brief Provides the default decoding lookup table + /// \return default decoding lookup table + static const int * CRYPTOPP_API GetDefaultDecodingLookupArray(); +}; + +/// \brief Base32 encodes data using extended hex +/// \details Converts data to base32 using extended hex alphabet. The alphabet is different than Base32Encoder. +/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder, RFC 4648, Base 32 Encoding with Extended Hex Alphabet. +/// \since Crypto++ 6.0 +class Base32HexEncoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a Base32HexEncoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param uppercase a flag indicating uppercase output + /// \param groupSize the size of the grouping + /// \param separator the separator to use between groups + /// \param terminator the terminator appeand after processing + /// \details Base32HexEncoder() constructs a default encoder. The constructor lacks fields for padding and + /// line breaks. You must use IsolatedInitialize() to change the default padding character or suppress it. + /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + Base32HexEncoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "") + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::Uppercase(), uppercase)(Name::GroupSize(), groupSize)(Name::Separator(), ConstByteArrayParameter(separator))(Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The following code modifies the padding and line break parameters for an encoder: + ///
+	///     Base32HexEncoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	///     encoder.IsolatedInitialize(params);
+ void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Base32 decodes data using extended hex +/// \details Converts data from base32 using extended hex alphabet. The alphabet is different than Base32Decoder. +/// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder, RFC 4648, Base 32 Encoding with Extended Hex Alphabet. +/// \since Crypto++ 6.0 +class Base32HexDecoder : public BaseN_Decoder +{ +public: + /// \brief Construct a Base32HexDecoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + Base32HexDecoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDefaultDecodingLookupArray(), 5, attachment) {} + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + /// \brief Provides the default decoding lookup table + /// \return default decoding lookup table + static const int * CRYPTOPP_API GetDefaultDecodingLookupArray(); +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/base64.h b/third_party/cryptoppwin/include/cryptopp/base64.h new file mode 100644 index 00000000..be5c6b77 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/base64.h @@ -0,0 +1,158 @@ +// base64.h - originally written and placed in the public domain by Wei Dai + +/// \file base64.h +/// \brief Classes for the Base64Encoder, Base64Decoder, Base64URLEncoder and Base64URLDecoder + +#ifndef CRYPTOPP_BASE64_H +#define CRYPTOPP_BASE64_H + +#include "cryptlib.h" +#include "basecode.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Base64 encodes data using DUDE +/// \details Base64 encodes data per RFC 4648, Base 64 Encoding. +class Base64Encoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a Base64Encoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param insertLineBreaks a BufferedTrasformation to attach to this object + /// \param maxLineLength the length of a line if line breaks are used + /// \details Base64Encoder constructs a default encoder. The constructor lacks a parameter for padding, and you must + /// use IsolatedInitialize() to modify the Base64Encoder after construction. + /// \sa IsolatedInitialize() for an example of modifying an encoder after construction. + Base64Encoder(BufferedTransformation *attachment = NULLPTR, bool insertLineBreaks = true, int maxLineLength = 72) + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::InsertLineBreaks(), insertLineBreaks)(Name::MaxLineLength(), maxLineLength)); + } + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The following code modifies the padding and line break parameters for an encoder: + ///
+	///     Base64Encoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	///     encoder.IsolatedInitialize(params);
+ /// \details You can change the encoding to RFC 4648 web safe alphabet by performing the following: + ///
+	///     Base64Encoder encoder;
+	///     const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+	///     AlgorithmParameters params = MakeParameters(Name::EncodingLookupArray(),(const byte *)ALPHABET);
+	///     encoder.IsolatedInitialize(params);
+ /// \details If you change the encoding alphabet, then you will need to change the decoding alphabet \a and + /// the decoder's lookup table. + /// \sa Base64URLEncoder for an encoder that provides the web safe alphabet, and Base64Decoder::IsolatedInitialize() + /// for an example of modifying a decoder's lookup table after construction. + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Base64 decodes data using DUDE +/// \details Base64 encodes data per RFC 4648, Base 64 Encoding. +class Base64Decoder : public BaseN_Decoder +{ +public: + /// \brief Construct a Base64Decoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \sa IsolatedInitialize() for an example of modifying an encoder after construction. + Base64Decoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDecodingLookupArray(), 6, attachment) {} + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The default decoding alpahbet is RFC 4868. You can change the to RFC 4868 web safe alphabet + /// by performing the following: + ///
+	///     int lookup[256];
+	///     const byte ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+	///     Base64Decoder::InitializeDecodingLookupArray(lookup, ALPHABET, 64, false);
+	///
+	///     Base64Decoder decoder;
+	///     AlgorithmParameters params = MakeParameters(Name::DecodingLookupArray(),(const int *)lookup);
+	///     decoder.IsolatedInitialize(params);
+ /// \sa Base64URLDecoder for a decoder that provides the web safe alphabet, and Base64Encoder::IsolatedInitialize() + /// for an example of modifying an encoder's alphabet after construction. + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + /// \brief Provides the default decoding lookup table + /// \return default decoding lookup table + static const int * CRYPTOPP_API GetDecodingLookupArray(); +}; + +/// \brief Base64 encodes data using a web safe alphabet +/// \details Base64 encodes data per RFC 4648, Base 64 Encoding +/// with URL and Filename Safe Alphabet. +class Base64URLEncoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a Base64URLEncoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param insertLineBreaks a BufferedTrasformation to attach to this object + /// \param maxLineLength the length of a line if line breaks are used + /// \details Base64URLEncoder() constructs a default encoder using a web safe alphabet. The constructor ignores + /// insertLineBreaks and maxLineLength because the web and URL safe specifications don't use them. They are + /// present in the constructor for API compatibility with Base64Encoder so it is a drop-in replacement. The + /// constructor also disables padding on the encoder for the same reason. + /// \details If you need line breaks or padding, then you must use IsolatedInitialize() to set them + /// after constructing a Base64URLEncoder. + /// \sa Base64Encoder for an encoder that provides a classic alphabet, and Base64URLEncoder::IsolatedInitialize + /// for an example of modifying an encoder after construction. + Base64URLEncoder(BufferedTransformation *attachment = NULLPTR, bool insertLineBreaks = false, int maxLineLength = -1) + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + CRYPTOPP_UNUSED(insertLineBreaks), CRYPTOPP_UNUSED(maxLineLength); + IsolatedInitialize(MakeParameters(Name::InsertLineBreaks(), false)(Name::MaxLineLength(), -1)(Name::Pad(),false)); + } + + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + /// transformations. If initialization should be propagated, then use the Initialize() function. + /// \details The following code modifies the padding and line break parameters for an encoder: + ///
+	///     Base64URLEncoder encoder;
+	///     AlgorithmParameters params = MakeParameters(Name::Pad(), true)(Name::InsertLineBreaks(), true);
+	///     encoder.IsolatedInitialize(params);
+ /// \sa Base64Encoder for an encoder that provides a classic alphabet. + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Base64 decodes data using a web safe alphabet +/// \details Base64 encodes data per RFC 4648, Base 64 Encoding +/// with URL and Filename Safe Alphabet. +class Base64URLDecoder : public BaseN_Decoder +{ +public: + /// \brief Construct a Base64URLDecoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \details Base64URLDecoder() constructs a default decoder using a web safe alphabet. + /// \sa Base64Decoder for a decoder that provides a classic alphabet. + Base64URLDecoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDecodingLookupArray(), 6, attachment) {} + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs used to initialize this object + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on + /// attached transformations. If initialization should be propagated, then use the Initialize() function. + /// \sa Base64Decoder for a decoder that provides a classic alphabet, and Base64URLEncoder::IsolatedInitialize + /// for an example of modifying an encoder after construction. + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + /// \brief Provides the default decoding lookup table + /// \return default decoding lookup table + static const int * CRYPTOPP_API GetDecodingLookupArray(); +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/basecode.h b/third_party/cryptoppwin/include/cryptopp/basecode.h new file mode 100644 index 00000000..7158de6a --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/basecode.h @@ -0,0 +1,146 @@ +// basecode.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Base classes for working with encoders and decoders. + +#ifndef CRYPTOPP_BASECODE_H +#define CRYPTOPP_BASECODE_H + +#include "cryptlib.h" +#include "filters.h" +#include "algparam.h" +#include "argnames.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Encoder for bases that are a power of 2 +class CRYPTOPP_DLL BaseN_Encoder : public Unflushable +{ +public: + /// \brief Construct a BaseN_Encoder + /// \param attachment a BufferedTransformation to attach to this object + BaseN_Encoder(BufferedTransformation *attachment=NULLPTR) + : m_alphabet(NULLPTR), m_padding(0), m_bitsPerChar(0) + , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) + {Detach(attachment);} + + /// \brief Construct a BaseN_Encoder + /// \param alphabet table of ASCII characters to use as the alphabet + /// \param log2base the log2base + /// \param attachment a BufferedTransformation to attach to this object + /// \param padding the character to use as padding + /// \pre log2base must be between 1 and 7 inclusive + /// \throw InvalidArgument if log2base is not between 1 and 7 + BaseN_Encoder(const byte *alphabet, int log2base, BufferedTransformation *attachment=NULLPTR, int padding=-1) + : m_alphabet(NULLPTR), m_padding(0), m_bitsPerChar(0) + , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) + { + Detach(attachment); + BaseN_Encoder::IsolatedInitialize( + MakeParameters + (Name::EncodingLookupArray(), alphabet) + (Name::Log2Base(), log2base) + (Name::Pad(), padding != -1) + (Name::PaddingByte(), byte(padding))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + +private: + const byte *m_alphabet; + int m_padding, m_bitsPerChar, m_outputBlockSize; + int m_bytePos, m_bitPos; + SecByteBlock m_outBuf; +}; + +/// \brief Decoder for bases that are a power of 2 +class CRYPTOPP_DLL BaseN_Decoder : public Unflushable +{ +public: + /// \brief Construct a BaseN_Decoder + /// \param attachment a BufferedTransformation to attach to this object + /// \details padding is set to -1, which means use default padding. If not + /// required, then the value must be set via IsolatedInitialize(). + BaseN_Decoder(BufferedTransformation *attachment=NULLPTR) + : m_lookup(NULLPTR), m_bitsPerChar(0) + , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) + {Detach(attachment);} + + /// \brief Construct a BaseN_Decoder + /// \param lookup table of values + /// \param log2base the log2base + /// \param attachment a BufferedTransformation to attach to this object + /// \details log2base is the exponent (like 5 in 25), and not + /// the number of elements (like 32). + /// \details padding is set to -1, which means use default padding. If not + /// required, then the value must be set via IsolatedInitialize(). + BaseN_Decoder(const int *lookup, int log2base, BufferedTransformation *attachment=NULLPTR) + : m_lookup(NULLPTR), m_bitsPerChar(0) + , m_outputBlockSize(0), m_bytePos(0), m_bitPos(0) + { + Detach(attachment); + BaseN_Decoder::IsolatedInitialize( + MakeParameters + (Name::DecodingLookupArray(), lookup) + (Name::Log2Base(), log2base)); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + + /// \brief Initializes BaseN lookup array + /// \param lookup table of values + /// \param alphabet table of ASCII characters + /// \param base the base for the encoder + /// \param caseInsensitive flag indicating whether the alphabet is case sensitivie + /// \pre COUNTOF(lookup) == 256 + /// \pre COUNTOF(alphabet) == base + /// \details Internally, the function sets the first 256 elements in the lookup table to + /// their value from the alphabet array or -1. base is the number of element (like 32), + /// and not an exponent (like 5 in 25) + static void CRYPTOPP_API InitializeDecodingLookupArray(int *lookup, const byte *alphabet, unsigned int base, bool caseInsensitive); + +private: + const int *m_lookup; + int m_bitsPerChar, m_outputBlockSize; + int m_bytePos, m_bitPos; + SecByteBlock m_outBuf; +}; + +/// \brief Filter that breaks input stream into groups of fixed size +class CRYPTOPP_DLL Grouper : public Bufferless +{ +public: + /// \brief Construct a Grouper + /// \param attachment a BufferedTransformation to attach to this object + Grouper(BufferedTransformation *attachment=NULLPTR) + : m_groupSize(0), m_counter(0) {Detach(attachment);} + + /// \brief Construct a Grouper + /// \param groupSize the size of the grouping + /// \param separator the separator to use between groups + /// \param terminator the terminator appeand after processing + /// \param attachment a BufferedTransformation to attach to this object + Grouper(int groupSize, const std::string &separator, const std::string &terminator, BufferedTransformation *attachment=NULLPTR) + : m_groupSize(0), m_counter(0) + { + Detach(attachment); + Grouper::IsolatedInitialize( + MakeParameters + (Name::GroupSize(), groupSize) + (Name::Separator(), ConstByteArrayParameter(separator)) + (Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + +private: + SecByteBlock m_separator, m_terminator; + size_t m_groupSize, m_counter; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/bench.h b/third_party/cryptoppwin/include/cryptopp/bench.h new file mode 100644 index 00000000..561b6578 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/bench.h @@ -0,0 +1,105 @@ +// bench.h - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 + +#ifndef CRYPTOPP_BENCH_H +#define CRYPTOPP_BENCH_H + +#include "cryptlib.h" + +#include +#include +#include +#include + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +// More granular control over benchmarks +enum TestClass { + /// \brief Random number generators + UnkeyedRNG=(1<<0), + /// \brief Message digests + UnkeyedHash=(1<<1), + /// \brief Other unkeyed algorithms + UnkeyedOther=(1<<2), + + /// \brief Message authentication codes + SharedKeyMAC=(1<<3), + /// \brief Stream ciphers + SharedKeyStream=(1<<4), + /// \brief Block ciphers ciphers + SharedKeyBlock=(1<<5), + /// \brief Other shared key algorithms + SharedKeyOther=(1<<6), + + /// \brief Key agreement algorithms over integers + PublicKeyAgreement=(1<<7), + /// \brief Encryption algorithms over integers + PublicKeyEncryption=(1<<8), + /// \brief Signature algorithms over integers + PublicKeySignature=(1<<9), + /// \brief Other public key algorithms over integers + PublicKeyOther=(1<<10), + + /// \brief Key agreement algorithms over EC + PublicKeyAgreementEC=(1<<11), + /// \brief Encryption algorithms over EC + PublicKeyEncryptionEC=(1<<12), + /// \brief Signature algorithms over EC + PublicKeySignatureEC=(1<<13), + /// \brief Other public key algorithms over EC + PublicKeyOtherEC=(1<<14), + + Unkeyed=UnkeyedRNG|UnkeyedHash|UnkeyedOther, + SharedKey=SharedKeyMAC|SharedKeyStream|SharedKeyBlock|SharedKeyOther, + PublicKey=PublicKeyAgreement|PublicKeyEncryption|PublicKeySignature|PublicKeyOther, + PublicKeyEC=PublicKeyAgreementEC|PublicKeyEncryptionEC|PublicKeySignatureEC|PublicKeyOtherEC, + + All=Unkeyed|SharedKey|PublicKey|PublicKeyEC, + + TestFirst=(0), TestLast=(1<<15) +}; + +extern const double CLOCK_TICKS_PER_SECOND; +extern double g_allocatedTime; +extern double g_hertz; +extern double g_logTotal; +extern unsigned int g_logCount; +extern const byte defaultKey[]; + +// Test book keeping +extern time_t g_testBegin; +extern time_t g_testEnd; + +// Benchmark command handler +void BenchmarkWithCommand(int argc, const char* const argv[]); +// Top level, prints preamble and postamble +void Benchmark(Test::TestClass suites, double t, double hertz); +// Unkeyed systems +void BenchmarkUnkeyedAlgorithms(double t, double hertz); +// Shared key systems +void BenchmarkSharedKeyedAlgorithms(double t, double hertz); +// Public key systems over integers +void BenchmarkPublicKeyAlgorithms(double t, double hertz); +// Public key systems over elliptic curves +void BenchmarkEllipticCurveAlgorithms(double t, double hertz); + +// These are defined in bench1.cpp +extern void OutputResultKeying(double iterations, double timeTaken); +extern void OutputResultBytes(const char *name, const char *provider, double length, double timeTaken); +extern void OutputResultOperations(const char *name, const char *provider, const char *operation, bool pc, unsigned long iterations, double timeTaken); + +// These are defined in bench1.cpp +extern void BenchMark(const char *name, BufferedTransformation &bt, double timeTotal); +extern void BenchMark(const char *name, StreamTransformation &cipher, double timeTotal); +extern void BenchMark(const char *name, HashTransformation &ht, double timeTotal); +extern void BenchMark(const char *name, RandomNumberGenerator &rng, double timeTotal); + +// These are defined in bench2.cpp +extern void BenchMarkKeying(SimpleKeyingInterface &c, size_t keyLength, const NameValuePairs ¶ms); +extern void BenchMark(const char *name, AuthenticatedSymmetricCipher &cipher, double timeTotal); + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/blake2.h b/third_party/cryptoppwin/include/cryptopp/blake2.h new file mode 100644 index 00000000..bbbe134b --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/blake2.h @@ -0,0 +1,444 @@ +// blake2.h - written and placed in the public domain by Jeffrey Walton +// and Zooko Wilcox-O'Hearn. Based on Aumasson, Neves, +// Wilcox-O'Hearn and Winnerlein's reference BLAKE2 +// implementation at http://github.com/BLAKE2/BLAKE2. + +/// \file blake2.h +/// \brief Classes for BLAKE2b and BLAKE2s message digests and keyed message digests +/// \details This implementation follows Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's +/// BLAKE2: simpler, smaller, fast as MD5 (2013.01.29). +/// Static algorithm name return either "BLAKE2b" or "BLAKE2s". An object algorithm name follows +/// the naming described in RFC 7693, The +/// BLAKE2 Cryptographic Hash and Message Authentication Code (MAC). +/// \since C++ since Crypto++ 5.6.4, SSE since Crypto++ 5.6.4, NEON since Crypto++ 6.0, +/// Power8 since Crypto++ 8.0 + +#ifndef CRYPTOPP_BLAKE2_H +#define CRYPTOPP_BLAKE2_H + +#include "cryptlib.h" +#include "secblock.h" +#include "seckey.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief BLAKE2s hash information +/// \since Crypto++ 5.6.4 +struct BLAKE2s_Info : public VariableKeyLength<32,0,32,1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> +{ + typedef VariableKeyLength<32,0,32,1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> KeyBase; + CRYPTOPP_CONSTANT(MIN_KEYLENGTH = KeyBase::MIN_KEYLENGTH); + CRYPTOPP_CONSTANT(MAX_KEYLENGTH = KeyBase::MAX_KEYLENGTH); + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = KeyBase::DEFAULT_KEYLENGTH); + + CRYPTOPP_CONSTANT(BLOCKSIZE = 64); + CRYPTOPP_CONSTANT(DIGESTSIZE = 32); + CRYPTOPP_CONSTANT(SALTSIZE = 8); + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = 8); + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BLAKE2s";} +}; + +/// \brief BLAKE2b hash information +/// \since Crypto++ 5.6.4 +struct BLAKE2b_Info : public VariableKeyLength<64,0,64,1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> +{ + typedef VariableKeyLength<64,0,64,1,SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> KeyBase; + CRYPTOPP_CONSTANT(MIN_KEYLENGTH = KeyBase::MIN_KEYLENGTH); + CRYPTOPP_CONSTANT(MAX_KEYLENGTH = KeyBase::MAX_KEYLENGTH); + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = KeyBase::DEFAULT_KEYLENGTH); + + CRYPTOPP_CONSTANT(BLOCKSIZE = 128); + CRYPTOPP_CONSTANT(DIGESTSIZE = 64); + CRYPTOPP_CONSTANT(SALTSIZE = 16); + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = 16); + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BLAKE2b";} +}; + +/// \brief BLAKE2s parameter block +struct CRYPTOPP_NO_VTABLE BLAKE2s_ParameterBlock +{ + CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2s_Info::SALTSIZE); + CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2s_Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2s_Info::PERSONALIZATIONSIZE); + + BLAKE2s_ParameterBlock() + { + Reset(); + } + + BLAKE2s_ParameterBlock(size_t digestSize) + { + Reset(digestSize); + } + + BLAKE2s_ParameterBlock(size_t digestSize, size_t keyLength, const byte* salt, size_t saltLength, + const byte* personalization, size_t personalizationLength); + + void Reset(size_t digestLength=DIGESTSIZE, size_t keyLength=0); + + byte* data() { + return m_data.data(); + } + + const byte* data() const { + return m_data.data(); + } + + size_t size() const { + return m_data.size(); + } + + byte* salt() { + return m_data + SaltOff; + } + + byte* personalization() { + return m_data + PersonalizationOff; + } + + // Offsets into the byte array + enum { + DigestOff = 0, KeyOff = 1, FanoutOff = 2, DepthOff = 3, LeafOff = 4, NodeOff = 8, + NodeDepthOff = 14, InnerOff = 15, SaltOff = 16, PersonalizationOff = 24 + }; + + FixedSizeAlignedSecBlock m_data; +}; + +/// \brief BLAKE2b parameter block +struct CRYPTOPP_NO_VTABLE BLAKE2b_ParameterBlock +{ + CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2b_Info::SALTSIZE); + CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2b_Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2b_Info::PERSONALIZATIONSIZE); + + BLAKE2b_ParameterBlock() + { + Reset(); + } + + BLAKE2b_ParameterBlock(size_t digestSize) + { + Reset(digestSize); + } + + BLAKE2b_ParameterBlock(size_t digestSize, size_t keyLength, const byte* salt, size_t saltLength, + const byte* personalization, size_t personalizationLength); + + void Reset(size_t digestLength=DIGESTSIZE, size_t keyLength=0); + + byte* data() { + return m_data.data(); + } + + const byte* data() const { + return m_data.data(); + } + + size_t size() const { + return m_data.size(); + } + + byte* salt() { + return m_data + SaltOff; + } + + byte* personalization() { + return m_data + PersonalizationOff; + } + + // Offsets into the byte array + enum { + DigestOff = 0, KeyOff = 1, FanoutOff = 2, DepthOff = 3, LeafOff = 4, NodeOff = 8, + NodeDepthOff = 16, InnerOff = 17, RfuOff = 18, SaltOff = 32, PersonalizationOff = 48 + }; + + FixedSizeAlignedSecBlock m_data; +}; + +/// \brief BLAKE2s state information +/// \since Crypto++ 5.6.4 +struct CRYPTOPP_NO_VTABLE BLAKE2s_State +{ + BLAKE2s_State() { + Reset(); + } + + void Reset(); + + inline word32* h() { + return m_hft.data(); + } + + inline word32* t() { + return m_hft.data() + 8; + } + + inline word32* f() { + return m_hft.data() + 10; + } + + inline byte* data() { + return m_buf.data(); + } + + // SSE4, Power7 and NEON depend upon t[] and f[] being side-by-side + CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2s_Info::BLOCKSIZE); + FixedSizeAlignedSecBlock m_hft; + FixedSizeAlignedSecBlock m_buf; + size_t m_len; +}; + +/// \brief BLAKE2b state information +/// \since Crypto++ 5.6.4 +struct CRYPTOPP_NO_VTABLE BLAKE2b_State +{ + BLAKE2b_State() { + Reset(); + } + + void Reset(); + + inline word64* h() { + return m_hft.data(); + } + + inline word64* t() { + return m_hft.data() + 8; + } + + inline word64* f() { + return m_hft.data() + 10; + } + + inline byte* data() { + return m_buf.data(); + } + + // SSE4, Power8 and NEON depend upon t[] and f[] being side-by-side + CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2b_Info::BLOCKSIZE); + FixedSizeAlignedSecBlock m_hft; + FixedSizeAlignedSecBlock m_buf; + size_t m_len; +}; + +/// \brief The BLAKE2s cryptographic hash function +/// \details BLAKE2s can function as both a hash and keyed hash. If you want only the hash, +/// then use the BLAKE2s constructor that accepts no parameters or digest size. If you +/// want a keyed hash, then use the constructor that accpts the key as a parameter. +/// Once a key and digest size are selected, its effectively immutable. The Restart() +/// method that accepts a ParameterBlock does not allow you to change it. +/// \sa Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's +/// BLAKE2: simpler, smaller, fast as MD5 (2013.01.29). +/// \since C++ since Crypto++ 5.6.4, SSE since Crypto++ 5.6.4, NEON since Crypto++ 6.0, +/// Power8 since Crypto++ 8.0 +class BLAKE2s : public SimpleKeyingInterfaceImpl +{ +public: + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = BLAKE2s_Info::DEFAULT_KEYLENGTH); + CRYPTOPP_CONSTANT(MIN_KEYLENGTH = BLAKE2s_Info::MIN_KEYLENGTH); + CRYPTOPP_CONSTANT(MAX_KEYLENGTH = BLAKE2s_Info::MAX_KEYLENGTH); + + CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2s_Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2s_Info::BLOCKSIZE); + CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2s_Info::SALTSIZE); + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2s_Info::PERSONALIZATIONSIZE); + + typedef BLAKE2s_State State; + typedef BLAKE2s_ParameterBlock ParameterBlock; + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BLAKE2s";} + + virtual ~BLAKE2s() {} + + /// \brief Construct a BLAKE2s hash + /// \param digestSize the digest size, in bytes + /// \param treeMode flag indicating tree mode + /// \since Crypto++ 5.6.4 + BLAKE2s(bool treeMode=false, unsigned int digestSize = DIGESTSIZE); + + /// \brief Construct a BLAKE2s hash + /// \param digestSize the digest size, in bytes + /// \details treeMode flag is set to false + /// \since Crypto++ 8.2 + BLAKE2s(unsigned int digestSize); + + /// \brief Construct a BLAKE2s hash + /// \param key a byte array used to key the cipher + /// \param keyLength the size of the byte array + /// \param salt a byte array used as salt + /// \param saltLength the size of the byte array + /// \param personalization a byte array used as personalization string + /// \param personalizationLength the size of the byte array + /// \param treeMode flag indicating tree mode + /// \param digestSize the digest size, in bytes + /// \since Crypto++ 5.6.4 + BLAKE2s(const byte *key, size_t keyLength, const byte* salt = NULLPTR, size_t saltLength = 0, + const byte* personalization = NULLPTR, size_t personalizationLength = 0, + bool treeMode=false, unsigned int digestSize = DIGESTSIZE); + + /// \brief Retrieve the object's name + /// \return the object's algorithm name following RFC 7693 + /// \details Object algorithm name follows the naming described in + /// RFC 7693, The BLAKE2 Cryptographic Hash and + /// Message Authentication Code (MAC). For example, "BLAKE2b-512" and "BLAKE2s-256". + std::string AlgorithmName() const {return std::string(BLAKE2s_Info::StaticAlgorithmName()) + "-" + IntToString(DigestSize()*8);} + + unsigned int BlockSize() const {return BLOCKSIZE;} + unsigned int DigestSize() const {return m_digestSize;} + unsigned int OptimalDataAlignment() const; + + void Update(const byte *input, size_t length); + void Restart(); + + /// \brief Restart a hash with parameter block and counter + /// \param block parameter block + /// \param counter counter array + /// \details Parameter block is persisted across calls to Restart(). + void Restart(const BLAKE2s_ParameterBlock& block, const word32 counter[2]); + + /// \brief Set tree mode + /// \param mode the new tree mode + /// \details BLAKE2 has two finalization flags, called State::f[0] and State::f[1]. + /// If treeMode=false (default), then State::f[1] is never set. If + /// treeMode=true, then State::f[1] is set when State::f[0] is set. + /// Tree mode is persisted across calls to Restart(). + void SetTreeMode(bool mode) {m_treeMode=mode;} + + /// \brief Get tree mode + /// \return the current tree mode + /// \details Tree mode is persisted across calls to Restart(). + bool GetTreeMode() const {return m_treeMode;} + + void TruncatedFinal(byte *hash, size_t size); + + std::string AlgorithmProvider() const; + +protected: + // Operates on state buffer and/or input. Must be BLOCKSIZE, final block will pad with 0's. + void Compress(const byte *input); + inline void IncrementCounter(size_t count=BLOCKSIZE); + + void UncheckedSetKey(const byte* key, unsigned int length, const CryptoPP::NameValuePairs& params); + +private: + State m_state; + ParameterBlock m_block; + AlignedSecByteBlock m_key; + word32 m_digestSize, m_keyLength; + bool m_treeMode; +}; + +/// \brief The BLAKE2b cryptographic hash function +/// \details BLAKE2b can function as both a hash and keyed hash. If you want only the hash, +/// then use the BLAKE2b constructor that accepts no parameters or digest size. If you +/// want a keyed hash, then use the constructor that accpts the key as a parameter. +/// Once a key and digest size are selected, its effectively immutable. The Restart() +/// method that accepts a ParameterBlock does not allow you to change it. +/// \sa Aumasson, Neves, Wilcox-O'Hearn and Winnerlein's +/// BLAKE2: simpler, smaller, fast as MD5 (2013.01.29). +/// \since C++ since Crypto++ 5.6.4, SSE since Crypto++ 5.6.4, NEON since Crypto++ 6.0, +/// Power8 since Crypto++ 8.0 +class BLAKE2b : public SimpleKeyingInterfaceImpl +{ +public: + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH = BLAKE2b_Info::DEFAULT_KEYLENGTH); + CRYPTOPP_CONSTANT(MIN_KEYLENGTH = BLAKE2b_Info::MIN_KEYLENGTH); + CRYPTOPP_CONSTANT(MAX_KEYLENGTH = BLAKE2b_Info::MAX_KEYLENGTH); + + CRYPTOPP_CONSTANT(DIGESTSIZE = BLAKE2b_Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(BLOCKSIZE = BLAKE2b_Info::BLOCKSIZE); + CRYPTOPP_CONSTANT(SALTSIZE = BLAKE2b_Info::SALTSIZE); + CRYPTOPP_CONSTANT(PERSONALIZATIONSIZE = BLAKE2b_Info::PERSONALIZATIONSIZE); + + typedef BLAKE2b_State State; + typedef BLAKE2b_ParameterBlock ParameterBlock; + + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BLAKE2b";} + + virtual ~BLAKE2b() {} + + /// \brief Construct a BLAKE2b hash + /// \param digestSize the digest size, in bytes + /// \param treeMode flag indicating tree mode + /// \since Crypto++ 5.6.4 + BLAKE2b(bool treeMode=false, unsigned int digestSize = DIGESTSIZE); + + /// \brief Construct a BLAKE2s hash + /// \param digestSize the digest size, in bytes + /// \details treeMode flag is set to false + /// \since Crypto++ 8.2 + BLAKE2b(unsigned int digestSize); + + /// \brief Construct a BLAKE2b hash + /// \param key a byte array used to key the cipher + /// \param keyLength the size of the byte array + /// \param salt a byte array used as salt + /// \param saltLength the size of the byte array + /// \param personalization a byte array used as personalization string + /// \param personalizationLength the size of the byte array + /// \param treeMode flag indicating tree mode + /// \param digestSize the digest size, in bytes + /// \since Crypto++ 5.6.4 + BLAKE2b(const byte *key, size_t keyLength, const byte* salt = NULLPTR, size_t saltLength = 0, + const byte* personalization = NULLPTR, size_t personalizationLength = 0, + bool treeMode=false, unsigned int digestSize = DIGESTSIZE); + + /// \brief Retrieve the object's name + /// \return the object's algorithm name following RFC 7693 + /// \details Object algorithm name follows the naming described in + /// RFC 7693, The BLAKE2 Cryptographic Hash and + /// Message Authentication Code (MAC). For example, "BLAKE2b-512" and "BLAKE2s-256". + std::string AlgorithmName() const {return std::string(BLAKE2b_Info::StaticAlgorithmName()) + "-" + IntToString(DigestSize()*8);} + + unsigned int BlockSize() const {return BLOCKSIZE;} + unsigned int DigestSize() const {return m_digestSize;} + unsigned int OptimalDataAlignment() const; + + void Update(const byte *input, size_t length); + void Restart(); + + /// \brief Restart a hash with parameter block and counter + /// \param block parameter block + /// \param counter counter array + /// \details Parameter block is persisted across calls to Restart(). + void Restart(const BLAKE2b_ParameterBlock& block, const word64 counter[2]); + + /// \brief Set tree mode + /// \param mode the new tree mode + /// \details BLAKE2 has two finalization flags, called State::f[0] and State::f[1]. + /// If treeMode=false (default), then State::f[1] is never set. If + /// treeMode=true, then State::f[1] is set when State::f[0] is set. + /// Tree mode is persisted across calls to Restart(). + void SetTreeMode(bool mode) {m_treeMode=mode;} + + /// \brief Get tree mode + /// \return the current tree mode + /// \details Tree mode is persisted across calls to Restart(). + bool GetTreeMode() const {return m_treeMode;} + + void TruncatedFinal(byte *hash, size_t size); + + std::string AlgorithmProvider() const; + +protected: + + // Operates on state buffer and/or input. Must be BLOCKSIZE, final block will pad with 0's. + void Compress(const byte *input); + inline void IncrementCounter(size_t count=BLOCKSIZE); + + void UncheckedSetKey(const byte* key, unsigned int length, const CryptoPP::NameValuePairs& params); + +private: + State m_state; + ParameterBlock m_block; + AlignedSecByteBlock m_key; + word32 m_digestSize, m_keyLength; + bool m_treeMode; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/blowfish.h b/third_party/cryptoppwin/include/cryptopp/blowfish.h new file mode 100644 index 00000000..8032491e --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/blowfish.h @@ -0,0 +1,54 @@ +// blowfish.h - originally written and placed in the public domain by Wei Dai + +/// \file blowfish.h +/// \brief Classes for the Blowfish block cipher + +#ifndef CRYPTOPP_BLOWFISH_H +#define CRYPTOPP_BLOWFISH_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Blowfish block cipher information +struct Blowfish_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 4, 56>, public FixedRounds<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Blowfish";} +}; + +// Blowfish + +/// \brief Blowfish block cipher +/// \since Crypto++ 1.0 +class Blowfish : public Blowfish_Info, public BlockCipherDocumentation +{ + /// \brief Class specific implementation and overrides used to operate the cipher. + /// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + void UncheckedSetKey(const byte *key_string, unsigned int keylength, const NameValuePairs ¶ms); + + private: + void crypt_block(const word32 in[2], word32 out[2]) const; + + static const word32 p_init[ROUNDS+2]; + static const word32 s_init[4*256]; + + FixedSizeSecBlock pbox; + FixedSizeSecBlock sbox; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Blowfish::Encryption BlowfishEncryption; +typedef Blowfish::Decryption BlowfishDecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/blumshub.h b/third_party/cryptoppwin/include/cryptopp/blumshub.h new file mode 100644 index 00000000..997a5152 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/blumshub.h @@ -0,0 +1,70 @@ +// blumshub.h - originally written and placed in the public domain by Wei Dai + +/// \file blumshub.h +/// \brief Classes for Blum Blum Shub generator + +#ifndef CRYPTOPP_BLUMSHUB_H +#define CRYPTOPP_BLUMSHUB_H + +#include "cryptlib.h" +#include "modarith.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief BlumBlumShub without factorization of the modulus +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +class PublicBlumBlumShub : public RandomNumberGenerator, + public StreamTransformation +{ +public: + virtual ~PublicBlumBlumShub() {} + + /// \brief Construct a PublicBlumBlumShub + /// \param n the modulus + /// \param seed the seed for the generator + /// \details seed is the secret key and should be about as large as n. + PublicBlumBlumShub(const Integer &n, const Integer &seed); + + unsigned int GenerateBit(); + byte GenerateByte(); + void GenerateBlock(byte *output, size_t size); + void ProcessData(byte *outString, const byte *inString, size_t length); + + bool IsSelfInverting() const {return true;} + bool IsForwardTransformation() const {return true;} + +protected: + ModularArithmetic modn; + Integer current; + word maxBits, bitsLeft; +}; + +/// \brief BlumBlumShub with factorization of the modulus +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +class BlumBlumShub : public PublicBlumBlumShub +{ +public: + virtual ~BlumBlumShub() {} + + /// \brief Construct a BlumBlumShub + /// \param p the first prime factor + /// \param q the second prime factor + /// \param seed the seed for the generator + /// \details Esure p and q are both primes congruent to 3 mod 4 and at least 512 bits long. + /// seed is the secret key and should be about as large as p*q. + BlumBlumShub(const Integer &p, const Integer &q, const Integer &seed); + + bool IsRandomAccess() const {return true;} + void Seek(lword index); + +protected: + const Integer p, q; + const Integer x0; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/camellia.h b/third_party/cryptoppwin/include/cryptopp/camellia.h new file mode 100644 index 00000000..2d551dcd --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/camellia.h @@ -0,0 +1,49 @@ +// camellia.h - originally written and placed in the public domain by Wei Dai + +/// \file camellia.h +/// \brief Classes for the Camellia block cipher + +#ifndef CRYPTOPP_CAMELLIA_H +#define CRYPTOPP_CAMELLIA_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Camellia block cipher information +struct Camellia_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Camellia";} +}; + +/// \brief Camellia block cipher +/// \sa Camellia +class Camellia : public Camellia_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + CRYPTOPP_ALIGN_DATA(4) static const byte s1[256]; + static const word32 SP[4][256]; + + unsigned int m_rounds; + SecBlock m_key; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Camellia::Encryption CamelliaEncryption; +typedef Camellia::Decryption CamelliaDecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/cast.h b/third_party/cryptoppwin/include/cryptopp/cast.h new file mode 100644 index 00000000..424cf62b --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/cast.h @@ -0,0 +1,109 @@ +// cast.h - originally written and placed in the public domain by Wei Dai + +/// \file cast.h +/// \brief Classes for the CAST-128 and CAST-256 block ciphers +/// \since Crypto++ 2.2 + +#ifndef CRYPTOPP_CAST_H +#define CRYPTOPP_CAST_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CAST block cipher base +/// \since Crypto++ 2.2 +class CAST +{ +protected: + static const word32 S[8][256]; +}; + +/// \brief CAST128 block cipher information +/// \since Crypto++ 2.2 +struct CAST128_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 5, 16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CAST-128";} +}; + +/// \brief CAST128 block cipher +/// \sa CAST-128 +/// \since Crypto++ 2.2 +class CAST128 : public CAST128_Info, public BlockCipherDocumentation +{ + /// \brief CAST128 block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public CAST, public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + bool reduced; + FixedSizeSecBlock K; + mutable FixedSizeSecBlock m_t; + }; + + /// \brief CAST128 block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief CAST128 block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief CAST256 block cipher information +/// \since Crypto++ 4.0 +struct CAST256_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 4> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CAST-256";} +}; + +/// \brief CAST256 block cipher +/// \sa CAST-256 +/// \since Crypto++ 4.0 +class CAST256 : public CAST256_Info, public BlockCipherDocumentation +{ + /// \brief CAST256 block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public CAST, public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + static const word32 t_m[8][24]; + static const unsigned int t_r[8][24]; + + static void Omega(int i, word32 kappa[8]); + + FixedSizeSecBlock K; + mutable FixedSizeSecBlock kappa; + mutable FixedSizeSecBlock m_t; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef CAST128::Encryption CAST128Encryption; +typedef CAST128::Decryption CAST128Decryption; + +typedef CAST256::Encryption CAST256Encryption; +typedef CAST256::Decryption CAST256Decryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/cbcmac.h b/third_party/cryptoppwin/include/cryptopp/cbcmac.h new file mode 100644 index 00000000..5a0c1201 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/cbcmac.h @@ -0,0 +1,63 @@ +// cbcmac.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Classes for CBC MAC +/// \since Crypto++ 3.1 + +#ifndef CRYPTOPP_CBCMAC_H +#define CRYPTOPP_CBCMAC_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CBC-MAC base class +/// \since Crypto++ 3.1 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_MAC_Base : public MessageAuthenticationCode +{ +public: + CBC_MAC_Base() : m_counter(0) {} + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + unsigned int DigestSize() const {return const_cast(this)->AccessCipher().BlockSize();} + +protected: + virtual BlockCipher & AccessCipher() =0; + +private: + void ProcessBuf(); + SecByteBlock m_reg; + unsigned int m_counter; +}; + +/// \brief CBC-MAC +/// \tparam T BlockCipherDocumentation derived class +/// \details CBC-MAC is compatible with FIPS 113. The MAC is secure only for fixed +/// length messages. For variable length messages use CMAC or DMAC. +/// \sa CBC-MAC +/// \since Crypto++ 3.1 +template +class CBC_MAC : public MessageAuthenticationCodeImpl >, public SameKeyLengthAs +{ +public: + /// \brief Construct a CBC_MAC + CBC_MAC() {} + /// \brief Construct a CBC_MAC + /// \param key a byte buffer used to key the cipher + /// \param length the length of the byte buffer + CBC_MAC(const byte *key, size_t length=SameKeyLengthAs::DEFAULT_KEYLENGTH) + {this->SetKey(key, length);} + + static std::string StaticAlgorithmName() {return std::string("CBC-MAC(") + T::StaticAlgorithmName() + ")";} + +private: + BlockCipher & AccessCipher() {return m_cipher;} + typename T::Encryption m_cipher; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/ccm.h b/third_party/cryptoppwin/include/cryptopp/ccm.h new file mode 100644 index 00000000..f4f8ab05 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/ccm.h @@ -0,0 +1,123 @@ +// ccm.h - originally written and placed in the public domain by Wei Dai + +/// \file ccm.h +/// \brief CCM block cipher mode of operation +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_CCM_H +#define CRYPTOPP_CCM_H + +#include "authenc.h" +#include "modes.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CCM block cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CCM_Base : public AuthenticatedSymmetricCipherBase +{ +public: + CCM_Base() + : m_digestSize(0), m_L(0), m_messageLength(0), m_aadLength(0) {} + + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return GetBlockCipher().AlgorithmName() + std::string("/CCM");} + std::string AlgorithmProvider() const + {return GetBlockCipher().AlgorithmProvider();} + size_t MinKeyLength() const + {return GetBlockCipher().MinKeyLength();} + size_t MaxKeyLength() const + {return GetBlockCipher().MaxKeyLength();} + size_t DefaultKeyLength() const + {return GetBlockCipher().DefaultKeyLength();} + size_t GetValidKeyLength(size_t keylength) const + {return GetBlockCipher().GetValidKeyLength(keylength);} + bool IsValidKeyLength(size_t keylength) const + {return GetBlockCipher().IsValidKeyLength(keylength);} + unsigned int OptimalDataAlignment() const + {return GetBlockCipher().OptimalDataAlignment();} + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return 8;} + unsigned int MinIVLength() const + {return 7;} + unsigned int MaxIVLength() const + {return 13;} + unsigned int DigestSize() const + {return m_digestSize;} + lword MaxHeaderLength() const + {return W64LIT(0)-1;} + lword MaxMessageLength() const + {return m_L<8 ? (W64LIT(1)<<(8*m_L))-1 : W64LIT(0)-1;} + bool NeedsPrespecifiedDataLengths() const + {return true;} + void UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength); + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const + {return true;} + unsigned int AuthenticationBlockSize() const + {return GetBlockCipher().BlockSize();} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastConfidentialBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + SymmetricCipher & AccessSymmetricCipher() {return m_ctr;} + + virtual BlockCipher & AccessBlockCipher() =0; + virtual int DefaultDigestSize() const =0; + + const BlockCipher & GetBlockCipher() const {return const_cast(this)->AccessBlockCipher();} + byte *CBC_Buffer() {return m_buffer+REQUIRED_BLOCKSIZE;} + + enum {REQUIRED_BLOCKSIZE = 16}; + int m_digestSize, m_L; + word64 m_messageLength, m_aadLength; + CTR_Mode_ExternalCipher::Encryption m_ctr; +}; + +/// \brief CCM block cipher final implementation +/// \tparam T_BlockCipher block cipher +/// \tparam T_DefaultDigestSize default digest size, in bytes +/// \tparam T_IsEncryption direction in which to operate the cipher +/// \since Crypto++ 5.6.0 +template +class CCM_Final : public CCM_Base +{ +public: + static std::string StaticAlgorithmName() + {return T_BlockCipher::StaticAlgorithmName() + std::string("/CCM");} + bool IsForwardTransformation() const + {return T_IsEncryption;} + +private: + BlockCipher & AccessBlockCipher() {return m_cipher;} + int DefaultDigestSize() const {return T_DefaultDigestSize;} + typename T_BlockCipher::Encryption m_cipher; +}; + +/// \brief CCM block cipher mode of operation +/// \tparam T_BlockCipher block cipher +/// \tparam T_DefaultDigestSize default digest size, in bytes +/// \details \p CCM provides the \p Encryption and \p Decryption typedef. See GCM_Base +/// and GCM_Final for the AuthenticatedSymmetricCipher implementation. +/// \sa CCM Mode and +/// Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +template +struct CCM : public AuthenticatedSymmetricCipherDocumentation +{ + typedef CCM_Final Encryption; + typedef CCM_Final Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/chacha.h b/third_party/cryptoppwin/include/cryptopp/chacha.h new file mode 100644 index 00000000..8b21ebb2 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/chacha.h @@ -0,0 +1,223 @@ +// chacha.h - written and placed in the public domain by Jeffrey Walton. +// Based on Wei Dai's Salsa20, Botan's SSE2 implementation, +// and Bernstein's reference ChaCha family implementation at +// http://cr.yp.to/chacha.html. + +// The library added Bernstein's ChaCha classes at Crypto++ 5.6.4. The IETF +// uses a slightly different implementation than Bernstein, and the IETF +// ChaCha and XChaCha classes were added at Crypto++ 8.1. We wanted to maintain +// ABI compatibility at the 8.1 release so the original ChaCha classes were not +// disturbed. Instead new classes were added for IETF ChaCha. The back-end +// implementation shares code as expected, however. + +/// \file chacha.h +/// \brief Classes for ChaCha8, ChaCha12 and ChaCha20 stream ciphers +/// \details Crypto++ provides Bernstein and ECRYPT's ChaCha from ChaCha, a +/// variant of Salsa20 (2008.01.28). Crypto++ also provides the +/// IETF implementation of ChaCha using the ChaChaTLS name. Bernstein's +/// implementation is _slightly_ different from the TLS working group's +/// implementation for cipher suites +/// TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +/// TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, +/// and TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. Finally, +/// the library provides XChaCha: +/// eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 (rev. 03). +/// \since ChaCha since Crypto++ 5.6.4, ChaChaTLS and XChaCha20 since Crypto++ 8.1 + +#ifndef CRYPTOPP_CHACHA_H +#define CRYPTOPP_CHACHA_H + +#include "strciphr.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +////////////////////////////// Bernstein ChaCha ////////////////////////////// + +/// \brief ChaCha stream cipher information +/// \since Crypto++ 5.6.4 +struct ChaCha_Info : public VariableKeyLength<32, 16, 32, 16, SimpleKeyingInterface::UNIQUE_IV, 8> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + /// \details Bernstein named the cipher variants ChaCha8, ChaCha12 and + /// ChaCha20. More generally, Bernstein called the family ChaCha{r}. + /// AlgorithmName() provides the exact name once rounds are set. + static const char* StaticAlgorithmName() { + return "ChaCha"; + } +}; + +/// \brief ChaCha stream cipher implementation +/// \since Crypto++ 5.6.4 +class CRYPTOPP_NO_VTABLE ChaCha_Policy : public AdditiveCipherConcretePolicy +{ +public: + virtual ~ChaCha_Policy() {} + ChaCha_Policy() : m_rounds(ROUNDS) {} + +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return true;} + void SeekToIteration(lword iterationCount); + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; + + std::string AlgorithmName() const; + std::string AlgorithmProvider() const; + + CRYPTOPP_CONSTANT(ROUNDS = 20); // Default rounds + FixedSizeAlignedSecBlock m_state; + unsigned int m_rounds; +}; + +/// \brief ChaCha stream cipher +/// \details This is Bernstein and ECRYPT's ChaCha. It is _slightly_ different +/// from the IETF's version of ChaCha called ChaChaTLS. +/// \sa ChaCha, a variant +/// of Salsa20 (2008.01.28). +/// \since Crypto++ 5.6.4 +struct ChaCha : public ChaCha_Info, public SymmetricCipherDocumentation +{ + /// \brief ChaCha Encryption + typedef SymmetricCipherFinal >, ChaCha_Info > Encryption; + /// \brief ChaCha Decryption + typedef Encryption Decryption; +}; + +////////////////////////////// IETF ChaChaTLS ////////////////////////////// + +/// \brief IETF ChaCha20 stream cipher information +/// \since Crypto++ 8.1 +struct ChaChaTLS_Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 12>, FixedRounds<20> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + /// \details This is the IETF's variant of Bernstein's ChaCha from RFC + /// 8439. IETF ChaCha is called ChaChaTLS in the Crypto++ library. It + /// is _slightly_ different from Bernstein's implementation. + static const char* StaticAlgorithmName() { + return "ChaChaTLS"; + } +}; + +/// \brief IETF ChaCha20 stream cipher implementation +/// \since Crypto++ 8.1 +class CRYPTOPP_NO_VTABLE ChaChaTLS_Policy : public AdditiveCipherConcretePolicy +{ +public: + virtual ~ChaChaTLS_Policy() {} + ChaChaTLS_Policy() : m_counter(0) {} + +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return true;} + void SeekToIteration(lword iterationCount); + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; + + std::string AlgorithmName() const; + std::string AlgorithmProvider() const; + + FixedSizeAlignedSecBlock m_state; + unsigned int m_counter; + CRYPTOPP_CONSTANT(ROUNDS = ChaChaTLS_Info::ROUNDS); + CRYPTOPP_CONSTANT(KEY = 16); // Index into m_state + CRYPTOPP_CONSTANT(CTR = 24); // Index into m_state +}; + +/// \brief IETF ChaCha20 stream cipher +/// \details This is the IETF's variant of Bernstein's ChaCha from RFC 8439. +/// IETF ChaCha is called ChaChaTLS in the Crypto++ library. It is +/// _slightly_ different from the Bernstein implementation. ChaCha-TLS +/// can be used for cipher suites +/// TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +/// TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, and +/// TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. +/// \sa RFC 8439, ChaCha20 and +/// Poly1305 for IETF Protocols, How +/// to handle block counter wrap in IETF's ChaCha algorithm? and +/// Issue +/// 790, ChaChaTLS results when counter block wraps. +/// \since Crypto++ 8.1 +struct ChaChaTLS : public ChaChaTLS_Info, public SymmetricCipherDocumentation +{ + /// \brief ChaCha-TLS Encryption + typedef SymmetricCipherFinal >, ChaChaTLS_Info > Encryption; + /// \brief ChaCha-TLS Decryption + typedef Encryption Decryption; +}; + +////////////////////////////// IETF XChaCha20 draft ////////////////////////////// + +/// \brief IETF XChaCha20 stream cipher information +/// \since Crypto++ 8.1 +struct XChaCha20_Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 24> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + /// \details This is the IETF's XChaCha from draft-arciszewski-xchacha. + static const char* StaticAlgorithmName() { + return "XChaCha20"; + } +}; + +/// \brief IETF XChaCha20 stream cipher implementation +/// \since Crypto++ 8.1 +class CRYPTOPP_NO_VTABLE XChaCha20_Policy : public AdditiveCipherConcretePolicy +{ +public: + virtual ~XChaCha20_Policy() {} + XChaCha20_Policy() : m_counter(0), m_rounds(ROUNDS) {} + +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return false;} + void SeekToIteration(lword iterationCount); + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; + + std::string AlgorithmName() const; + std::string AlgorithmProvider() const; + + FixedSizeAlignedSecBlock m_state; + unsigned int m_counter, m_rounds; + CRYPTOPP_CONSTANT(ROUNDS = 20); // Default rounds + CRYPTOPP_CONSTANT(KEY = 16); // Index into m_state +}; + +/// \brief IETF XChaCha20 stream cipher +/// \details This is the IETF's XChaCha from draft-arciszewski-xchacha. +/// \sa XChaCha: +/// eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 (rev. 03), How +/// to handle block counter wrap in IETF's ChaCha algorithm? and +/// Issue +/// 790, ChaCha20 results when counter block wraps. +/// \since Crypto++ 8.1 +struct XChaCha20 : public XChaCha20_Info, public SymmetricCipherDocumentation +{ + /// \brief XChaCha Encryption + typedef SymmetricCipherFinal >, XChaCha20_Info > Encryption; + /// \brief XChaCha Decryption + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_CHACHA_H diff --git a/third_party/cryptoppwin/include/cryptopp/chachapoly.h b/third_party/cryptoppwin/include/cryptopp/chachapoly.h new file mode 100644 index 00000000..27d4d593 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/chachapoly.h @@ -0,0 +1,322 @@ +// chachapoly.h - written and placed in the public domain by Jeffrey Walton +// RFC 8439, Section 2.8, AEAD Construction, http://tools.ietf.org/html/rfc8439 + +/// \file chachapoly.h +/// \brief IETF ChaCha20/Poly1305 AEAD scheme +/// \details ChaCha20Poly1305 is an authenticated encryption scheme that combines +/// ChaCha20TLS and Poly1305TLS. The scheme is defined in RFC 8439, section 2.8, +/// AEAD_CHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20 +/// and Poly1305. +/// \sa RFC 8439, ChaCha20 and Poly1305 +/// for IETF Protocols. +/// \since Crypto++ 8.1 + +#ifndef CRYPTOPP_CHACHA_POLY1305_H +#define CRYPTOPP_CHACHA_POLY1305_H + +#include "cryptlib.h" +#include "authenc.h" +#include "chacha.h" +#include "poly1305.h" + +NAMESPACE_BEGIN(CryptoPP) + +////////////////////////////// IETF ChaChaTLS ////////////////////////////// + +/// \brief IETF ChaCha20Poly1305 cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 8.1 +class ChaCha20Poly1305_Base : public AuthenticatedSymmetricCipherBase +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() + {return "ChaCha20/Poly1305";} + + virtual ~ChaCha20Poly1305_Base() {} + + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return std::string("ChaCha20/Poly1305");} + std::string AlgorithmProvider() const + {return GetSymmetricCipher().AlgorithmProvider();} + size_t MinKeyLength() const + {return 32;} + size_t MaxKeyLength() const + {return 32;} + size_t DefaultKeyLength() const + {return 32;} + size_t GetValidKeyLength(size_t n) const + {CRYPTOPP_UNUSED(n); return 32;} + bool IsValidKeyLength(size_t n) const + {return n==32;} + unsigned int OptimalDataAlignment() const + {return GetSymmetricCipher().OptimalDataAlignment();} + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return 12;} + unsigned int MinIVLength() const + {return 12;} + unsigned int MaxIVLength() const + {return 12;} + unsigned int DigestSize() const + {return 16;} + lword MaxHeaderLength() const + {return LWORD_MAX;} // 2^64-1 bytes + lword MaxMessageLength() const + {return W64LIT(274877906880);} // 2^38-1 blocks + lword MaxFooterLength() const + {return 0;} + + /// \brief Encrypts and calculates a MAC in one call + /// \param ciphertext the encryption buffer + /// \param mac the mac buffer + /// \param macSize the size of the MAC buffer, in bytes + /// \param iv the iv buffer + /// \param ivLength the size of the IV buffer, in bytes + /// \param aad the AAD buffer + /// \param aadLength the size of the AAD buffer, in bytes + /// \param message the message buffer + /// \param messageLength the size of the messagetext buffer, in bytes + /// \details EncryptAndAuthenticate() encrypts and generates the MAC in one call. The function + /// truncates the MAC if macSize < TagSize(). + virtual void EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength); + + /// \brief Decrypts and verifies a MAC in one call + /// \param message the decryption buffer + /// \param mac the mac buffer + /// \param macSize the size of the MAC buffer, in bytes + /// \param iv the iv buffer + /// \param ivLength the size of the IV buffer, in bytes + /// \param aad the AAD buffer + /// \param aadLength the size of the AAD buffer, in bytes + /// \param ciphertext the cipher buffer + /// \param ciphertextLength the size of the ciphertext buffer, in bytes + /// \return true if the MAC is valid and the decoding succeeded, false otherwise + /// \details DecryptAndVerify() decrypts and verifies the MAC in one call. + /// message is a decryption buffer and should be at least as large as the ciphertext buffer. + /// \details The function returns true iff MAC is valid. DecryptAndVerify() assumes the MAC + /// is truncated if macLength < TagSize(). + virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength); + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const {return false;} + unsigned int AuthenticationBlockSize() const {return 1;} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastConfidentialBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + + // See comments in chachapoly.cpp + void RekeyCipherAndMac(const byte *userKey, size_t userKeyLength, const NameValuePairs ¶ms); + + virtual const MessageAuthenticationCode & GetMAC() const = 0; + virtual MessageAuthenticationCode & AccessMAC() = 0; + +private: + SecByteBlock m_userKey; +}; + +/// \brief IETF ChaCha20Poly1305 cipher final implementation +/// \tparam T_IsEncryption flag indicating cipher direction +/// \details ChaCha20Poly1305 is an authenticated encryption scheme that combines +/// ChaCha20TLS and Poly1305TLS. The scheme is defined in RFC 8439, section 2.8, +/// AEAD_CHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20 +/// and Poly1305. +/// \sa RFC 8439, ChaCha20 and Poly1305 +/// for IETF Protocols. +/// \since Crypto++ 8.1 +template +class ChaCha20Poly1305_Final : public ChaCha20Poly1305_Base +{ +public: + virtual ~ChaCha20Poly1305_Final() {} + +protected: + const SymmetricCipher & GetSymmetricCipher() + {return const_cast(this)->AccessSymmetricCipher();} + SymmetricCipher & AccessSymmetricCipher() + {return m_cipher;} + bool IsForwardTransformation() const + {return T_IsEncryption;} + + const MessageAuthenticationCode & GetMAC() const + {return const_cast(this)->AccessMAC();} + MessageAuthenticationCode & AccessMAC() + {return m_mac;} + +private: + ChaChaTLS::Encryption m_cipher; + Poly1305TLS m_mac; +}; + +/// \brief IETF ChaCha20/Poly1305 AEAD scheme +/// \details ChaCha20Poly1305 is an authenticated encryption scheme that combines +/// ChaCha20TLS and Poly1305TLS. The scheme is defined in RFC 8439, section 2.8, +/// AEAD_CHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20 +/// and Poly1305. +/// \sa RFC 8439, ChaCha20 and Poly1305 +/// for IETF Protocols. +/// \since Crypto++ 8.1 +struct ChaCha20Poly1305 : public AuthenticatedSymmetricCipherDocumentation +{ + /// \brief ChaCha20Poly1305 encryption + typedef ChaCha20Poly1305_Final Encryption; + /// \brief ChaCha20Poly1305 decryption + typedef ChaCha20Poly1305_Final Decryption; +}; + +////////////////////////////// IETF XChaCha20 draft ////////////////////////////// + +/// \brief IETF XChaCha20Poly1305 cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 8.1 +class XChaCha20Poly1305_Base : public AuthenticatedSymmetricCipherBase +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() + {return "XChaCha20/Poly1305";} + + virtual ~XChaCha20Poly1305_Base() {} + + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return std::string("XChaCha20/Poly1305");} + std::string AlgorithmProvider() const + {return GetSymmetricCipher().AlgorithmProvider();} + size_t MinKeyLength() const + {return 32;} + size_t MaxKeyLength() const + {return 32;} + size_t DefaultKeyLength() const + {return 32;} + size_t GetValidKeyLength(size_t n) const + {CRYPTOPP_UNUSED(n); return 32;} + bool IsValidKeyLength(size_t n) const + {return n==32;} + unsigned int OptimalDataAlignment() const + {return GetSymmetricCipher().OptimalDataAlignment();} + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return 24;} + unsigned int MinIVLength() const + {return 24;} + unsigned int MaxIVLength() const + {return 24;} + unsigned int DigestSize() const + {return 16;} + lword MaxHeaderLength() const + {return LWORD_MAX;} // 2^64-1 bytes + lword MaxMessageLength() const + {return W64LIT(274877906880);} // 2^38-1 blocks + lword MaxFooterLength() const + {return 0;} + + /// \brief Encrypts and calculates a MAC in one call + /// \param ciphertext the encryption buffer + /// \param mac the mac buffer + /// \param macSize the size of the MAC buffer, in bytes + /// \param iv the iv buffer + /// \param ivLength the size of the IV buffer, in bytes + /// \param aad the AAD buffer + /// \param aadLength the size of the AAD buffer, in bytes + /// \param message the message buffer + /// \param messageLength the size of the messagetext buffer, in bytes + /// \details EncryptAndAuthenticate() encrypts and generates the MAC in one call. The function + /// truncates the MAC if macSize < TagSize(). + virtual void EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength); + + /// \brief Decrypts and verifies a MAC in one call + /// \param message the decryption buffer + /// \param mac the mac buffer + /// \param macSize the size of the MAC buffer, in bytes + /// \param iv the iv buffer + /// \param ivLength the size of the IV buffer, in bytes + /// \param aad the AAD buffer + /// \param aadLength the size of the AAD buffer, in bytes + /// \param ciphertext the cipher buffer + /// \param ciphertextLength the size of the ciphertext buffer, in bytes + /// \return true if the MAC is valid and the decoding succeeded, false otherwise + /// \details DecryptAndVerify() decrypts and verifies the MAC in one call. + /// message is a decryption buffer and should be at least as large as the ciphertext buffer. + /// \details The function returns true iff MAC is valid. DecryptAndVerify() assumes the MAC + /// is truncated if macLength < TagSize(). + virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength); + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const {return false;} + unsigned int AuthenticationBlockSize() const {return 1;} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastConfidentialBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + + // See comments in chachapoly.cpp + void RekeyCipherAndMac(const byte *userKey, size_t userKeyLength, const NameValuePairs ¶ms); + + virtual const MessageAuthenticationCode & GetMAC() const = 0; + virtual MessageAuthenticationCode & AccessMAC() = 0; + +private: + SecByteBlock m_userKey; +}; + +/// \brief IETF XChaCha20Poly1305 cipher final implementation +/// \tparam T_IsEncryption flag indicating cipher direction +/// \details XChaCha20Poly1305 is an authenticated encryption scheme that combines +/// XChaCha20 and Poly1305-TLS. The scheme is defined in RFC 8439, section 2.8, +/// AEAD_CHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20 +/// and Poly1305. +/// \sa RFC 8439, ChaCha20 and Poly1305 +/// for IETF Protocols. +/// \since Crypto++ 8.1 +template +class XChaCha20Poly1305_Final : public XChaCha20Poly1305_Base +{ +public: + virtual ~XChaCha20Poly1305_Final() {} + +protected: + const SymmetricCipher & GetSymmetricCipher() + {return const_cast(this)->AccessSymmetricCipher();} + SymmetricCipher & AccessSymmetricCipher() + {return m_cipher;} + bool IsForwardTransformation() const + {return T_IsEncryption;} + + const MessageAuthenticationCode & GetMAC() const + {return const_cast(this)->AccessMAC();} + MessageAuthenticationCode & AccessMAC() + {return m_mac;} + +private: + XChaCha20::Encryption m_cipher; + Poly1305TLS m_mac; +}; + +/// \brief IETF XChaCha20/Poly1305 AEAD scheme +/// \details XChaCha20Poly1305 is an authenticated encryption scheme that combines +/// XChaCha20 and Poly1305-TLS. The scheme is defined in RFC 8439, section 2.8, +/// AEAD_XCHACHA20_POLY1305 construction, and uses the IETF versions of ChaCha20 +/// and Poly1305. +/// \sa RFC 8439, ChaCha20 and Poly1305 +/// for IETF Protocols. +/// \since Crypto++ 8.1 +struct XChaCha20Poly1305 : public AuthenticatedSymmetricCipherDocumentation +{ + /// \brief XChaCha20Poly1305 encryption + typedef XChaCha20Poly1305_Final Encryption; + /// \brief XChaCha20Poly1305 decryption + typedef XChaCha20Poly1305_Final Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_CHACHA_POLY1305_H diff --git a/third_party/cryptoppwin/include/cryptopp/cham.h b/third_party/cryptoppwin/include/cryptopp/cham.h new file mode 100644 index 00000000..2ce7b8e6 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/cham.h @@ -0,0 +1,179 @@ +// cham.h - written and placed in the public domain by Kim Sung Hee and Jeffrey Walton +// Based on "CHAM: A Family of Lightweight Block Ciphers for +// Resource-Constrained Devices" by Bonwook Koo, Dongyoung Roh, +// Hyeonjin Kim, Younghoon Jung, Dong-Geon Lee, and Daesung Kwon + +/// \file cham.h +/// \brief Classes for the CHAM block cipher +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_CHAM_H +#define CRYPTOPP_CHAM_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" + +#if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86) +# define CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS 1 +#endif + +// Yet another SunStudio/SunCC workaround. Failed self tests +// in SSE code paths on i386 for SunStudio 12.3 and below. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120) +# undef CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CHAM block cipher information +/// \since Crypto++ 8.0 +struct CHAM64_Info : public FixedBlockSize<8>, public FixedKeyLength<16> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize + return "CHAM-64"; + } +}; + +/// \brief CHAM block cipher information +/// \since Crypto++ 8.0 +struct CHAM128_Info : public FixedBlockSize<16>, public VariableKeyLength<16,16,32,16> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize + return "CHAM-128"; + } +}; + +/// \brief CHAM 64-bit block cipher +/// \details CHAM64 provides 64-bit block size. The valid key size is 128-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa CHAM128, CHAM, +/// +/// CHAM: A Family of Lightweight Block Ciphers for Resource-Constrained Devices +/// \since Crypto++ 8.0 +class CRYPTOPP_NO_VTABLE CHAM64 : public CHAM64_Info, public BlockCipherDocumentation +{ +public: + /// \brief CHAM block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + + SecBlock m_rk; + mutable FixedSizeSecBlock m_x; + unsigned int m_kw; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief CHAM64 encryption + typedef BlockCipherFinal Encryption; + /// \brief CHAM64 decryption + typedef BlockCipherFinal Decryption; +}; + +/// \brief CHAM64 encryption +typedef CHAM64::Encryption CHAM64Encryption; +/// \brief CHAM64 decryption +typedef CHAM64::Decryption CHAM64Decryption; + +/// \brief CHAM 128-bit block cipher +/// \details CHAM128 provides 128-bit block size. The valid key size is 128-bit and 256-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa CHAM64, CHAM, +/// +/// CHAM: A Family of Lightweight Block Ciphers for Resource-Constrained Devices +/// \since Crypto++ 8.0 +class CRYPTOPP_NO_VTABLE CHAM128 : public CHAM128_Info, public BlockCipherDocumentation +{ +public: + /// \brief CHAM block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + std::string AlgorithmProvider() const; + + SecBlock m_rk; + mutable FixedSizeSecBlock m_x; + unsigned int m_kw; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_CHAM128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief CHAM128 encryption + typedef BlockCipherFinal Encryption; + /// \brief CHAM128 decryption + typedef BlockCipherFinal Decryption; +}; + +/// \brief CHAM128 encryption +typedef CHAM128::Encryption CHAM128Encryption; +/// \brief CHAM128 decryption +typedef CHAM128::Decryption CHAM128Decryption; + +NAMESPACE_END + +#endif // CRYPTOPP_CHAM_H diff --git a/third_party/cryptoppwin/include/cryptopp/channels.h b/third_party/cryptoppwin/include/cryptopp/channels.h new file mode 100644 index 00000000..d7aecd2a --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/channels.h @@ -0,0 +1,142 @@ +// channels.h - originally written and placed in the public domain by Wei Dai + +/// \file channels.h +/// \brief Classes for multiple named channels + +#ifndef CRYPTOPP_CHANNELS_H +#define CRYPTOPP_CHANNELS_H + +#include "cryptlib.h" +#include "simple.h" +#include "smartptr.h" +#include "stdcpp.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4355) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if 0 +/// Route input on default channel to different and/or multiple channels based on message sequence number +class MessageSwitch : public Sink +{ +public: + void AddDefaultRoute(BufferedTransformation &destination, const std::string &channel); + void AddRoute(unsigned int begin, unsigned int end, BufferedTransformation &destination, const std::string &channel); + + void Put(byte inByte); + void Put(const byte *inString, unsigned int length); + + void Flush(bool completeFlush, int propagation=-1); + void MessageEnd(int propagation=-1); + void PutMessageEnd(const byte *inString, unsigned int length, int propagation=-1); + void MessageSeriesEnd(int propagation=-1); + +private: + typedef std::pair Route; + struct RangeRoute + { + RangeRoute(unsigned int begin, unsigned int end, const Route &route) + : begin(begin), end(end), route(route) {} + bool operator<(const RangeRoute &rhs) const {return begin < rhs.begin;} + unsigned int begin, end; + Route route; + }; + + typedef std::list RouteList; + typedef std::list DefaultRouteList; + + RouteList m_routes; + DefaultRouteList m_defaultRoutes; + unsigned int m_nCurrentMessage; +}; +#endif + +class ChannelSwitchTypedefs +{ +public: + typedef std::pair Route; + typedef std::multimap RouteMap; + + typedef std::pair > DefaultRoute; + typedef std::list DefaultRouteList; + + // SunCC workaround: can't use const_iterator here + typedef RouteMap::iterator MapIterator; + typedef DefaultRouteList::iterator ListIterator; +}; + +class ChannelSwitch; + +class ChannelRouteIterator : public ChannelSwitchTypedefs +{ +public: + ChannelRouteIterator(ChannelSwitch &cs) : m_cs(cs), m_useDefault(false) {} + + void Reset(const std::string &channel); + bool End() const; + void Next(); + BufferedTransformation & Destination(); + const std::string & Channel(); + + ChannelSwitch& m_cs; + std::string m_channel; + bool m_useDefault; + MapIterator m_itMapCurrent, m_itMapEnd; + ListIterator m_itListCurrent, m_itListEnd; + +protected: + // Hide this to see if we break something... + ChannelRouteIterator(); +}; + +/// Route input to different and/or multiple channels based on channel ID +class CRYPTOPP_DLL ChannelSwitch : public Multichannel, public ChannelSwitchTypedefs +{ +public: + ChannelSwitch() : m_it(*this), m_blocked(false) {} + ChannelSwitch(BufferedTransformation &destination) : m_it(*this), m_blocked(false) + { + AddDefaultRoute(destination); + } + ChannelSwitch(BufferedTransformation &destination, const std::string &outChannel) : m_it(*this), m_blocked(false) + { + AddDefaultRoute(destination, outChannel); + } + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking); + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking); + + bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true); + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true); + + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size); + + void AddDefaultRoute(BufferedTransformation &destination); + void RemoveDefaultRoute(BufferedTransformation &destination); + void AddDefaultRoute(BufferedTransformation &destination, const std::string &outChannel); + void RemoveDefaultRoute(BufferedTransformation &destination, const std::string &outChannel); + void AddRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel); + void RemoveRoute(const std::string &inChannel, BufferedTransformation &destination, const std::string &outChannel); + +private: + RouteMap m_routeMap; + DefaultRouteList m_defaultRoutes; + + ChannelRouteIterator m_it; + bool m_blocked; + + friend class ChannelRouteIterator; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/cmac.h b/third_party/cryptoppwin/include/cryptopp/cmac.h new file mode 100644 index 00000000..91d9f7f9 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/cmac.h @@ -0,0 +1,76 @@ +// cmac.h - originally written and placed in the public domain by Wei Dai + +/// \file cmac.h +/// \brief Classes for CMAC message authentication code +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_CMAC_H +#define CRYPTOPP_CMAC_H + +#include "seckey.h" +#include "secblock.h" + +/// \brief Enable CMAC and wide block ciphers +/// \details CMAC is only defined for AES. The library can support wide +/// block ciphers like Kaylna and Threefish since we know the polynomials. +#ifndef CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS +# define CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS 1 +#endif // CRYPTOPP_CMAC_WIDE_BLOCK_CIPHERS + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief CMAC base implementation +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CMAC_Base : public MessageAuthenticationCode +{ +public: + + virtual ~CMAC_Base() {} + CMAC_Base() : m_counter(0) {} + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + unsigned int DigestSize() const {return GetCipher().BlockSize();} + unsigned int OptimalBlockSize() const {return GetCipher().BlockSize();} + unsigned int OptimalDataAlignment() const {return GetCipher().OptimalDataAlignment();} + std::string AlgorithmProvider() const {return GetCipher().AlgorithmProvider();} + +protected: + friend class EAX_Base; + + const BlockCipher & GetCipher() const {return const_cast(this)->AccessCipher();} + virtual BlockCipher & AccessCipher() =0; + + void ProcessBuf(); + SecByteBlock m_reg; + unsigned int m_counter; +}; + +/// \brief CMAC message authentication code +/// \tparam T block cipher +/// \details Template parameter T should be a class derived from BlockCipherDocumentation, for example AES, with a block size of 8, 16, or 32. +/// \sa CMAC +/// \since Crypto++ 5.6.0 +template +class CMAC : public MessageAuthenticationCodeImpl >, public SameKeyLengthAs +{ +public: + /// \brief Construct a CMAC + CMAC() {} + /// \brief Construct a CMAC + /// \param key the MAC key + /// \param length the key size, in bytes + CMAC(const byte *key, size_t length=SameKeyLengthAs::DEFAULT_KEYLENGTH) + {this->SetKey(key, length);} + + static std::string StaticAlgorithmName() {return std::string("CMAC(") + T::StaticAlgorithmName() + ")";} + +private: + BlockCipher & AccessCipher() {return m_cipher;} + typename T::Encryption m_cipher; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/config.h b/third_party/cryptoppwin/include/cryptopp/config.h new file mode 100644 index 00000000..e96b1127 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/config.h @@ -0,0 +1,33 @@ +// config.h - originally written and placed in the public domain by Wei Dai + +/// \file config.h +/// \brief Library configuration file +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +/// \file config.h +/// \brief Library configuration file + +#ifndef CRYPTOPP_CONFIG_H +#define CRYPTOPP_CONFIG_H + +#include "config_align.h" +#include "config_asm.h" +#include "config_cpu.h" +#include "config_cxx.h" +#include "config_dll.h" +#include "config_int.h" +#include "config_misc.h" +#include "config_ns.h" +#include "config_os.h" +#include "config_ver.h" + +#endif // CRYPTOPP_CONFIG_H diff --git a/third_party/cryptoppwin/include/cryptopp/config_align.h b/third_party/cryptoppwin/include/cryptopp/config_align.h new file mode 100644 index 00000000..d6d85e75 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/config_align.h @@ -0,0 +1,72 @@ +// config_align.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_align.h +/// \brief Library configuration file +/// \details config_align.h provides defines for aligned memory +/// allocations. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_align.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_ALIGN_H +#define CRYPTOPP_CONFIG_ALIGN_H + +#include "config_asm.h" // CRYPTOPP_DISABLE_ASM +#include "config_cpu.h" // X86, X32, X64, ARM32, ARM64, etc +#include "config_cxx.h" // CRYPTOPP_CXX11_ALIGNAS +#include "config_ver.h" // Compiler versions + +// Nearly all Intel's and AMD's have SSE. Enable it independent of SSE ASM and intrinsics. +// ARM NEON and ARMv8 ASIMD only need natural alignment of an element in the vector. +// Altivec through POWER7 need vector alignment. POWER8 and POWER9 relax the requirement. +#if defined(CRYPTOPP_DISABLE_ASM) + #define CRYPTOPP_BOOL_ALIGN16 0 +#elif (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || \ + CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) + #define CRYPTOPP_BOOL_ALIGN16 1 +#else + #define CRYPTOPP_BOOL_ALIGN16 0 +#endif + +// How to allocate 16-byte aligned memory (for SSE2) +// posix_memalign see https://forum.kde.org/viewtopic.php?p=66274 +#if defined(CRYPTOPP_MSC_VERSION) + #define CRYPTOPP_MM_MALLOC_AVAILABLE +#elif defined(__linux__) || defined(__sun__) || defined(__CYGWIN__) + #define CRYPTOPP_MEMALIGN_AVAILABLE +#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + #define CRYPTOPP_MALLOC_ALIGNMENT_IS_16 +#elif (defined(_GNU_SOURCE) || ((_XOPEN_SOURCE + 0) >= 600)) && (_POSIX_ADVISORY_INFO > 0) + #define CRYPTOPP_POSIX_MEMALIGN_AVAILABLE +#else + #define CRYPTOPP_NO_ALIGNED_ALLOC +#endif + +// Sun Studio Express 3 (December 2006) provides GCC-style attributes. +// IBM XL C/C++ alignment modifier per Optimization Guide, pp. 19-20. +// __IBM_ATTRIBUTES per XLC 12.1 AIX Compiler Manual, p. 473. +// CRYPTOPP_ALIGN_DATA may not be reliable on AIX. +#if defined(CRYPTOPP_CXX11_ALIGNAS) + #define CRYPTOPP_ALIGN_DATA(x) alignas(x) +#elif defined(CRYPTOPP_MSC_VERSION) + #define CRYPTOPP_ALIGN_DATA(x) __declspec(align(x)) +#elif defined(__GNUC__) || defined(__clang__) || (__SUNPRO_CC >= 0x5100) + #define CRYPTOPP_ALIGN_DATA(x) __attribute__((aligned(x))) +#elif defined(__xlc__) || defined(__xlC__) + #define CRYPTOPP_ALIGN_DATA(x) __attribute__((aligned(x))) +#else + #define CRYPTOPP_ALIGN_DATA(x) +#endif + +#endif // CRYPTOPP_CONFIG_ALIGN_H diff --git a/third_party/cryptoppwin/include/cryptopp/config_asm.h b/third_party/cryptoppwin/include/cryptopp/config_asm.h new file mode 100644 index 00000000..edfbdefb --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/config_asm.h @@ -0,0 +1,492 @@ +// config_asm.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_asm.h +/// \brief Library configuration file +/// \details config_asm.h provides defines for instruction set +/// architectures +/// and inline assembly. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_asm.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_ASM_H +#define CRYPTOPP_CONFIG_ASM_H + +#include "config_os.h" +#include "config_cpu.h" +#include "config_ver.h" + +// Define this to disable ASM, intrinsics and built-ins. The library code will +// not explicitly include SSE2 (and above), NEON, Aarch32, Aarch64, or Altivec +// (and above). Note the compiler may use higher ISAs depending on compiler +// options, but the library will not explicitly use the ISAs. When disabling ASM, +// it is best to do it from config_asm.h to ensure the library and all programs +// share the setting. +// #define CRYPTOPP_DISABLE_ASM 1 + +// https://github.com/weidai11/cryptopp/issues/719 +#if defined(__native_client__) +# undef CRYPTOPP_DISABLE_ASM +# define CRYPTOPP_DISABLE_ASM 1 +#endif + +// Some Clang and SunCC cannot handle mixed asm with positional arguments, +// where the body is Intel style with no prefix and the templates are +// AT&T style. Define this if the Makefile misdetects the configuration. +// Also see https://bugs.llvm.org/show_bug.cgi?id=39895 . +// #define CRYPTOPP_DISABLE_MIXED_ASM 1 + +#if defined(__clang__) || (defined(__APPLE__) && defined(__GNUC__)) || defined(__SUNPRO_CC) +# undef CRYPTOPP_DISABLE_MIXED_ASM +# define CRYPTOPP_DISABLE_MIXED_ASM 1 +#endif + +// Define this if you need to disable Android advanced ISAs. +// The problem is, Android-mk does not allow us to specify an +// ISA option, like -maes or -march=armv8-a+crypto for AES. +// Lack of an option results in a compile failure. To avoid +// the compile failure, set this define. Also see +// https://github.com/weidai11/cryptopp/issues/1015 +// CRYPTOPP_DISABLE_ANDROID_ADVANCED_ISA 1 + +// ***************** IA32 CPU features ******************** + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + +// Apple Clang prior to 5.0 cannot handle SSE2 +#if defined(CRYPTOPP_APPLE_CLANG_VERSION) && (CRYPTOPP_APPLE_CLANG_VERSION < 50000) +# define CRYPTOPP_DISABLE_ASM 1 +#endif + +// Sun Studio 12.1 provides GCC inline assembly +// http://blogs.oracle.com/x86be/entry/gcc_style_asm_inlining_support +#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5100) +# define CRYPTOPP_DISABLE_ASM 1 +#endif + +// Guard everything in CRYPTOPP_DISABLE_ASM +#if !defined(CRYPTOPP_DISABLE_ASM) + +#if (defined(_MSC_VER) && defined(_M_IX86)) || ((defined(__GNUC__) && (defined(__i386__)) || defined(__x86_64__))) + // C++Builder 2010 does not allow "call label" where label is defined within inline assembly + #define CRYPTOPP_X86_ASM_AVAILABLE 1 + + #if !defined(CRYPTOPP_DISABLE_SSE2) && (defined(_MSC_VER) || CRYPTOPP_GCC_VERSION >= 30300 || defined(__SSE2__)) + #define CRYPTOPP_SSE2_ASM_AVAILABLE 1 + #endif + + #if !defined(CRYPTOPP_DISABLE_SSSE3) && (_MSC_VER >= 1500 || CRYPTOPP_GCC_VERSION >= 40300 || defined(__SSSE3__)) + #define CRYPTOPP_SSSE3_ASM_AVAILABLE 1 + #endif +#endif + +#if defined(_MSC_VER) && defined(_M_X64) + #define CRYPTOPP_X64_MASM_AVAILABLE 1 +#endif + +#if defined(__GNUC__) && defined(__x86_64__) + #define CRYPTOPP_X64_ASM_AVAILABLE 1 +#endif + +// 32-bit SunCC does not enable SSE2 by default. +#if !defined(CRYPTOPP_DISABLE_SSE2) && (defined(CRYPTOPP_MSC_VERSION) || CRYPTOPP_GCC_VERSION >= 30300 || defined(__SSE2__) || (__SUNPRO_CC >= 0x5100)) + #define CRYPTOPP_SSE2_INTRIN_AVAILABLE 1 +#endif + +#if !defined(CRYPTOPP_DISABLE_SSSE3) +# if defined(__SSSE3__) || (CRYPTOPP_MSC_VERSION >= 1500) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || (__SUNPRO_CC >= 0x5110) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) + #define CRYPTOPP_SSSE3_AVAILABLE 1 +# endif +#endif + +// Intrinsics available in GCC 4.3 (http://gcc.gnu.org/gcc-4.3/changes.html) and +// MSVC 2008 (http://msdn.microsoft.com/en-us/library/bb892950%28v=vs.90%29.aspx) +// SunCC could generate SSE4 at 12.1, but the intrinsics are missing until 12.4. +#if !defined(CRYPTOPP_DISABLE_SSE4) && defined(CRYPTOPP_SSSE3_AVAILABLE) && \ + (defined(__SSE4_1__) || (CRYPTOPP_MSC_VERSION >= 1500) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || (__SUNPRO_CC >= 0x5110) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000)) + #define CRYPTOPP_SSE41_AVAILABLE 1 +#endif + +#if !defined(CRYPTOPP_DISABLE_SSE4) && defined(CRYPTOPP_SSSE3_AVAILABLE) && \ + (defined(__SSE4_2__) || (CRYPTOPP_MSC_VERSION >= 1500) || (__SUNPRO_CC >= 0x5110) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000)) + #define CRYPTOPP_SSE42_AVAILABLE 1 +#endif + +// Couple to CRYPTOPP_DISABLE_AESNI, but use CRYPTOPP_CLMUL_AVAILABLE so we can selectively +// disable for misbehaving platforms and compilers, like Solaris or some Clang. +#if defined(CRYPTOPP_DISABLE_AESNI) + #define CRYPTOPP_DISABLE_CLMUL 1 +#endif + +// Requires Sun Studio 12.3 (SunCC 0x5120) in theory. +#if !defined(CRYPTOPP_DISABLE_CLMUL) && defined(CRYPTOPP_SSE42_AVAILABLE) && \ + (defined(__PCLMUL__) || (_MSC_FULL_VER >= 150030729) || (__SUNPRO_CC >= 0x5120) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1110) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30200) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300)) + #define CRYPTOPP_CLMUL_AVAILABLE 1 +#endif + +// Requires Sun Studio 12.3 (SunCC 0x5120) +#if !defined(CRYPTOPP_DISABLE_AESNI) && defined(CRYPTOPP_SSE42_AVAILABLE) && \ + (defined(__AES__) || (_MSC_FULL_VER >= 150030729) || (__SUNPRO_CC >= 0x5120) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1110) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30200) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300)) + #define CRYPTOPP_AESNI_AVAILABLE 1 +#endif + +// Requires Binutils 2.24 +#if !defined(CRYPTOPP_DISABLE_AVX) && defined(CRYPTOPP_SSE42_AVAILABLE) && \ + (defined(__AVX2__) || (CRYPTOPP_MSC_VERSION >= 1800) || (__SUNPRO_CC >= 0x5130) || \ + (CRYPTOPP_GCC_VERSION >= 40700) || (__INTEL_COMPILER >= 1400) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40600)) +#define CRYPTOPP_AVX_AVAILABLE 1 +#endif + +// Requires Binutils 2.24 +#if !defined(CRYPTOPP_DISABLE_AVX2) && defined(CRYPTOPP_AVX_AVAILABLE) && \ + (defined(__AVX2__) || (CRYPTOPP_MSC_VERSION >= 1800) || (__SUNPRO_CC >= 0x5130) || \ + (CRYPTOPP_GCC_VERSION >= 40900) || (__INTEL_COMPILER >= 1400) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30100) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40600)) +#define CRYPTOPP_AVX2_AVAILABLE 1 +#endif + +// Guessing at SHA for SunCC. Its not in Sun Studio 12.6. Also see +// http://stackoverflow.com/questions/45872180/which-xarch-for-sha-extensions-on-solaris +// Guessing for Intel ICPC. A slide deck says SHA support is in version 16.0-beta +// https://www.alcf.anl.gov/files/ken_intel_compiler_optimization.pdf +#if !defined(CRYPTOPP_DISABLE_SHANI) && defined(CRYPTOPP_SSE42_AVAILABLE) && \ + (defined(__SHA__) || (CRYPTOPP_MSC_VERSION >= 1900) || (__SUNPRO_CC >= 0x5160) || \ + (CRYPTOPP_GCC_VERSION >= 40900) || (__INTEL_COMPILER >= 1600) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30400) || (CRYPTOPP_APPLE_CLANG_VERSION >= 50100)) + #define CRYPTOPP_SHANI_AVAILABLE 1 +#endif + +// RDRAND uses byte codes. All we need is x86 ASM for it. +// However tie it to AES-NI since SecureKey was available with it. +#if !defined(CRYPTOPP_DISABLE_RDRAND) && defined(CRYPTOPP_AESNI_AVAILABLE) + #define CRYPTOPP_RDRAND_AVAILABLE 1 +#endif + +// RDSEED uses byte codes. All we need is x86 ASM for it. +// However tie it to AES-NI since SecureKey was available with it. +#if !defined(CRYPTOPP_DISABLE_RDSEED) && defined(CRYPTOPP_AESNI_AVAILABLE) + #define CRYPTOPP_RDSEED_AVAILABLE 1 +#endif + +// PadlockRNG uses byte codes. All we need is x86 ASM for it. +#if !defined(CRYPTOPP_DISABLE_PADLOCK) && \ + !(defined(__ANDROID__) || defined(ANDROID) || defined(__APPLE__)) && \ + defined(CRYPTOPP_X86_ASM_AVAILABLE) + #define CRYPTOPP_PADLOCK_AVAILABLE 1 + #define CRYPTOPP_PADLOCK_RNG_AVAILABLE 1 + #define CRYPTOPP_PADLOCK_ACE_AVAILABLE 1 + #define CRYPTOPP_PADLOCK_ACE2_AVAILABLE 1 + #define CRYPTOPP_PADLOCK_PHE_AVAILABLE 1 + #define CRYPTOPP_PADLOCK_PMM_AVAILABLE 1 +#endif + +// Fixup for SunCC 12.1-12.4. Bad code generation in AES_Encrypt and friends. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5130) +# undef CRYPTOPP_AESNI_AVAILABLE +#endif + +// Fixup for SunCC 12.1-12.6. Compiler crash on GCM_Reduce_CLMUL. +// http://github.com/weidai11/cryptopp/issues/226 +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5150) +# undef CRYPTOPP_CLMUL_AVAILABLE +#endif + +// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670 +#define M128_CAST(x) ((__m128i *)(void *)(x)) +#define CONST_M128_CAST(x) ((const __m128i *)(const void *)(x)) +#define M256_CAST(x) ((__m256i *)(void *)(x)) +#define CONST_M256_CAST(x) ((const __m256i *)(const void *)(x)) + +#endif // CRYPTOPP_DISABLE_ASM + +#endif // X86, X32, X64 + +// ***************** ARM CPU features ******************** + +#if (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8) + +// We don't have an ARM big endian test rig. Disable +// ARM-BE ASM and instrinsics until we can test it. +#if (CRYPTOPP_BIG_ENDIAN) +# define CRYPTOPP_DISABLE_ASM 1 +#endif + +// Guard everything in CRYPTOPP_DISABLE_ASM +#if !defined(CRYPTOPP_DISABLE_ASM) + +// Requires ACLE 1.0. -mfpu=neon or above must be present +// Requires GCC 4.3, Clang 2.8 or Visual Studio 2012 +// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. +#if !defined(CRYPTOPP_ARM_NEON_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_NEON) +# if defined(__arm__) || defined(__ARM_NEON) || defined(__ARM_FEATURE_NEON) || defined(_M_ARM) +# if (CRYPTOPP_GCC_VERSION >= 40300) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20800) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 30200) || (CRYPTOPP_MSC_VERSION >= 1700) +# define CRYPTOPP_ARM_NEON_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and ASIMD. -march=armv8-a or above must be present +// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 +// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. +#if !defined(CRYPTOPP_ARM_ASIMD_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_ASIMD) +# if defined(__aarch32__) || defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) +# if defined(__ARM_NEON) || defined(__ARM_ASIMD) || defined(__ARM_FEATURE_NEON) || defined(__ARM_FEATURE_ASIMD) || \ + (CRYPTOPP_GCC_VERSION >= 40800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) || (CRYPTOPP_MSC_VERSION >= 1916) +# define CRYPTOPP_ARM_NEON_AVAILABLE 1 +# define CRYPTOPP_ARM_ASIMD_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and ASIMD. -march=armv8-a+crc or above must be present +// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 +#if !defined(CRYPTOPP_ARM_CRC32_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_CRC32) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_FEATURE_CRC32) || (CRYPTOPP_GCC_VERSION >= 40800) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300) || \ + (CRYPTOPP_MSC_VERSION >= 1916) +# define CRYPTOPP_ARM_CRC32_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and AES. -march=armv8-a+crypto or above must be present +// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 +#if !defined(CRYPTOPP_ARM_AES_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_AES) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_FEATURE_CRYPTO) || (CRYPTOPP_GCC_VERSION >= 40800) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300) || \ + (CRYPTOPP_MSC_VERSION >= 1916) +# define CRYPTOPP_ARM_AES_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and PMULL. -march=armv8-a+crypto or above must be present +// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 +#if !defined(CRYPTOPP_ARM_PMULL_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_PMULL) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_FEATURE_CRYPTO) || (CRYPTOPP_GCC_VERSION >= 40800) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300) || \ + (CRYPTOPP_MSC_VERSION >= 1916) +# define CRYPTOPP_ARM_PMULL_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and SHA-1, SHA-256. -march=armv8-a+crypto or above must be present +// Requires GCC 4.8, Clang 3.3 or Visual Studio 2017 +#if !defined(CRYPTOPP_ARM_SHA_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_SHA) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_FEATURE_CRYPTO) || (CRYPTOPP_GCC_VERSION >= 40800) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300) || \ + (CRYPTOPP_MSC_VERSION >= 1916) +# define CRYPTOPP_ARM_SHA1_AVAILABLE 1 +# define CRYPTOPP_ARM_SHA2_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// Buggy Microsoft compiler, https://github.com/weidai11/cryptopp/issues/1096 +#if defined(CRYPTOPP_MSC_VERSION) +# undef CRYPTOPP_ARM_SHA1_AVAILABLE +# undef CRYPTOPP_ARM_SHA2_AVAILABLE +#endif + +// ARMv8 and SHA-512, SHA-3. -march=armv8.2-a+crypto or above must be present +// Requires GCC 8.0, Clang 11.0, Apple Clang 12.0 or Visual Studio 20?? +#if !defined(CRYPTOPP_ARM_SHA3_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_SHA) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_FEATURE_SHA3) || (CRYPTOPP_GCC_VERSION >= 80000) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 120000) || (CRYPTOPP_LLVM_CLANG_VERSION >= 110000) +# define CRYPTOPP_ARM_SHA512_AVAILABLE 1 +# define CRYPTOPP_ARM_SHA3_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// ARMv8 and SM3, SM4. -march=armv8.2-a+crypto or above must be present +// Requires GCC 8.0, Clang ??? or Visual Studio 20?? +// Do not use APPLE_CLANG_VERSION; use __ARM_FEATURE_XXX instead. +#if !defined(CRYPTOPP_ARM_SM3_AVAILABLE) && !defined(CRYPTOPP_DISABLE_ARM_SM3) +# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) +# if defined(__ARM_FEATURE_SM3) || (CRYPTOPP_GCC_VERSION >= 80000) +# define CRYPTOPP_ARM_SM3_AVAILABLE 1 +# define CRYPTOPP_ARM_SM4_AVAILABLE 1 +# endif // Compilers +# endif // Platforms +#endif + +// Limit the include. +#if !defined(CRYPTOPP_ARM_NEON_HEADER) +# if defined(CRYPTOPP_ARM_NEON_AVAILABLE) || defined (CRYPTOPP_ARM_ASIMD_AVAILABLE) +# if !defined(_M_ARM64) +# define CRYPTOPP_ARM_NEON_HEADER 1 +# endif +# endif +#endif + +// Limit the include. +#if !defined(CRYPTOPP_ARM_ACLE_HEADER) +# if defined(__aarch32__) || defined(__aarch64__) || (__ARM_ARCH >= 8) || defined(__ARM_ACLE) +# define CRYPTOPP_ARM_ACLE_HEADER 1 +# endif +#endif + +// Apple M1 hack. Xcode cross-compiles for iOS lack +// arm_acle.h. Apple M1 needs arm_acle.h. The problem +// in practice is, we can't get CRYPTOPP_ARM_ACLE_HEADER +// quite right based on ARM preprocessor macros. +#if defined(__APPLE__) && !defined(__ARM_FEATURE_CRC32) +# undef CRYPTOPP_ARM_ACLE_HEADER +#endif + +// Cryptogams offers an ARM asm implementations for AES and SHA. Crypto++ does +// not provide an asm implementation. The Cryptogams AES implementation is +// about 50% faster than C/C++, and SHA implementation is about 30% faster +// than C/C++. Define this to use the Cryptogams AES and SHA implementations +// on GNU Linux systems. When defined, Crypto++ will use aes_armv4.S, +// sha1_armv4.S and sha256_armv4.S. https://www.cryptopp.com/wiki/Cryptogams. +#if !defined(CRYPTOPP_DISABLE_ARM_NEON) +# if defined(__arm__) && defined(__linux__) +# if defined(__GNUC__) || defined(__clang__) +# define CRYPTOGAMS_ARM_AES 1 +# define CRYPTOGAMS_ARM_SHA1 1 +# define CRYPTOGAMS_ARM_SHA256 1 +# define CRYPTOGAMS_ARM_SHA512 1 +# endif +# endif +#endif + +// We are still having trouble with integrating Cryptogams AES. Ugh... +// https://github.com/weidai11/cryptopp/issues/1236 +#undef CRYPTOGAMS_ARM_AES + +// Clang intrinsic casts, http://bugs.llvm.org/show_bug.cgi?id=20670 +#define UINT64_CAST(x) ((uint64_t *)(void *)(x)) +#define CONST_UINT64_CAST(x) ((const uint64_t *)(const void *)(x)) + +#endif // CRYPTOPP_DISABLE_ASM + +#endif // ARM32, ARM64 + +// ***************** AltiVec and Power8 ******************** + +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) + +// Guard everything in CRYPTOPP_DISABLE_ASM +#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(CRYPTOPP_DISABLE_ALTIVEC) + +// An old Apple G5 with GCC 4.01 has AltiVec, but its only Power4 or so. +#if !defined(CRYPTOPP_ALTIVEC_AVAILABLE) +# if defined(_ARCH_PWR4) || defined(__ALTIVEC__) || \ + (CRYPTOPP_XLC_VERSION >= 100000) || (CRYPTOPP_GCC_VERSION >= 40001) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) +# define CRYPTOPP_ALTIVEC_AVAILABLE 1 +# endif +#endif + +#if defined(CRYPTOPP_ALTIVEC_AVAILABLE) + +// We need Power7 for unaligned loads and stores +#if !defined(CRYPTOPP_POWER7_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER7) +# if defined(_ARCH_PWR7) || (CRYPTOPP_XLC_VERSION >= 100000) || \ + (CRYPTOPP_GCC_VERSION >= 40100) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30100) +# define CRYPTOPP_POWER7_AVAILABLE 1 +# endif +#endif + +#if defined(CRYPTOPP_POWER7_AVAILABLE) + +// We need Power8 for in-core crypto and 64-bit vector types +#if !defined(CRYPTOPP_POWER8_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER8) +# if defined(_ARCH_PWR8) || (CRYPTOPP_XLC_VERSION >= 130000) || \ + (CRYPTOPP_GCC_VERSION >= 40800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 70000) +# define CRYPTOPP_POWER8_AVAILABLE 1 +# endif +#endif + +#if !defined(CRYPTOPP_POWER8_AES_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER8_AES) && defined(CRYPTOPP_POWER8_AVAILABLE) +# if defined(__CRYPTO__) || defined(_ARCH_PWR8) || (CRYPTOPP_XLC_VERSION >= 130000) || \ + (CRYPTOPP_GCC_VERSION >= 40800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 70000) +//# define CRYPTOPP_POWER8_CRC_AVAILABLE 1 +# define CRYPTOPP_POWER8_AES_AVAILABLE 1 +# define CRYPTOPP_POWER8_VMULL_AVAILABLE 1 +# define CRYPTOPP_POWER8_SHA_AVAILABLE 1 +# endif +#endif + +#if defined(CRYPTOPP_POWER8_AVAILABLE) + +// Power9 for random numbers +#if !defined(CRYPTOPP_POWER9_AVAILABLE) && !defined(CRYPTOPP_DISABLE_POWER9) +# if defined(_ARCH_PWR9) || (CRYPTOPP_XLC_VERSION >= 130200) || \ + (CRYPTOPP_GCC_VERSION >= 70000) || (CRYPTOPP_LLVM_CLANG_VERSION >= 80000) +# define CRYPTOPP_POWER9_AVAILABLE 1 +# endif +#endif + +#endif // CRYPTOPP_POWER8_AVAILABLE +#endif // CRYPTOPP_POWER7_AVAILABLE +#endif // CRYPTOPP_ALTIVEC_AVAILABLE +#endif // CRYPTOPP_DISABLE_ASM +#endif // PPC32, PPC64 + +// https://github.com/weidai11/cryptopp/issues/1015 +#if defined(CRYPTOPP_DISABLE_ANDROID_ADVANCED_ISA) +# if defined(__ANDROID__) || defined(ANDROID) +# if (CRYPTOPP_BOOL_X86) +# undef CRYPTOPP_SSE41_AVAILABLE +# undef CRYPTOPP_SSE42_AVAILABLE +# undef CRYPTOPP_CLMUL_AVAILABLE +# undef CRYPTOPP_AESNI_AVAILABLE +# undef CRYPTOPP_SHANI_AVAILABLE +# undef CRYPTOPP_RDRAND_AVAILABLE +# undef CRYPTOPP_RDSEED_AVAILABLE +# undef CRYPTOPP_AVX_AVAILABLE +# undef CRYPTOPP_AVX2_AVAILABLE +# endif +# if (CRYPTOPP_BOOL_X64) +# undef CRYPTOPP_CLMUL_AVAILABLE +# undef CRYPTOPP_AESNI_AVAILABLE +# undef CRYPTOPP_SHANI_AVAILABLE +# undef CRYPTOPP_RDRAND_AVAILABLE +# undef CRYPTOPP_RDSEED_AVAILABLE +# undef CRYPTOPP_AVX_AVAILABLE +# undef CRYPTOPP_AVX2_AVAILABLE +# endif +# if (CRYPTOPP_BOOL_ARMV8) +# undef CRYPTOPP_ARM_CRC32_AVAILABLE +# undef CRYPTOPP_ARM_PMULL_AVAILABLE +# undef CRYPTOPP_ARM_AES_AVAILABLE +# undef CRYPTOPP_ARM_SHA1_AVAILABLE +# undef CRYPTOPP_ARM_SHA2_AVAILABLE +# endif +# endif // ANDROID +#endif // CRYPTOPP_DISABLE_ANDROID_ADVANCED_ISA + +#endif // CRYPTOPP_CONFIG_ASM_H diff --git a/third_party/cryptoppwin/include/cryptopp/config_cpu.h b/third_party/cryptoppwin/include/cryptopp/config_cpu.h new file mode 100644 index 00000000..15f694e7 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/config_cpu.h @@ -0,0 +1,212 @@ +// config_cpu.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_cpu.h +/// \brief Library configuration file +/// \details config_cpu.h provides defines for the cpu and machine +/// architecture. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_cpu.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki, +/// Sourceforge +/// Pre-defined Compiler Macros +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_CPU_H +#define CRYPTOPP_CONFIG_CPU_H + +#include "config_ver.h" + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief 32-bit x32 platform + /// \details CRYPTOPP_BOOL_X32 is defined to 1 when building the library + /// for a 32-bit x32 platform. Otherwise, the macro is not defined. + /// \details x32 is sometimes referred to as x86_32. x32 is the ILP32 data + /// model on a 64-bit cpu. Integers, longs and pointers are 32-bit but the + /// program runs on a 64-bit cpu. + /// \details The significance of x32 is, inline assembly must operate on + /// 64-bit registers, not 32-bit registers. That means, for example, + /// function prologues and epilogues must push and pop RSP, not ESP. + /// \note: Clang defines __ILP32__ on any 32-bit platform. Therefore, + /// CRYPTOPP_BOOL_X32 depends upon both __ILP32__ and __x86_64__. + /// \sa Debian X32 Port, + /// Gentoo + /// Multilib Concepts + #define CRYPTOPP_BOOL_X32 ... + /// \brief 32-bit x86 platform + /// \details CRYPTOPP_BOOL_X64 is defined to 1 when building the library + /// for a 64-bit x64 platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_X64 ... + /// \brief 32-bit x86 platform + /// \details CRYPTOPP_BOOL_X86 is defined to 1 when building the library + /// for a 32-bit x86 platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_X86 ... +#elif (defined(__ILP32__) || defined(_ILP32)) && defined(__x86_64__) + #define CRYPTOPP_BOOL_X32 1 +#elif (defined(_M_X64) || defined(__x86_64__)) + #define CRYPTOPP_BOOL_X64 1 +#elif (defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(_X86_) || defined(__I86__) || defined(__INTEL__)) + #define CRYPTOPP_BOOL_X86 1 +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief ARMv8 platform + /// \details CRYPTOPP_BOOL_ARMV8 is defined to 1 when building the library + /// for an ARMv8 platform. Otherwise, the macro is not defined. + /// \details ARMv8 includes both Aarch32 and Aarch64. Aarch32 is a 32-bit + /// execution environment on Aarch64. + #define CRYPTOPP_BOOL_ARMV8 ... + /// \brief 64-bit ARM platform + /// \details CRYPTOPP_BOOL_ARM64 is defined to 1 when building the library + /// for a 64-bit x64 platform. Otherwise, the macro is not defined. + /// \details Currently the macro indicates an ARM 64-bit architecture. + #define CRYPTOPP_BOOL_ARM64 ... + /// \brief 32-bit ARM platform + /// \details CRYPTOPP_BOOL_ARM32 is defined to 1 when building the library + /// for a 32-bit ARM platform. Otherwise, the macro is not defined. + /// \details Currently the macro indicates an ARM A-32 architecture. + #define CRYPTOPP_BOOL_ARM32 ... +#elif defined(__arm64__) || defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) + // Microsoft added ARM64 define December 2017. + #define CRYPTOPP_BOOL_ARMV8 1 +#endif +#if defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) + #define CRYPTOPP_BOOL_ARM64 1 +#elif defined(__arm__) || defined(_M_ARM) + #define CRYPTOPP_BOOL_ARM32 1 +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief 64-bit PowerPC platform + /// \details CRYPTOPP_BOOL_PPC64 is defined to 1 when building the library + /// for a 64-bit PowerPC platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_PPC64 ... + /// \brief 32-bit PowerPC platform + /// \details CRYPTOPP_BOOL_PPC32 is defined to 1 when building the library + /// for a 32-bit PowerPC platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_PPC32 ... +#elif defined(__ppc64__) || defined(__powerpc64__) || defined(__PPC64__) || defined(_ARCH_PPC64) + #define CRYPTOPP_BOOL_PPC64 1 +#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(_ARCH_PPC) + #define CRYPTOPP_BOOL_PPC32 1 +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief 64-bit MIPS platform + /// \details CRYPTOPP_BOOL_MIPS64 is defined to 1 when building the library + /// for a 64-bit MIPS platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_MIPS64 ... + /// \brief 64-bit MIPS platform + /// \details CRYPTOPP_BOOL_MIPS32 is defined to 1 when building the library + /// for a 32-bit MIPS platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_MIPS32 ... +#elif defined(__mips64__) + #define CRYPTOPP_BOOL_MIPS64 1 +#elif defined(__mips__) + #define CRYPTOPP_BOOL_MIPS32 1 +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief 64-bit SPARC platform + /// \details CRYPTOPP_BOOL_SPARC64 is defined to 1 when building the library + /// for a 64-bit SPARC platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_SPARC64 ... + /// \brief 32-bit SPARC platform + /// \details CRYPTOPP_BOOL_SPARC32 is defined to 1 when building the library + /// for a 32-bit SPARC platform. Otherwise, the macro is not defined. + #define CRYPTOPP_BOOL_SPARC32 ... +#elif defined(__sparc64__) || defined(__sparc64) || defined(__sparcv9) || defined(__sparc_v9__) + #define CRYPTOPP_BOOL_SPARC64 1 +#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) || defined(__sparc_v8__) + #define CRYPTOPP_BOOL_SPARC32 1 +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief L1 data cache line size + /// \details CRYPTOPP_L1_CACHE_LINE_SIZE should be a lower bound on the L1 + /// data cache line size. It is used for defense against some timing attacks. + /// \details CRYPTOPP_L1_CACHE_LINE_SIZE default value on 32-bit platforms + /// is 32, and the default value on 64-bit platforms is 64. On PowerPC the + /// default value is 128 since all PowerPC cpu's starting at PPC 970 provide + /// it. + /// \note The runtime library on some PowerPC platforms misreport the size + /// of the cache line size. The runtime library reports 64, while the cpu + /// has a cache line size of 128. + /// \sa CentOS Issue + /// 14599: sysconf(_SC_LEVEL1_DCACHE_LINESIZE) returns 0 instead of 128 + /// \since Crypto++ 5.3 + #define CRYPTOPP_L1_CACHE_LINE_SIZE ... +#else + #ifndef CRYPTOPP_L1_CACHE_LINE_SIZE + #if defined(CRYPTOPP_BOOL_X32) || defined(CRYPTOPP_BOOL_X64) || defined(CRYPTOPP_BOOL_ARMV8) || \ + defined(CRYPTOPP_BOOL_MIPS64) || defined(CRYPTOPP_BOOL_SPARC64) + #define CRYPTOPP_L1_CACHE_LINE_SIZE 64 + #elif defined(CRYPTOPP_BOOL_PPC32) || defined(CRYPTOPP_BOOL_PPC64) + // http://lists.llvm.org/pipermail/llvm-dev/2017-March/110982.html + #define CRYPTOPP_L1_CACHE_LINE_SIZE 128 + #else + // L1 cache line size is 32 on Pentium III and earlier + #define CRYPTOPP_L1_CACHE_LINE_SIZE 32 + #endif + #endif +#endif + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief Initialized data section + /// \details CRYPTOPP_SECTION_INIT is added to variables to place them in the + /// initialized data section (sometimes denoted .data). The placement + /// helps avoid "uninitialized variable" warnings from Valgrind and other tools. + #define CRYPTOPP_SECTION_INIT ... +#else + // The section attribute attempts to initialize CPU flags to avoid Valgrind findings above -O1 + #if ((defined(__MACH__) && defined(__APPLE__)) && ((CRYPTOPP_LLVM_CLANG_VERSION >= 30600) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 70100) || (CRYPTOPP_GCC_VERSION >= 40300))) + #define CRYPTOPP_SECTION_INIT __attribute__((section ("__DATA,__data"))) + #elif (defined(__ELF__) && (CRYPTOPP_GCC_VERSION >= 40300)) + #define CRYPTOPP_SECTION_INIT __attribute__((section ("nocommon"))) + #elif defined(__ELF__) && (defined(__xlC__) || defined(__ibmxl__)) + #define CRYPTOPP_SECTION_INIT __attribute__((section ("nocommon"))) + #else + #define CRYPTOPP_SECTION_INIT + #endif +#endif + +// How to disable CPU feature probing. We determine machine +// capabilities by performing an os/platform *query* first, +// like getauxv(). If the *query* fails, we move onto a +// cpu *probe*. The cpu *probe* tries to exeute an instruction +// and then catches a SIGILL on Linux or the exception +// EXCEPTION_ILLEGAL_INSTRUCTION on Windows. Some OSes +// fail to hangle a SIGILL gracefully, like Apple OSes. Apple +// machines corrupt memory and variables around the probe. +#if defined(__APPLE__) + #define CRYPTOPP_NO_CPU_FEATURE_PROBES 1 +#endif + +// Flavor of inline assembly language +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief Microsoft style inline assembly + /// \details CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY is defined when either + /// _MSC_VER or __BORLANDC__ are defined. + #define CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY ... + /// \brief GNU style inline assembly + /// \details CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY is defined when neither + /// _MSC_VER nor __BORLANDC__ are defined. + #define CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY ... +#elif defined(CRYPTOPP_MSC_VERSION) || defined(__BORLANDC__) || \ + defined(CRYPTOPP_MSVC_CLANG_VERSION) + #define CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY 1 +#else + #define CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY 1 +#endif + +#endif // CRYPTOPP_CONFIG_CPU_H diff --git a/third_party/cryptoppwin/include/cryptopp/config_cxx.h b/third_party/cryptoppwin/include/cryptopp/config_cxx.h new file mode 100644 index 00000000..ffd57add --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/config_cxx.h @@ -0,0 +1,250 @@ +// config_cxx.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_cxx.h +/// \brief Library configuration file +/// \details config_cxx.h provides defines for C++ language and +/// runtime library +/// features. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_cxx.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +// Visual Studio began at VS2010, http://msdn.microsoft.com/en-us/library/hh567368%28v=vs.110%29.aspx +// and https://docs.microsoft.com/en-us/cpp/visual-cpp-language-conformance +// Intel, http://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler +// GCC, http://gcc.gnu.org/projects/cxx0x.html +// Clang, http://clang.llvm.org/cxx_status.html + +#ifndef CRYPTOPP_CONFIG_CXX_H +#define CRYPTOPP_CONFIG_CXX_H + +#include "config_os.h" +#include "config_cpu.h" +#include "config_ver.h" + +// https://github.com/weidai11/cryptopp/issues/960 +#include +#include + +// You may need to force include a C++ header on Android when using STLPort +// to ensure _STLPORT_VERSION is defined +#if (defined(CRYPTOPP_MSC_VERSION) && CRYPTOPP_MSC_VERSION <= 1300) || \ + defined(__MWERKS__) || \ + (defined(_STLPORT_VERSION) && ((_STLPORT_VERSION < 0x450) || defined(_STLP_NO_UNCAUGHT_EXCEPT_SUPPORT)) || \ + (__cplusplus >= 202002L)) +#define CRYPTOPP_DISABLE_UNCAUGHT_EXCEPTION +#endif + +// Ancient Crypto++ define, dating back to C++98. +#ifndef CRYPTOPP_DISABLE_UNCAUGHT_EXCEPTION +# define CRYPTOPP_UNCAUGHT_EXCEPTION_AVAILABLE 1 +# define CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION 1 +#endif + +// Compatibility with non-clang compilers. +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +// C++11 macro version, https://stackoverflow.com/q/7223991/608639 +#if ((CRYPTOPP_MSC_VERSION >= 1600) || (__cplusplus >= 201103L)) && !defined(_STLPORT_VERSION) +# define CRYPTOPP_CXX11 1 +#endif + +// Hack ahead. Apple's standard library does not have C++'s unique_ptr in C++11. +// We can't test for unique_ptr directly because some of the non-Apple Clangs +// on OS X fail the same way. However, modern standard libraries have +// , so we test for it instead. Thanks to Jonathan Wakely for +// devising the clever test for modern/ancient versions. TODO: test under +// Xcode 3, where g++ is really g++. +#if defined(__APPLE__) && defined(__clang__) +# if !(defined(__has_include) && __has_include()) +# undef CRYPTOPP_CXX11 +# endif +#endif + +// C++14 macro version, https://stackoverflow.com/q/26089319/608639 +#if defined(CRYPTOPP_CXX11) && !defined(CRYPTOPP_NO_CXX14) +# if ((CRYPTOPP_MSC_VERSION >= 1900) || (__cplusplus >= 201402L)) && !defined(_STLPORT_VERSION) +# define CRYPTOPP_CXX14 1 +# endif +#endif + +// C++17 macro version, https://stackoverflow.com/q/38456127/608639 +#if defined(CRYPTOPP_CXX14) && !defined(CRYPTOPP_NO_CXX17) +# if ((CRYPTOPP_MSC_VERSION >= 1900) || (__cplusplus >= 201703L)) && !defined(_STLPORT_VERSION) +# define CRYPTOPP_CXX17 1 +# endif +#endif + +// ***************** C++11 and above ******************** + +#if defined(CRYPTOPP_CXX11) + +// atomics: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.1/3.2; Intel 13.0; SunCC 5.14. +#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_atomic) || \ + (__INTEL_COMPILER >= 1300) || (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5140) +# define CRYPTOPP_CXX11_ATOMIC 1 +#endif // atomics + +// synchronization: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.3; Xcode 5.0; Intel 12.0; SunCC 5.13. +// TODO: verify Clang and Intel versions; find __has_feature(x) extension for Clang +#if (CRYPTOPP_MSC_VERSION >= 1700) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30300) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 50000) || (__INTEL_COMPILER >= 1200) || \ + (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5130) +// Hack ahead. New GCC compilers like GCC 6 on AIX 7.0 or earlier as well as original MinGW +// don't have the synchronization gear. However, Wakely's test used for Apple does not work +// on the GCC/AIX combination. Another twist is we need other stuff from C++11, +// like no-except destructors. Dumping preprocessors shows the following may +// apply: http://stackoverflow.com/q/14191566/608639. +# include +# if !defined(__GLIBCXX__) || defined(_GLIBCXX_HAS_GTHREADS) +# define CRYPTOPP_CXX11_SYNCHRONIZATION 1 +# endif +#endif // synchronization + +// Dynamic Initialization and Destruction with Concurrency ("Magic Statics") +// MS at VS2015 with Vista (19.00); GCC at 4.3; LLVM Clang at 2.9; Apple Clang at 4.0; Intel 11.1; SunCC 5.13. +// Microsoft's implementation only works for Vista and above, so its further +// limited. http://connect.microsoft.com/VisualStudio/feedback/details/1789709 +// Clang may not support this as early as we indicate. Also see https://bugs.llvm.org/show_bug.cgi?id=47012. +#if (__cpp_threadsafe_static_init >= 200806) || \ + (CRYPTOPP_MSC_VERSION >= 1900) && ((WINVER >= 0x0600) || (_WIN32_WINNT >= 0x0600)) || \ + (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) || \ + (__INTEL_COMPILER >= 1110) || (CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_STATIC_INIT 1 +#endif // Dynamic Initialization compilers + +// deleted functions: MS at VS2013 (18.00); GCC at 4.3; Clang at 2.9; Intel 12.1; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) || (__INTEL_COMPILER >= 1210) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_DELETED_FUNCTIONS 1 +#endif // deleted functions + +// alignof/alignas: MS at VS2015 (19.00); GCC at 4.8; Clang at 3.0; Intel 15.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_alignas) || \ + (__INTEL_COMPILER >= 1500) || (CRYPTOPP_GCC_VERSION >= 40800) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_ALIGNAS 1 +#endif // alignas + +// alignof: MS at VS2015 (19.00); GCC at 4.5; Clang at 2.9; Intel 15.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_alignof) || \ + (__INTEL_COMPILER >= 1500) || (CRYPTOPP_GCC_VERSION >= 40500) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_ALIGNOF 1 +#endif // alignof + +// initializer lists: MS at VS2013 (18.00); GCC at 4.4; Clang at 3.1; Intel 14.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1800) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30100) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 40000) || (__INTEL_COMPILER >= 1400) || \ + (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_INITIALIZER_LIST 1 +#endif // alignas + +// lambdas: MS at VS2012 (17.00); GCC at 4.9; Clang at 3.3; Intel 12.0; SunCC 5.14. +#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_lambdas) || \ + (__INTEL_COMPILER >= 1200) || (CRYPTOPP_GCC_VERSION >= 40900) || (__SUNPRO_CC >= 0x5140) +# define CRYPTOPP_CXX11_LAMBDA 1 +#endif // lambdas + +// noexcept: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.0; Intel 14.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1900) || __has_feature(cxx_noexcept) || \ + (__INTEL_COMPILER >= 1400) || (CRYPTOPP_GCC_VERSION >= 40600) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_NOEXCEPT 1 +#endif // noexcept compilers + +// variadic templates: MS at VS2013 (18.00); GCC at 4.3; Clang at 2.9; Intel 12.1; SunCC 5.13. +#if (__cpp_variadic_templates >= 200704) || __has_feature(cxx_variadic_templates) || \ + (CRYPTOPP_MSC_VERSION >= 1800) || (__INTEL_COMPILER >= 1210) || \ + (CRYPTOPP_GCC_VERSION >= 40300) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_VARIADIC_TEMPLATES 1 +#endif // variadic templates + +// constexpr: MS at VS2015 (19.00); GCC at 4.6; Clang at 3.1; Intel 16.0; SunCC 5.13. +// Intel has mis-supported the feature since at least ICPC 13.00 +#if (__cpp_constexpr >= 200704) || __has_feature(cxx_constexpr) || \ + (CRYPTOPP_MSC_VERSION >= 1900) || (__INTEL_COMPILER >= 1600) || \ + (CRYPTOPP_GCC_VERSION >= 40600) || (__SUNPRO_CC >= 0x5130) +# define CRYPTOPP_CXX11_CONSTEXPR 1 +#endif // constexpr compilers + +// strong typed enums: MS at VS2012 (17.00); GCC at 4.4; Clang at 3.3; Intel 14.0; SunCC 5.12. +// Mircorosft and Intel had partial support earlier, but we require full support. +#if (CRYPTOPP_MSC_VERSION >= 1700) || __has_feature(cxx_strong_enums) || \ + (__INTEL_COMPILER >= 1400) || (CRYPTOPP_GCC_VERSION >= 40400) || (__SUNPRO_CC >= 0x5120) +# define CRYPTOPP_CXX11_STRONG_ENUM 1 +#endif // constexpr compilers + +// nullptr_t: MS at VS2010 (16.00); GCC at 4.6; Clang at 3.3; Intel 10.0; SunCC 5.13. +#if (CRYPTOPP_MSC_VERSION >= 1600) || __has_feature(cxx_nullptr) || \ + (__INTEL_COMPILER >= 1000) || (CRYPTOPP_GCC_VERSION >= 40600) || \ + (__SUNPRO_CC >= 0x5130) || defined(__IBMCPP_NULLPTR) +# define CRYPTOPP_CXX11_NULLPTR 1 +#endif // nullptr_t compilers + +#endif // CRYPTOPP_CXX11 + +// ***************** C++14 and above ******************** + +#if defined(CRYPTOPP_CXX14) + +// Extended static_assert with one argument +// Microsoft cannot handle the single argument static_assert as of VS2019 (cl.exe 19.00) +#if (__cpp_static_assert >= 201411) +# define CRYPTOPP_CXX17_STATIC_ASSERT 1 +#endif // static_assert + +#endif + +// ***************** C++17 and above ******************** + +// C++17 is available +#if defined(CRYPTOPP_CXX17) + +// C++17 uncaught_exceptions: MS at VS2015 (19.00); GCC at 6.0; Clang at 3.5; Intel 18.0. +// Clang and __EXCEPTIONS see http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html +// Also see https://github.com/weidai11/cryptopp/issues/980. I'm not sure what +// to do when the compiler defines __cpp_lib_uncaught_exceptions but the platform +// does not support std::uncaught_exceptions. What was Apple thinking??? +#if defined(__clang__) +# if __EXCEPTIONS && __has_feature(cxx_exceptions) +# if __cpp_lib_uncaught_exceptions >= 201411L +# define CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS 1 +# endif +# endif +#elif (CRYPTOPP_MSC_VERSION >= 1900) || (__INTEL_COMPILER >= 1800) || \ + (CRYPTOPP_GCC_VERSION >= 60000) || (__cpp_lib_uncaught_exceptions >= 201411L) +# define CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS 1 +#endif // uncaught_exceptions compilers + +#endif // CRYPTOPP_CXX17 + +// ***************** C++ fixups ******************** + +#if defined(CRYPTOPP_CXX11_NOEXCEPT) +# define CRYPTOPP_THROW noexcept(false) +# define CRYPTOPP_NO_THROW noexcept(true) +#else +# define CRYPTOPP_THROW +# define CRYPTOPP_NO_THROW +#endif // CRYPTOPP_CXX11_NOEXCEPT + +// Hack... C++11 nullptr_t type safety and analysis +#if defined(CRYPTOPP_CXX11_NULLPTR) && !defined(NULLPTR) +# define NULLPTR nullptr +#elif !defined(NULLPTR) +# define NULLPTR NULL +#endif // CRYPTOPP_CXX11_NULLPTR + +#endif // CRYPTOPP_CONFIG_CXX_H diff --git a/third_party/cryptoppwin/include/cryptopp/config_dll.h b/third_party/cryptoppwin/include/cryptopp/config_dll.h new file mode 100644 index 00000000..73d16d9d --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/config_dll.h @@ -0,0 +1,178 @@ +// config_dll.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_dll.h +/// \brief Library configuration file +/// \details config_dll.h provides defines for shared objects and +/// dynamic libraries. Generally speaking the macros are used to export +/// classes and template classes from the Win32 dynamic link library. +/// When not building the Win32 dynamic link library they are mostly an extern +/// template declaration. +/// \details In practice they are a furball coughed up by a cat and then peed +/// on by a dog. They are awful to get just right because of inconsistent +/// compiler support for extern templates, manual instantiation and the FIPS DLL. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_dll.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script, +/// Visual Studio, +/// and FIPS DLL +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_DLL_H +#define CRYPTOPP_CONFIG_DLL_H + +#include "config_os.h" + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + + /// \brief Win32 define for dynamic link libraries + /// \details CRYPTOPP_IMPORTS is set in the Visual Studio project files. + /// When the macro is set, CRYPTOPP_DLL is defined to + /// __declspec(dllimport). + /// \details This macro has no effect on Unix & Linux. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_IMPORTS ... + + /// \brief Win32 define for dynamic link libraries + /// \details CRYPTOPP_EXPORTS is set in the Visual Studio project files. + /// When the macro is set, CRYPTOPP_DLL is defined to + /// __declspec(dllexport). + /// \details This macro has no effect on Unix & Linux. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_EXPORTS ... + + /// \brief Win32 define for dynamic link libraries + /// \details CRYPTOPP_IS_DLL is set in the Visual Studio project files. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_IS_DLL + + /// \brief Instantiate templates in a dynamic library + /// \details CRYPTOPP_DLL_TEMPLATE_CLASS decoration should be used + /// for classes intended to be exported from dynamic link libraries. + /// \details This macro is primarily used on Win32, but sees some + /// action on Unix & Linux due to the source file dll.cpp. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_DLL_TEMPLATE_CLASS ... + + /// \brief Instantiate templates in a dynamic library + /// \details CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS decoration should be used + /// for template classes intended to be exported from dynamic link libraries. + /// \details This macro is primarily used on Win32, but sees some + /// action on Unix & Linux due to the source file dll.cpp. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS ... + + /// \brief Instantiate templates in a dynamic library + /// \details CRYPTOPP_STATIC_TEMPLATE_CLASS decoration should be used + /// for template classes intended to be exported from dynamic link libraries. + /// \details This macro is primarily used on Win32, but sees some + /// action on Unix & Linux due to the source file dll.cpp. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_STATIC_TEMPLATE_CLASS ... + + /// \brief Instantiate templates in a dynamic library + /// \details CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS decoration should be used + /// for template classes intended to be exported from dynamic link libraries. + /// \details This macro is primarily used on Win32, but sees some + /// action on Unix & Linux due to the source file dll.cpp. + /// \sa Visual Studio, + /// and FIPS DLL + /// on the Crypto++ wiki + #define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS ... + + /// \brief Override for internal linkage + /// \details CRYPTOPP_TABLE can be used to override internal linkage + /// on tables with the const qualifier. According to C++ rules + /// a declaration with const qualifier is internal linkage. + /// \note The name CRYPTOPP_TABLE was chosen because it is often used to + /// export a table, like AES or SHA constants. The name avoids collisions + /// with the DLL gear macros, like CRYPTOPP_EXPORTS and CRYPTOPP_EXTERN. + #define CRYPTOPP_TABLE extern + + /// \brief Win32 calling convention + /// \details CRYPTOPP_API sets the calling convention on Win32. + /// On Win32 CRYPTOPP_API is __cedcl. On Unix & Linux + /// CRYPTOPP_API is defined to nothing. + /// \sa Visual Studio + /// on the Crypto++ wiki + #define CRYPTOPP_API ... + +#else // CRYPTOPP_DOXYGEN_PROCESSING + +#if defined(CRYPTOPP_WIN32_AVAILABLE) + + #if defined(CRYPTOPP_EXPORTS) + # define CRYPTOPP_IS_DLL + # define CRYPTOPP_DLL __declspec(dllexport) + #elif defined(CRYPTOPP_IMPORTS) + # define CRYPTOPP_IS_DLL + # define CRYPTOPP_DLL __declspec(dllimport) + #else + # define CRYPTOPP_DLL + #endif + + // C++ makes const internal linkage + #define CRYPTOPP_TABLE extern + #define CRYPTOPP_API __cdecl + +#else // not CRYPTOPP_WIN32_AVAILABLE + + // C++ makes const internal linkage + #define CRYPTOPP_TABLE extern + #define CRYPTOPP_DLL + #define CRYPTOPP_API + +#endif // CRYPTOPP_WIN32_AVAILABLE + +#if defined(__MWERKS__) +# define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS extern class CRYPTOPP_DLL +#elif defined(__BORLANDC__) || defined(__SUNPRO_CC) +# define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS template class CRYPTOPP_DLL +#else +# define CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS extern template class CRYPTOPP_DLL +#endif + +#if defined(CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES) && !defined(CRYPTOPP_IMPORTS) +# define CRYPTOPP_DLL_TEMPLATE_CLASS template class CRYPTOPP_DLL +#else +# define CRYPTOPP_DLL_TEMPLATE_CLASS CRYPTOPP_EXTERN_DLL_TEMPLATE_CLASS +#endif + +#if defined(__MWERKS__) +# define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS extern class +#elif defined(__BORLANDC__) || defined(__SUNPRO_CC) +# define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS template class +#else +# define CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS extern template class +#endif + +#if defined(CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES) && !defined(CRYPTOPP_EXPORTS) +# define CRYPTOPP_STATIC_TEMPLATE_CLASS template class +#else +# define CRYPTOPP_STATIC_TEMPLATE_CLASS CRYPTOPP_EXTERN_STATIC_TEMPLATE_CLASS +#endif + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +#endif // CRYPTOPP_CONFIG_DLL_H diff --git a/third_party/cryptoppwin/include/cryptopp/config_int.h b/third_party/cryptoppwin/include/cryptopp/config_int.h new file mode 100644 index 00000000..2eeda0e9 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/config_int.h @@ -0,0 +1,268 @@ +// config_int.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_int.h +/// \brief Library configuration file +/// \details config_int.h provides defines and typedefs for fixed +/// size integers. The library's choices for fixed size integers predates other +/// standard-based integers by about 5 years. After fixed sizes were +/// made standard, the library continued to use its own definitions for +/// compatibility with previous versions of the library. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_int.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_INT_H +#define CRYPTOPP_CONFIG_INT_H + +#include "config_ns.h" +#include "config_ver.h" +#include "config_misc.h" + +// C5264 new for VS2022/v17.4, MSC v17.3.4 +// https://github.com/weidai11/cryptopp/issues/1185 +#if (CRYPTOPP_MSC_VERSION) +# pragma warning(push) +# if (CRYPTOPP_MSC_VERSION >= 1933) +# pragma warning(disable: 5264) +# endif +#endif + +/// \brief Library byte guard +/// \details CRYPTOPP_NO_GLOBAL_BYTE indicates byte is in the Crypto++ +/// namespace. +/// \details The Crypto++ byte was originally in global namespace to avoid +/// ambiguity with other byte typedefs. byte was moved to CryptoPP namespace +/// at Crypto++ 6.0 due to C++17, std::byte and potential compile problems. +/// \sa Issue 442, +/// std::byte on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +#define CRYPTOPP_NO_GLOBAL_BYTE 1 + +NAMESPACE_BEGIN(CryptoPP) + +// Signed words added at Issue 609 for early versions of and Visual Studio and +// the NaCl gear. Also see https://github.com/weidai11/cryptopp/issues/609. + +/// \brief 8-bit unsigned datatype +/// \details The Crypto++ byte was originally in global namespace to avoid +/// ambiguity with other byte typedefs. byte was moved to CryptoPP namespace +/// at Crypto++ 6.0 due to C++17, std::byte and potential compile problems. +/// \sa CRYPTOPP_NO_GLOBAL_BYTE, Issue 442, +/// std::byte on the +/// Crypto++ wiki +/// \since Crypto++ 1.0, CryptoPP namespace since Crypto++ 6.0 +typedef unsigned char byte; +/// \brief 16-bit unsigned datatype +/// \since Crypto++ 1.0 +typedef unsigned short word16; +/// \brief 32-bit unsigned datatype +/// \since Crypto++ 1.0 +typedef unsigned int word32; + +/// \brief 8-bit signed datatype +/// \details The 8-bit signed datatype was added to support constant time +/// implementations for curve25519, X25519 key agreement and ed25519 +/// signatures. +/// \since Crypto++ 8.0 +typedef signed char sbyte; +/// \brief 16-bit signed datatype +/// \details The 32-bit signed datatype was added to support constant time +/// implementations for curve25519, X25519 key agreement and ed25519 +/// signatures. +/// \since Crypto++ 8.0 +typedef signed short sword16; +/// \brief 32-bit signed datatype +/// \details The 32-bit signed datatype was added to support constant time +/// implementations for curve25519, X25519 key agreement and ed25519 +/// signatures. +/// \since Crypto++ 8.0 +typedef signed int sword32; + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + + /// \brief 64-bit unsigned datatype + /// \details The typedef for word64 varies depending on the platform. + /// On Microsoft platforms it is unsigned __int64. On Unix & Linux + /// with LP64 data model it is unsigned long. On Unix & Linux with ILP32 + /// data model it is unsigned long long. + /// \since Crypto++ 1.0 + typedef unsigned long long word64; + + /// \brief 64-bit signed datatype + /// \details The typedef for sword64 varies depending on the platform. + /// On Microsoft platforms it is signed __int64. On Unix & Linux + /// with LP64 data model it is signed long. On Unix & Linux with ILP32 + /// data model it is signed long long. + /// \since Crypto++ 8.0 + typedef signed long long sword64; + + /// \brief 128-bit unsigned datatype + /// \details The typedef for word128 varies depending on the platform. + /// word128 is only available on 64-bit machines when + /// CRYPTOPP_WORD128_AVAILABLE is defined. + /// On Unix & Linux with LP64 data model it is __uint128_t. + /// Microsoft platforms do not provide a 128-bit integer type. 32-bit platforms + /// do not provide a 128-bit integer type. + /// \since Crypto++ 5.6 + typedef __uint128_t word128; + + /// \brief Declare an unsigned word64 + /// \details W64LIT is used to portability declare or assign 64-bit literal values. + /// W64LIT will append the proper suffix to ensure the compiler accepts the literal. + /// \details Use the macro like shown below. + ///
+	///    word64 x = W64LIT(0xffffffffffffffff);
+	///  
+ /// \since Crypto++ 1.0 + #define W64LIT(x) ... + + /// \brief Declare a signed word64 + /// \details SW64LIT is used to portability declare or assign 64-bit literal values. + /// SW64LIT will append the proper suffix to ensure the compiler accepts the literal. + /// \details Use the macro like shown below. + ///
+	///    sword64 x = SW64LIT(0xffffffffffffffff);
+	///  
+ /// \since Crypto++ 8.0 + #define SW64LIT(x) ... + + /// \brief Declare ops on word64 are slow + /// \details CRYPTOPP_BOOL_SLOW_WORD64 is typically defined to 1 on platforms + /// that have a machine word smaller than 64-bits. That is, the define + /// is present on 32-bit platforms. The define is also present on platforms + /// where the cpu is slow even with a 64-bit cpu. + #define CRYPTOPP_BOOL_SLOW_WORD64 ... + +#elif defined(CRYPTOPP_MSC_VERSION) || defined(__BORLANDC__) + typedef signed __int64 sword64; + typedef unsigned __int64 word64; + #define SW64LIT(x) x##i64 + #define W64LIT(x) x##ui64 +#elif (_LP64 || __LP64__) + typedef signed long sword64; + typedef unsigned long word64; + #define SW64LIT(x) x##L + #define W64LIT(x) x##UL +#else + typedef signed long long sword64; + typedef unsigned long long word64; + #define SW64LIT(x) x##LL + #define W64LIT(x) x##ULL +#endif + +/// \brief Large word type +/// \details lword is a typedef for large word types. It is used for file +/// offsets and such. +typedef word64 lword; + +/// \brief Large word type max value +/// \details LWORD_MAX is the maximum value for large word types. +/// Since an lword is an unsigned type, the value is +/// 0xffffffffffffffff. W64LIT will append the proper suffix. +CRYPTOPP_CONST_OR_CONSTEXPR lword LWORD_MAX = W64LIT(0xffffffffffffffff); + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + /// \brief Half word used for multiprecision integer arithmetic + /// \details hword is used for multiprecision integer arithmetic. + /// The typedef for hword varies depending on the platform. + /// On 32-bit platforms it is usually word16. On 64-bit platforms + /// it is usually word32. + /// \details Library users typically use byte, word16, word32 and word64. + /// \since Crypto++ 2.0 + typedef word32 hword; + /// \brief Full word used for multiprecision integer arithmetic + /// \details word is used for multiprecision integer arithmetic. + /// The typedef for word varies depending on the platform. + /// On 32-bit platforms it is usually word32. On 64-bit platforms + /// it is usually word64. + /// \details Library users typically use byte, word16, word32 and word64. + /// \since Crypto++ 2.0 + typedef word64 word; + /// \brief Double word used for multiprecision integer arithmetic + /// \details dword is used for multiprecision integer arithmetic. + /// The typedef for dword varies depending on the platform. + /// On 32-bit platforms it is usually word64. On 64-bit Unix & + /// Linux platforms it is usually word128. word128 is + /// not available on Microsoft platforms. word128 is only available + /// when CRYPTOPP_WORD128_AVAILABLE is defined. + /// \details Library users typically use byte, word16, word32 and word64. + /// \sa CRYPTOPP_WORD128_AVAILABLE + /// \since Crypto++ 2.0 + typedef word128 dword; + + /// \brief 128-bit word availability + /// \details CRYPTOPP_WORD128_AVAILABLE indicates a 128-bit word is + /// available from the platform. 128-bit words are usually available on + /// 64-bit platforms, but not available 32-bit platforms. + /// \details If CRYPTOPP_WORD128_AVAILABLE is not defined, then 128-bit + /// words are not available. + /// \details GCC and compatible compilers signal 128-bit word availability + /// with the preporcessor macro __SIZEOF_INT128__ >= 16. + /// \since Crypto++ 2.0 + #define CRYPTOPP_WORD128_AVAILABLE ... +#else + // define hword, word, and dword. these are used for multiprecision integer arithmetic + // Intel compiler won't have _umul128 until version 10.0. See http://softwarecommunity.intel.com/isn/Community/en-US/forums/thread/30231625.aspx + #if (defined(CRYPTOPP_MSC_VERSION) && (!defined(__INTEL_COMPILER) || __INTEL_COMPILER >= 1000) && (defined(_M_X64) || defined(_M_IA64))) || (defined(__DECCXX) && defined(__alpha__)) || (defined(__INTEL_COMPILER) && defined(__x86_64__)) || (defined(__SUNPRO_CC) && defined(__x86_64__)) + typedef word32 hword; + typedef word64 word; + #else + #define CRYPTOPP_NATIVE_DWORD_AVAILABLE 1 + #if defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || defined(__x86_64__) || defined(__mips64) || defined(__sparc64__) || defined(__aarch64__) + #if ((CRYPTOPP_GCC_VERSION >= 30400) || (CRYPTOPP_LLVM_CLANG_VERSION >= 30000) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40300)) && (__SIZEOF_INT128__ >= 16) + // GCC 4.0.1 on MacOS X is missing __umodti3 and __udivti3 + // GCC 4.8.3 and bad uint128_t ops on PPC64/POWER7 (Issue 421) + // mode(TI) division broken on amd64 with GCC earlier than GCC 3.4 + typedef word32 hword; + typedef word64 word; + typedef __uint128_t dword; + typedef __uint128_t word128; + #define CRYPTOPP_WORD128_AVAILABLE 1 + #else + // if we're here, it means we're on a 64-bit CPU but we don't have a way to obtain 128-bit multiplication results + typedef word16 hword; + typedef word32 word; + typedef word64 dword; + #endif + #else + // being here means the native register size is probably 32 bits or less + #define CRYPTOPP_BOOL_SLOW_WORD64 1 + typedef word16 hword; + typedef word32 word; + typedef word64 dword; + #endif + #endif +#endif + +#ifndef CRYPTOPP_BOOL_SLOW_WORD64 +# define CRYPTOPP_BOOL_SLOW_WORD64 0 +#endif + +/// \brief Size of a platform word in bytes +/// \details The size of a platform word, in bytes +CRYPTOPP_CONST_OR_CONSTEXPR unsigned int WORD_SIZE = sizeof(word); + +/// \brief Size of a platform word in bits +/// \details The size of a platform word, in bits +/// \sa https://github.com/weidai11/cryptopp/issues/1185 +CRYPTOPP_CONST_OR_CONSTEXPR unsigned int WORD_BITS = WORD_SIZE * 8; + +NAMESPACE_END + +#if (CRYPTOPP_MSC_VERSION) +# pragma warning(pop) +#endif + +#endif // CRYPTOPP_CONFIG_INT_H diff --git a/third_party/cryptoppwin/include/cryptopp/config_misc.h b/third_party/cryptoppwin/include/cryptopp/config_misc.h new file mode 100644 index 00000000..68e196cb --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/config_misc.h @@ -0,0 +1,199 @@ +// config_misc.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_misc.h +/// \brief Library configuration file +/// \details config_misc.h provides miscellaneous defines. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_misc.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_MISC_H +#define CRYPTOPP_CONFIG_MISC_H + +#include "config_asm.h" +#include "config_cxx.h" +#include "config_os.h" +#include "config_ver.h" + +// Define this if running on a big-endian CPU +// big endian will be assumed if CRYPTOPP_LITTLE_ENDIAN is not non-0 +#if !defined(CRYPTOPP_LITTLE_ENDIAN) && !defined(CRYPTOPP_BIG_ENDIAN) && (defined(__BIG_ENDIAN__) || (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) || (defined(__m68k__) || defined(__MC68K__)) || defined(__sparc) || defined(__sparc__) || defined(__hppa__) || defined(__MIPSEB__) || defined(__ARMEB__) || (defined(__MWERKS__) && !defined(__INTEL__))) +# define CRYPTOPP_BIG_ENDIAN 1 +#endif + +// Define this if running on a little-endian CPU +// big endian will be assumed if CRYPTOPP_LITTLE_ENDIAN is not non-0 +#if !defined(CRYPTOPP_BIG_ENDIAN) && !defined(CRYPTOPP_LITTLE_ENDIAN) +# define CRYPTOPP_LITTLE_ENDIAN 1 +#endif + +// Define this if you want to set a prefix for TestData/ and TestVectors/ +// Be sure to add the trailing slash since its simple concatenation. +// After https://github.com/weidai11/cryptopp/issues/760 the library +// should find the test vectors and data without much effort. It +// will search in "./" and "$ORIGIN/../share/cryptopp" automatically. +#ifndef CRYPTOPP_DATA_DIR +# define CRYPTOPP_DATA_DIR "" +#endif + +// Define this to disable the test suite from searching for test +// vectors and data in "./" and "$ORIGIN/../share/cryptopp". The +// library will still search in CRYPTOPP_DATA_DIR, regardless. +// Some distros may want to disable this feature. Also see +// https://github.com/weidai11/cryptopp/issues/760 +// #ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH +// # define CRYPTOPP_DISABLE_DATA_DIR_SEARCH +// #endif + +// Define this if you want or need the library's memcpy_s and memmove_s. +// See http://github.com/weidai11/cryptopp/issues/28. +// #if !defined(CRYPTOPP_WANT_SECURE_LIB) +// # define CRYPTOPP_WANT_SECURE_LIB +// #endif + +// Define this if ARMv8 shifts are slow. ARM Cortex-A53 and Cortex-A57 shift +// operation perform poorly, so NEON and ASIMD code that relies on shifts +// or rotates often performs worse than C/C++ code. Also see +// http://github.com/weidai11/cryptopp/issues/367. +#define CRYPTOPP_SLOW_ARMV8_SHIFT 1 + +// CRYPTOPP_DEBUG enables the library's CRYPTOPP_ASSERT. CRYPTOPP_ASSERT +// raises a SIGTRAP (Unix) or calls DebugBreak() (Windows). CRYPTOPP_ASSERT +// is only in effect when CRYPTOPP_DEBUG, DEBUG or _DEBUG is defined. Unlike +// Posix assert, CRYPTOPP_ASSERT is not affected by NDEBUG (or failure to +// define it). According to the ndk-build docs, Android use NDK_DEBUG=1 to +// signal a DEBUG build (and NDK_DEBUG=0 to signal non-DEBUG build). +// Also see http://github.com/weidai11/cryptopp/issues/277, CVE-2016-7420 and +// https://developer.android.com/ndk/guides/ndk-build +#if (defined(DEBUG) || defined(_DEBUG)) || (defined(NDK_DEBUG) && (NDK_DEBUG > 0)) +# undef CRYPTOPP_DEBUG +# define CRYPTOPP_DEBUG 1 +#endif + +// File system code to use when creating GZIP archive. +// http://www.gzip.org/format.txt +#if !defined(GZIP_OS_CODE) +# if defined(__macintosh__) +# define GZIP_OS_CODE 7 +# elif defined(__unix__) || defined(__linux__) +# define GZIP_OS_CODE 3 +# else +# define GZIP_OS_CODE 0 +# endif +#endif + +// Try this if your CPU has 256K internal cache or a slow multiply instruction +// and you want a (possibly) faster IDEA implementation using log tables +// #define IDEA_LARGECACHE + +// Define this if, for the linear congruential RNG, you want to use +// the original constants as specified in S.K. Park and K.W. Miller's +// CACM paper. +// #define LCRNG_ORIGINAL_NUMBERS + +// Define this if you want Integer's operator<< to honor std::showbase (and +// std::noshowbase). If defined, Integer will use a suffix of 'b', 'o', 'h' +// or '.' (the last for decimal) when std::showbase is in effect. If +// std::noshowbase is set, then the suffix is not added to the Integer. If +// not defined, existing behavior is preserved and Integer will use a suffix +// of 'b', 'o', 'h' or '.' (the last for decimal). +// #define CRYPTOPP_USE_STD_SHOWBASE + +// Define this if you want to decouple AlgorithmParameters and Integer +// The decoupling should make it easier for the linker to remove Integer +// related code for those who do not need Integer, and avoid a potential +// race during AssignIntToInteger pointer initialization. Also +// see http://github.com/weidai11/cryptopp/issues/389. +// #define CRYPTOPP_NO_ASSIGN_TO_INTEGER + +// Need GCC 4.6/Clang 1.7/Apple Clang 2.0 or above due to "GCC diagnostic {push|pop}" +#if (CRYPTOPP_GCC_VERSION >= 40600) || (CRYPTOPP_LLVM_CLANG_VERSION >= 10700) || \ + (CRYPTOPP_APPLE_CLANG_VERSION >= 20000) + #define CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE 1 +#endif + +// Portable way to suppress warnings. +// Moved from misc.h due to circular depenedencies. +#ifndef CRYPTOPP_UNUSED + #define CRYPTOPP_UNUSED(x) ((void)(x)) +#endif + +// how to disable inlining +#if defined(CRYPTOPP_MSC_VERSION) +# define CRYPTOPP_NOINLINE_DOTDOTDOT +# define CRYPTOPP_NOINLINE __declspec(noinline) +#elif defined(__xlc__) || defined(__xlC__) || defined(__ibmxl__) +# define CRYPTOPP_NOINLINE_DOTDOTDOT ... +# define CRYPTOPP_NOINLINE __attribute__((noinline)) +#elif defined(__GNUC__) +# define CRYPTOPP_NOINLINE_DOTDOTDOT +# define CRYPTOPP_NOINLINE __attribute__((noinline)) +#else +# define CRYPTOPP_NOINLINE_DOTDOTDOT ... +# define CRYPTOPP_NOINLINE +#endif + +// http://stackoverflow.com/a/13867690/608639 +// CRYPTOPP_CONST_OR_CONSTEXPR due to https://github.com/weidai11/cryptopp/issues/1185 +#if defined(CRYPTOPP_CXX11_CONSTEXPR) +# define CRYPTOPP_STATIC_CONSTEXPR static constexpr +# define CRYPTOPP_STATIC_CONST_OR_CONSTEXPR static constexpr +# define CRYPTOPP_CONST_OR_CONSTEXPR constexpr +# define CRYPTOPP_CONSTEXPR constexpr +#else +# define CRYPTOPP_STATIC_CONSTEXPR static +# define CRYPTOPP_STATIC_CONST_OR_CONSTEXPR static const +# define CRYPTOPP_CONST_OR_CONSTEXPR const +# define CRYPTOPP_CONSTEXPR +#endif // CRYPTOPP_CXX11_CONSTEXPR + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +# define CRYPTOPP_CONSTANT(x) static const int x +#elif defined(CRYPTOPP_CXX11_STRONG_ENUM) +# define CRYPTOPP_CONSTANT(x) enum : int { x } +#elif defined(CRYPTOPP_CXX11_CONSTEXPR) +# define CRYPTOPP_CONSTANT(x) constexpr static int x +#else +# define CRYPTOPP_CONSTANT(x) static const int x +#endif + +// Warnings +#ifdef CRYPTOPP_MSC_VERSION + // 4127: conditional expression is constant + // 4512: assignment operator not generated + // 4661: no suitable definition provided for explicit template instantiation request + // 4910: '__declspec(dllexport)' and 'extern' are incompatible on an explicit instantiation +# pragma warning(disable: 4127 4512 4661 4910) + // CRYPTOPP_MSC_VERSION 1920 is VS2019 +# if CRYPTOPP_MSC_VERSION >= 1920 + // 5054: operator '|': deprecated between enumerations of different types +# pragma warning(disable: 5054) +# endif + // Security related, possible defects + // http://blogs.msdn.com/b/vcblog/archive/2010/12/14/off-by-default-compiler-warnings-in-visual-c.aspx +# pragma warning(once: 4191 4242 4263 4264 4266 4302 4826 4905 4906 4928) +#endif + +#ifdef __BORLANDC__ +// 8037: non-const function called for const object. needed to work around BCB2006 bug +# pragma warn -8037 +#endif + +// [GCC Bug 53431] "C++ preprocessor ignores #pragma GCC diagnostic". Clang honors it. +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic ignored "-Wunknown-pragmas" +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#endif // CRYPTOPP_CONFIG_MISC_H diff --git a/third_party/cryptoppwin/include/cryptopp/config_ns.h b/third_party/cryptoppwin/include/cryptopp/config_ns.h new file mode 100644 index 00000000..256b7916 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/config_ns.h @@ -0,0 +1,76 @@ +// config_ns.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_ns.h +/// \brief Library configuration file +/// \details config_ns.h provides defines for C++ and library +/// namespaces. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_ns.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_NAMESPACE_H +#define CRYPTOPP_CONFIG_NAMESPACE_H + +// namespace support is now required +#ifdef NO_NAMESPACE +# error namespace support is now required +#endif + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING + +/// \namespace CryptoPP +/// \brief Crypto++ library namespace +/// \details Nearly all classes are located in the CryptoPP namespace. Within +/// the namespace, there are four additional namespaces. +///
    +///
  • Name - namespace for names used with NameValuePairs and documented +/// in argnames.h +///
  • NaCl - namespace for NaCl test functions like crypto_box, +/// crypto_box_open, crypto_sign, and crypto_sign_open +///
  • Donna - namespace for curve25519 library operations. The name was +/// selected due to use of Langley and Moon's curve25519-donna. +///
  • Test - namespace for testing and benchmarks classes +///
  • Weak - namespace for weak and wounded algorithms, like ARC4, MD5 +/// and Pananma +///
+/// \since Crypto++ 3.0 +namespace CryptoPP { } + +// Bring in the symbols found in the weak namespace; and fold Weak1 into Weak +#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 +#define Weak1 Weak +// Avoid putting "CryptoPP::" in front of everything in Doxygen output +#define CryptoPP +#define NAMESPACE_BEGIN(x) +#define NAMESPACE_END +// Get Doxygen to generate better documentation for these typedefs +#define DOCUMENTED_TYPEDEF(x, y) class y : public x {} +// Make "protected" "private" so the functions and members are not documented +#define protected private + +#else +// Not Doxygen +#define NAMESPACE_BEGIN(x) namespace x { +#define NAMESPACE_END } +#define DOCUMENTED_TYPEDEF(x, y) typedef x y + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +#define ANONYMOUS_NAMESPACE_BEGIN namespace { +#define ANONYMOUS_NAMESPACE_END } +#define USING_NAMESPACE(x) using namespace x; +#define DOCUMENTED_NAMESPACE_BEGIN(x) namespace x { +#define DOCUMENTED_NAMESPACE_END } + +#endif // CRYPTOPP_CONFIG_NAMESPACE_H diff --git a/third_party/cryptoppwin/include/cryptopp/config_os.h b/third_party/cryptoppwin/include/cryptopp/config_os.h new file mode 100644 index 00000000..1a636c34 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/config_os.h @@ -0,0 +1,168 @@ +// config_os.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_os.h +/// \brief Library configuration file +/// \details config_os.h provides defines for platforms and operating +/// systems. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_os.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_OS_H +#define CRYPTOPP_CONFIG_OS_H + +#include "config_ver.h" + +// It is OK to remove the hard stop below, but you are on your own. +// After building the library be sure to run self tests described +// https://www.cryptopp.com/wiki/Release_Process#Self_Tests +// The problems with Clang pretending to be other compilers is +// discussed at http://github.com/weidai11/cryptopp/issues/147. +#if (defined(_MSC_VER) && defined(__clang__)) +//# error: "Unsupported configuration" +#endif + +// Windows platform +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) +#define CRYPTOPP_WIN32_AVAILABLE +#endif + +// Unix and Linux platforms +#if defined(__unix__) || defined(__MACH__) || defined(__NetBSD__) || defined(__sun) +#define CRYPTOPP_UNIX_AVAILABLE +#endif + +// BSD platforms +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +#define CRYPTOPP_BSD_AVAILABLE +#endif + +// Microsoft compilers +#if defined(CRYPTOPP_MSC_VERSION) || defined(__fastcall) + #define CRYPTOPP_FASTCALL __fastcall +#else + #define CRYPTOPP_FASTCALL +#endif + +// Microsoft compilers +#if defined(CRYPTOPP_MSC_VERSION) + #define CRYPTOPP_NO_VTABLE __declspec(novtable) +#else + #define CRYPTOPP_NO_VTABLE +#endif + +// Define this if you want to disable all OS-dependent features, +// such as sockets and OS-provided random number generators +// #define NO_OS_DEPENDENCE + +// Define this to use features provided by Microsoft's CryptoAPI. +// Currently the only feature used is Windows random number generation. +// This macro will be ignored if NO_OS_DEPENDENCE is defined. +// #define USE_MS_CRYPTOAPI + +// Define this to use features provided by Microsoft's CryptoNG API. +// CryptoNG API is available in Vista and above and its cross platform, +// including desktop apps and store apps. Currently the only feature +// used is Windows random number generation. +// This macro will be ignored if NO_OS_DEPENDENCE is defined. +// #define USE_MS_CNGAPI + +// If the user did not make a choice, then select CryptoNG if +// targeting Windows 8 or above. +#if !defined(USE_MS_CRYPTOAPI) && !defined(USE_MS_CNGAPI) +# if !defined(_USING_V110_SDK71_) && ((WINVER >= 0x0602 /*_WIN32_WINNT_WIN8*/) || \ + (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)) +# define USE_MS_CNGAPI +# else +# define USE_MS_CRYPTOAPI +# endif +#endif + +// Begin OS features, like init priorities and random numbers +#ifndef NO_OS_DEPENDENCE + +// CRYPTOPP_INIT_PRIORITY attempts to manage initialization of C++ static objects. +// Under GCC, the library uses init_priority attribute in the range +// [CRYPTOPP_INIT_PRIORITY, CRYPTOPP_INIT_PRIORITY+100]. Under Windows, +// CRYPTOPP_INIT_PRIORITY enlists "#pragma init_seg(lib)". The platforms +// with gaps are Apple and Sun because they require linker scripts. Apple and +// Sun will use the library's Singletons to initialize and acquire resources. +// Also see http://cryptopp.com/wiki/Static_Initialization_Order_Fiasco +#ifndef CRYPTOPP_INIT_PRIORITY +# define CRYPTOPP_INIT_PRIORITY 250 +#endif + +// CRYPTOPP_USER_PRIORITY is for other libraries and user code that is using Crypto++ +// and managing C++ static object creation. It is guaranteed not to conflict with +// values used by (or would be used by) the Crypto++ library. +#ifndef CRYPTOPP_USER_PRIORITY +# define CRYPTOPP_USER_PRIORITY (CRYPTOPP_INIT_PRIORITY+101) +#endif + +// Most platforms allow us to specify when to create C++ objects. Apple and Sun do not. +#if (CRYPTOPP_INIT_PRIORITY > 0) && !(defined(NO_OS_DEPENDENCE) || defined(__APPLE__) || defined(__sun__)) +# if (CRYPTOPP_GCC_VERSION >= 30000) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || (_INTEL_COMPILER >= 800) +# define HAVE_GCC_INIT_PRIORITY 1 +# elif (CRYPTOPP_MSC_VERSION >= 1310) +# define HAVE_MSC_INIT_PRIORITY 1 +# elif defined(__xlc__) || defined(__xlC__) || defined(__ibmxl__) +# define HAVE_XLC_INIT_PRIORITY 1 +# endif +#endif // CRYPTOPP_INIT_PRIORITY, NO_OS_DEPENDENCE, Apple, Sun + +#if defined(CRYPTOPP_WIN32_AVAILABLE) || defined(CRYPTOPP_UNIX_AVAILABLE) +# define HIGHRES_TIMER_AVAILABLE +#endif + +#ifdef CRYPTOPP_WIN32_AVAILABLE +# if !defined(WINAPI_FAMILY) +# define THREAD_TIMER_AVAILABLE +# elif defined(WINAPI_FAMILY) +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) +# define THREAD_TIMER_AVAILABLE +# endif +# endif +#endif + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +# define NONBLOCKING_RNG_AVAILABLE +# define BLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +#endif + +// Cygwin/Newlib requires _XOPEN_SOURCE=600 +#if defined(CRYPTOPP_UNIX_AVAILABLE) +# define UNIX_SIGNALS_AVAILABLE 1 +#endif + +#ifdef CRYPTOPP_WIN32_AVAILABLE +# if !defined(WINAPI_FAMILY) +# define NONBLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +# elif defined(WINAPI_FAMILY) +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) +# define NONBLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +# elif !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)) +# if ((WINVER >= 0x0A00 /*_WIN32_WINNT_WIN10*/) || (_WIN32_WINNT >= 0x0A00 /*_WIN32_WINNT_WIN10*/)) +# define NONBLOCKING_RNG_AVAILABLE +# define OS_RNG_AVAILABLE +# endif +# endif +# endif +#endif + +#endif // NO_OS_DEPENDENCE + +#endif // CRYPTOPP_CONFIG_OS_H diff --git a/third_party/cryptoppwin/include/cryptopp/config_ver.h b/third_party/cryptoppwin/include/cryptopp/config_ver.h new file mode 100644 index 00000000..c7e457c2 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/config_ver.h @@ -0,0 +1,98 @@ +// config_ver.h - written and placed in public domain by Jeffrey Walton +// the bits that make up this source file are from the +// library's monolithic config.h. + +/// \file config_ver.h +/// \brief Library configuration file +/// \details config_ver.h provides defines for library and compiler +/// versions. +/// \details config.h was split into components in May 2019 to better +/// integrate with Autoconf and its feature tests. The splitting occurred so +/// users could continue to include config.h while allowing Autoconf +/// to write new config_asm.h and new config_cxx.h using +/// its feature tests. +/// \note You should include config.h rather than config_ver.h +/// directly. +/// \sa Issue 835, +/// Make config.h more autoconf friendly, +/// Configure.sh script +/// on the Crypto++ wiki +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_CONFIG_VERSION_H +#define CRYPTOPP_CONFIG_VERSION_H + +/// \brief Library major version +/// \details CRYPTOPP_MAJOR reflects the major version of the library the +/// headers came from. It is not necessarily the version of the library built +/// as a shared object if versions are inadvertently mixed and matched. +/// \sa CRYPTOPP_VERSION, LibraryVersion(), HeaderVersion() +/// \since Crypto++ 8.2 +#define CRYPTOPP_MAJOR 8 +/// \brief Library minor version +/// \details CRYPTOPP_MINOR reflects the minor version of the library the +/// headers came from. It is not necessarily the version of the library built +/// as a shared object if versions are inadvertently mixed and matched. +/// \sa CRYPTOPP_VERSION, LibraryVersion(), HeaderVersion() +/// \since Crypto++ 8.2 +#define CRYPTOPP_MINOR 9 +/// \brief Library revision number +/// \details CRYPTOPP_REVISION reflects the revision number of the library the +/// headers came from. It is not necessarily the revision of the library built +/// as a shared object if versions are inadvertently mixed and matched. +/// \sa CRYPTOPP_VERSION, LibraryVersion(), HeaderVersion() +/// \since Crypto++ 8.2 +#define CRYPTOPP_REVISION 0 + +/// \brief Full library version +/// \details CRYPTOPP_VERSION reflects the version of the library the headers +/// came from. It is not necessarily the version of the library built as a +/// shared object if versions are inadvertently mixed and matched. +/// \sa CRYPTOPP_MAJOR, CRYPTOPP_MINOR, CRYPTOPP_REVISION, LibraryVersion(), HeaderVersion() +/// \since Crypto++ 5.6 +#define CRYPTOPP_VERSION 890 + +// Compiler version macros + +// Apple and LLVM Clang versions. Apple Clang version 7.0 roughly equals +// LLVM Clang version 3.7. Also see https://gist.github.com/yamaya/2924292 +#if defined(__clang__) && defined(__apple_build_version__) +# define CRYPTOPP_APPLE_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#elif defined(__clang__) && defined(_MSC_VER) +# define CRYPTOPP_MSVC_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#elif defined(__clang__) +# define CRYPTOPP_LLVM_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#endif + +// Clang pretends to be other compilers. The compiler gets into +// code paths that it cannot compile. Unset Clang to save the grief. +// Also see http://github.com/weidai11/cryptopp/issues/147. + +#if defined(__GNUC__) && !defined(__clang__) +# undef CRYPTOPP_APPLE_CLANG_VERSION +# undef CRYPTOPP_LLVM_CLANG_VERSION +# define CRYPTOPP_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +#if defined(__xlc__) || defined(__xlC__) && !defined(__clang__) +# undef CRYPTOPP_LLVM_CLANG_VERSION +# define CRYPTOPP_XLC_VERSION ((__xlC__ / 256) * 10000 + (__xlC__ % 256) * 100) +#endif + +#if defined(__INTEL_COMPILER) && !defined(__clang__) +# undef CRYPTOPP_LLVM_CLANG_VERSION +# define CRYPTOPP_INTEL_VERSION (__INTEL_COMPILER) +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +# undef CRYPTOPP_LLVM_CLANG_VERSION +# define CRYPTOPP_MSC_VERSION (_MSC_VER) +#endif + +// To control include. May need a guard, like GCC 4.5 and above +// Also see https://stackoverflow.com/a/42493893 and https://github.com/weidai11/cryptopp/issues/1198 +#if defined(CRYPTOPP_GCC_VERSION) || defined(CRYPTOPP_APPLE_CLANG_VERSION) || defined(CRYPTOPP_LLVM_CLANG_VERSION) +# define CRYPTOPP_GCC_COMPATIBLE 1 +#endif + +#endif // CRYPTOPP_CONFIG_VERSION_H diff --git a/third_party/cryptoppwin/include/cryptopp/cpu.h b/third_party/cryptoppwin/include/cryptopp/cpu.h new file mode 100644 index 00000000..29ab6d42 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/cpu.h @@ -0,0 +1,1089 @@ +// cpu.h - originally written and placed in the public domain by Wei Dai +// updated for ARM and PowerPC by Jeffrey Walton. +// updated to split CPU_Query() and CPU_Probe() by Jeffrey Walton. + +/// \file cpu.h +/// \brief Functions for CPU features and intrinsics +/// \details The CPU functions are used in IA-32, ARM and PowerPC code paths. The +/// functions provide cpu specific feature testing on IA-32, ARM and PowerPC machines. +/// \details Feature detection uses CPUID on IA-32, like Intel and AMD. On other platforms +/// a two-part strategy is used. First, the library attempts to *Query* the OS for a feature, +/// like using Linux getauxval() or android_getCpuFeatures(). If that fails, then *Probe* +/// the cpu executing an instruction and an observe a SIGILL if unsupported. The general +/// pattern used by the library is: +///
+///    g_hasCRC32 = CPU_QueryCRC32() || CPU_ProbeCRC32();
+///    g_hasPMULL = CPU_QueryPMULL() || CPU_ProbePMULL();
+///    g_hasAES  = CPU_QueryAES() || CPU_ProbeAES();
+/// 
+/// \details Generally speaking, CPU_Query() is in the source file cpu.cpp because it +/// does not require special architectural flags. CPU_Probe() is in a source file that receives +/// architectural flags, like sse_simd.cpp, neon_simd.cpp and +/// ppc_simd.cpp. For example, compiling neon_simd.cpp on an ARM64 machine will +/// have -march=armv8-a applied during a compile to make the instruction set architecture +/// (ISA) available. +/// \details The cpu probes are expensive when compared to a standard OS feature query. The library +/// also avoids probes on Apple platforms because Apple's signal handling for SIGILLs appears to +/// corrupt memory. CPU_Probe() will unconditionally return false for Apple platforms. OpenSSL +/// experienced the same problem and moved away from SIGILL probes on Apple. + +#ifndef CRYPTOPP_CPU_H +#define CRYPTOPP_CPU_H + +#include "config.h" + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +// Applies to both X86/X32/X64 and ARM32/ARM64 +#if defined(CRYPTOPP_LLVM_CLANG_VERSION) || defined(CRYPTOPP_APPLE_CLANG_VERSION) + #define NEW_LINE "\n" + #define INTEL_PREFIX ".intel_syntax;" + #define INTEL_NOPREFIX ".intel_syntax;" + #define ATT_PREFIX ".att_syntax;" + #define ATT_NOPREFIX ".att_syntax;" +#elif defined(CRYPTOPP_GCC_VERSION) + #define NEW_LINE + #define INTEL_PREFIX ".intel_syntax prefix;" + #define INTEL_NOPREFIX ".intel_syntax noprefix;" + #define ATT_PREFIX ".att_syntax prefix;" + #define ATT_NOPREFIX ".att_syntax noprefix;" +#else + #define NEW_LINE + #define INTEL_PREFIX + #define INTEL_NOPREFIX + #define ATT_PREFIX + #define ATT_NOPREFIX +#endif + +// Thanks to v1ne at https://github.com/weidai11/cryptopp/pull/1133 +#define PERCENT_PASTE(x) "%" #x +#define PERCENT_REG(x) PERCENT_PASTE(x) + +#ifdef CRYPTOPP_GENERATE_X64_MASM + +#define CRYPTOPP_X86_ASM_AVAILABLE +#define CRYPTOPP_BOOL_X64 1 +#define CRYPTOPP_SSE2_ASM_AVAILABLE 1 +#define NAMESPACE_END + +#else + +NAMESPACE_BEGIN(CryptoPP) + +// ***************************** IA-32 ***************************** // + +#if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || CRYPTOPP_DOXYGEN_PROCESSING + +#define CRYPTOPP_CPUID_AVAILABLE 1 + +// Hide from Doxygen +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +// These should not be used directly +extern CRYPTOPP_DLL bool g_x86DetectionDone; +extern CRYPTOPP_DLL bool g_hasSSE2; +extern CRYPTOPP_DLL bool g_hasSSSE3; +extern CRYPTOPP_DLL bool g_hasSSE41; +extern CRYPTOPP_DLL bool g_hasSSE42; +extern CRYPTOPP_DLL bool g_hasMOVBE; +extern CRYPTOPP_DLL bool g_hasAESNI; +extern CRYPTOPP_DLL bool g_hasCLMUL; +extern CRYPTOPP_DLL bool g_hasAVX; +extern CRYPTOPP_DLL bool g_hasAVX2; +extern CRYPTOPP_DLL bool g_hasSHA; +extern CRYPTOPP_DLL bool g_hasADX; +extern CRYPTOPP_DLL bool g_isP4; +extern CRYPTOPP_DLL bool g_hasRDRAND; +extern CRYPTOPP_DLL bool g_hasRDSEED; +extern CRYPTOPP_DLL bool g_hasPadlockRNG; +extern CRYPTOPP_DLL bool g_hasPadlockACE; +extern CRYPTOPP_DLL bool g_hasPadlockACE2; +extern CRYPTOPP_DLL bool g_hasPadlockPHE; +extern CRYPTOPP_DLL bool g_hasPadlockPMM; +extern CRYPTOPP_DLL word32 g_cacheLineSize; + +CRYPTOPP_DLL void CRYPTOPP_API DetectX86Features(); +CRYPTOPP_DLL bool CRYPTOPP_API CpuId(word32 func, word32 subfunc, word32 output[4]); +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \name IA-32 CPU FEATURES +//@{ + +/// \brief Determine SSE2 availability +/// \return true if SSE2 is determined to be available, false otherwise +/// \details MMX, SSE and SSE2 are core processor features for x86_64, and +/// the function return value is based on OSXSAVE. On i386 both +/// SSE2 and OSXSAVE are used for the return value. +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSSE2() +{ +#if (CRYPTOPP_SSE2_ASM_AVAILABLE || CRYPTOPP_SSE2_INTRIN_AVAILABLE) + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSSE2; +#else + return false; +#endif +} + +/// \brief Determine SSSE3 availability +/// \return true if SSSE3 is determined to be available, false otherwise +/// \details HasSSSE3() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSSSE3() +{ +#if CRYPTOPP_SSSE3_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSSSE3; +#else + return false; +#endif +} + +/// \brief Determine SSE4.1 availability +/// \return true if SSE4.1 is determined to be available, false otherwise +/// \details HasSSE41() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSSE41() +{ +#if CRYPTOPP_SSE41_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSSE41; +#else + return false; +#endif +} + +/// \brief Determine SSE4.2 availability +/// \return true if SSE4.2 is determined to be available, false otherwise +/// \details HasSSE42() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSSE42() +{ +#if CRYPTOPP_SSE42_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSSE42; +#else + return false; +#endif +} + +/// \brief Determine MOVBE availability +/// \return true if MOVBE is determined to be available, false otherwise +/// \details HasMOVBE() is a runtime check performed using CPUID +/// \since Crypto++ 8.3 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasMOVBE() +{ +#if CRYPTOPP_SSE42_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasMOVBE; +#else + return false; +#endif +} + +/// \brief Determine AES-NI availability +/// \return true if AES-NI is determined to be available, false otherwise +/// \details HasAESNI() is a runtime check performed using CPUID +/// \since Crypto++ 5.6.1 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasAESNI() +{ +#if CRYPTOPP_AESNI_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasAESNI; +#else + return false; +#endif +} + +/// \brief Determine Carryless Multiply availability +/// \return true if pclmulqdq is determined to be available, false otherwise +/// \details HasCLMUL() is a runtime check performed using CPUID +/// \since Crypto++ 5.6.1 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasCLMUL() +{ +#if CRYPTOPP_CLMUL_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasCLMUL; +#else + return false; +#endif +} + +/// \brief Determine SHA availability +/// \return true if SHA is determined to be available, false otherwise +/// \details HasSHA() is a runtime check performed using CPUID +/// \since Crypto++ 6.0 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasSHA() +{ +#if CRYPTOPP_SHANI_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasSHA; +#else + return false; +#endif +} + +/// \brief Determine ADX availability +/// \return true if ADX is determined to be available, false otherwise +/// \details HasADX() is a runtime check performed using CPUID +/// \since Crypto++ 7.0 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasADX() +{ +#if CRYPTOPP_ADX_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasADX; +#else + return false; +#endif +} + +/// \brief Determine AVX availability +/// \return true if AVX is determined to be available, false otherwise +/// \details HasAVX() is a runtime check performed using CPUID +/// \since Crypto++ 8.0 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasAVX() +{ +#if CRYPTOPP_AVX_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasAVX; +#else + return false; +#endif +} + +/// \brief Determine AVX2 availability +/// \return true if AVX2 is determined to be available, false otherwise +/// \details HasAVX2() is a runtime check performed using CPUID +/// \since Crypto++ 8.0 +/// \note This function is only available on Intel IA-32 platforms +inline bool HasAVX2() +{ +#if CRYPTOPP_AVX2_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasAVX2; +#else + return false; +#endif +} + +/// \brief Determine RDRAND availability +/// \return true if RDRAND is determined to be available, false otherwise +/// \details HasRDRAND() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasRDRAND() +{ +#if CRYPTOPP_RDRAND_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasRDRAND; +#else + return false; +#endif +} + +/// \brief Determine RDSEED availability +/// \return true if RDSEED is determined to be available, false otherwise +/// \details HasRDSEED() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasRDSEED() +{ +#if CRYPTOPP_RDSEED_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasRDSEED; +#else + return false; +#endif +} + +/// \brief Determine Padlock RNG availability +/// \return true if VIA Padlock RNG is determined to be available, false otherwise +/// \details HasPadlockRNG() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockRNG() +{ +#if CRYPTOPP_PADLOCK_RNG_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockRNG; +#else + return false; +#endif +} + +/// \brief Determine Padlock ACE availability +/// \return true if VIA Padlock ACE is determined to be available, false otherwise +/// \details HasPadlockACE() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockACE() +{ +#if CRYPTOPP_PADLOCK_ACE_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockACE; +#else + return false; +#endif +} + +/// \brief Determine Padlock ACE2 availability +/// \return true if VIA Padlock ACE2 is determined to be available, false otherwise +/// \details HasPadlockACE2() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockACE2() +{ +#if CRYPTOPP_PADLOCK_ACE2_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockACE2; +#else + return false; +#endif +} + +/// \brief Determine Padlock PHE availability +/// \return true if VIA Padlock PHE is determined to be available, false otherwise +/// \details HasPadlockPHE() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockPHE() +{ +#if CRYPTOPP_PADLOCK_PHE_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockPHE; +#else + return false; +#endif +} + +/// \brief Determine Padlock PMM availability +/// \return true if VIA Padlock PMM is determined to be available, false otherwise +/// \details HasPadlockPMM() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool HasPadlockPMM() +{ +#if CRYPTOPP_PADLOCK_PMM_AVAILABLE + if (!g_x86DetectionDone) + DetectX86Features(); + return g_hasPadlockPMM; +#else + return false; +#endif +} + +/// \brief Determine if the CPU is an Intel P4 +/// \return true if the CPU is a P4, false otherwise +/// \details IsP4() is a runtime check performed using CPUID +/// \note This function is only available on Intel IA-32 platforms +inline bool IsP4() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_isP4; +} + +/// \brief Provides the cache line size +/// \return lower bound on the size of a cache line in bytes, if available +/// \details GetCacheLineSize() returns the lower bound on the size of a cache line, if it +/// is available. If the value is not available at runtime, then 32 is returned for a 32-bit +/// processor and 64 is returned for a 64-bit processor. +/// \details x86/x32/x64 uses CPUID to determine the value and it is usually accurate. PowerPC +/// and AIX also makes the value available to user space and it is also usually accurate. The +/// ARM processor equivalent is a privileged instruction, so a compile time value is returned. +inline int GetCacheLineSize() +{ + if (!g_x86DetectionDone) + DetectX86Features(); + return g_cacheLineSize; +} +//@} + +#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + +// ***************************** ARM-32, Aarch32 and Aarch64 ***************************** // + +#if CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8 || CRYPTOPP_DOXYGEN_PROCESSING + +// Hide from Doxygen +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +extern bool g_ArmDetectionDone; +extern bool g_hasARMv7; +extern bool g_hasNEON; +extern bool g_hasPMULL; +extern bool g_hasCRC32; +extern bool g_hasAES; +extern bool g_hasSHA1; +extern bool g_hasSHA2; +extern bool g_hasSHA512; +extern bool g_hasSHA3; +extern bool g_hasSM3; +extern bool g_hasSM4; +void CRYPTOPP_API DetectArmFeatures(); +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \name ARM A-32, Aarch32 and AArch64 CPU FEATURES +//@{ + +/// \brief Determine if an ARM processor is ARMv7 or above +/// \return true if the hardware is ARMv7 or above, false otherwise. +/// \details Some AES code requires ARMv7 or above +/// \since Crypto++ 8.0 +/// \note This function is only available on ARM-32, Aarch32 and Aarch64 platforms +inline bool HasARMv7() +{ + // ASIMD is a core feature on Aarch32 and Aarch64 like SSE2 is a core feature on x86_64 +#if defined(__aarch32__) || defined(__aarch64__) + return true; +#else + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasARMv7; +#endif +} + +/// \brief Determine if an ARM processor has Advanced SIMD available +/// \return true if the hardware is capable of Advanced SIMD at runtime, false otherwise. +/// \details Advanced SIMD instructions are available under most ARMv7, Aarch32 and Aarch64. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mfpu=neon (32-bit) or -march=armv8-a +/// (64-bit). Also see ARM's __ARM_NEON preprocessor macro. +/// \since Crypto++ 5.6.4 +/// \note This function is only available on ARM-32, Aarch32 and Aarch64 platforms +inline bool HasNEON() +{ + // ASIMD is a core feature on Aarch32 and Aarch64 like SSE2 is a core feature on x86_64 +#if defined(CRYPTOPP_ARM_ASIMD_AVAILABLE) + return true; +#elif defined(CRYPTOPP_ARM_NEON_AVAILABLE) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasNEON; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has CRC32 available +/// \return true if the hardware is capable of CRC32 at runtime, false otherwise. +/// \details CRC32 instructions provide access to the processor's CRC-32 and CRC-32C +/// instructions. They are provided by ARM C Language Extensions 2.0 (ACLE 2.0) and +/// available under Aarch32 and Aarch64. +/// \details Runtime support requires compile time support. When compiling with GCC, +/// you may need to compile with -march=armv8-a+crc; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRC32 preprocessor macro. +/// \since Crypto++ 5.6.4 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasCRC32() +{ +#if defined(CRYPTOPP_ARM_CRC32_AVAILABLE) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasCRC32; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has AES available +/// \return true if the hardware is capable of AES at runtime, false otherwise. +/// \details AES is part of the optional Crypto extensions on Aarch32 and Aarch64. They are +/// accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -march=armv8-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 5.6.4 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasAES() +{ +#if defined(CRYPTOPP_ARM_AES_AVAILABLE) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasAES; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor provides Polynomial Multiplication +/// \return true if the hardware is capable of polynomial multiplications at runtime, +/// false otherwise. +/// \details The multiplication instructions are available under Aarch32 and Aarch64. +/// \details Runtime support requires compile time support. When compiling with GCC, +/// you may need to compile with -march=armv8-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 5.6.4 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasPMULL() +{ +#if defined(CRYPTOPP_ARM_PMULL_AVAILABLE) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasPMULL; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SHA1 available +/// \return true if the hardware is capable of SHA1 at runtime, false otherwise. +/// \details SHA1 is part of the optional Crypto extensions on Aarch32 and Aarch64. They are +/// accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -march=armv8-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 5.6.4 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasSHA1() +{ +#if defined(CRYPTOPP_ARM_SHA1_AVAILABLE) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSHA1; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SHA256 available +/// \return true if the hardware is capable of SHA256 at runtime, false otherwise. +/// \details SHA256 is part of the optional Crypto extensions on Aarch32 and Aarch64. They are +/// accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -march=armv8-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 5.6.4 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasSHA2() +{ +#if defined(CRYPTOPP_ARM_SHA2_AVAILABLE) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSHA2; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SHA3 available +/// \return true if the hardware is capable of SHA3 at runtime, false otherwise. +/// \details SHA3 is part of the ARMv8.2 Crypto extensions on Aarch32 and Aarch64. They +/// are accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you +/// may need to compile with -march=armv8.2-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 8.0 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasSHA3() +{ +#if defined(CRYPTOPP_ARM_SHA3_AVAILABLE) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSHA3; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SHA512 available +/// \return true if the hardware is capable of SHA512 at runtime, false otherwise. +/// \details SHA512 is part of the ARMv8.2 Crypto extensions on Aarch32 and Aarch64. They +/// are accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you +/// may need to compile with -march=armv8.2-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 8.0 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasSHA512() +{ +#if defined(CRYPTOPP_ARM_SHA512_AVAILABLE) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSHA512; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SM3 available +/// \return true if the hardware is capable of SM3 at runtime, false otherwise. +/// \details SM3 is part of the ARMv8.2 Crypto extensions on Aarch32 and Aarch64. They +/// are accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you +/// may need to compile with -march=armv8.2-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 8.0 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasSM3() +{ +#if defined(CRYPTOPP_ARM_SM3_AVAILABLE) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSM3; +#else + return false; +#endif +} + +/// \brief Determine if an ARM processor has SM4 available +/// \return true if the hardware is capable of SM4 at runtime, false otherwise. +/// \details SM4 is part of the ARMv8.2 Crypto extensions on Aarch32 and Aarch64. They +/// are accessed using ARM C Language Extensions 2.0 (ACLE 2.0). +/// \details Runtime support requires compile time support. When compiling with GCC, you +/// may need to compile with -march=armv8.2-a+crypto; while Apple requires +/// -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro. +/// \since Crypto++ 8.0 +/// \note This function is only available on Aarch32 and Aarch64 platforms +inline bool HasSM4() +{ +#if defined(CRYPTOPP_ARM_SM4_AVAILABLE) + if (!g_ArmDetectionDone) + DetectArmFeatures(); + return g_hasSM4; +#else + return false; +#endif +} + +//@} + +#endif // CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8 + +// ***************************** PowerPC ***************************** // + +#if CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 || CRYPTOPP_DOXYGEN_PROCESSING + +// Hide from Doxygen +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +extern bool g_PowerPcDetectionDone; +extern bool g_hasAltivec; +extern bool g_hasPower7; +extern bool g_hasPower8; +extern bool g_hasPower9; +extern bool g_hasAES; +extern bool g_hasPMULL; +extern bool g_hasSHA256; +extern bool g_hasSHA512; +extern bool g_hasDARN; +extern word32 g_cacheLineSize; +void CRYPTOPP_API DetectPowerPcFeatures(); +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \name POWERPC CPU FEATURES +//@{ + +/// \brief Determine if a PowerPC processor has Altivec available +/// \return true if the hardware is capable of Altivec at runtime, false otherwise. +/// \details Altivec instructions are available on modern PowerPCs. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power4; while IBM XL C/C++ compilers require +/// -qarch=pwr6 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasAltivec() +{ +#if CRYPTOPP_ALTIVEC_AVAILABLE + if (!g_PowerPcDetectionDone) + DetectPowerPcFeatures(); + return g_hasAltivec; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has Power7 available +/// \return true if the hardware is capable of Power7 at runtime, false otherwise. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power7; while IBM XL C/C++ compilers require +/// -qarch=pwr7 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasPower7() +{ +#if CRYPTOPP_POWER7_AVAILABLE + if (!g_PowerPcDetectionDone) + DetectPowerPcFeatures(); + return g_hasPower7; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has Power8 available +/// \return true if the hardware is capable of Power8 at runtime, false otherwise. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasPower8() +{ +#if CRYPTOPP_POWER8_AVAILABLE + if (!g_PowerPcDetectionDone) + DetectPowerPcFeatures(); + return g_hasPower8; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has Power9 available +/// \return true if the hardware is capable of Power9 at runtime, false otherwise. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power9; while IBM XL C/C++ compilers require +/// -qarch=pwr9 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasPower9() +{ +#if CRYPTOPP_POWER9_AVAILABLE + if (!g_PowerPcDetectionDone) + DetectPowerPcFeatures(); + return g_hasPower9; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has AES available +/// \return true if the hardware is capable of AES at runtime, false otherwise. +/// \details AES is part of the in-crypto extensions on Power8 and Power9. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasAES() +{ +#if CRYPTOPP_POWER8_AES_AVAILABLE + if (!g_PowerPcDetectionDone) + DetectPowerPcFeatures(); + return g_hasAES; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has Polynomial Multiply available +/// \return true if the hardware is capable of PMULL at runtime, false otherwise. +/// \details PMULL is part of the in-crypto extensions on Power8 and Power9. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasPMULL() +{ +#if CRYPTOPP_POWER8_VMULL_AVAILABLE + if (!g_PowerPcDetectionDone) + DetectPowerPcFeatures(); + return g_hasPMULL; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has SHA256 available +/// \return true if the hardware is capable of SHA256 at runtime, false otherwise. +/// \details SHA is part of the in-crypto extensions on Power8 and Power9. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasSHA256() +{ +#if CRYPTOPP_POWER8_SHA_AVAILABLE + if (!g_PowerPcDetectionDone) + DetectPowerPcFeatures(); + return g_hasSHA256; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has SHA512 available +/// \return true if the hardware is capable of SHA512 at runtime, false otherwise. +/// \details SHA is part of the in-crypto extensions on Power8 and Power9. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power8; while IBM XL C/C++ compilers require +/// -qarch=pwr8 -qaltivec. Also see PowerPC's __CRYPTO preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasSHA512() +{ +#if CRYPTOPP_POWER8_SHA_AVAILABLE + if (!g_PowerPcDetectionDone) + DetectPowerPcFeatures(); + return g_hasSHA512; +#else + return false; +#endif +} + +/// \brief Determine if a PowerPC processor has DARN available +/// \return true if the hardware is capable of DARN at runtime, false otherwise. +/// \details Runtime support requires compile time support. When compiling with GCC, you may +/// need to compile with -mcpu=power9; while IBM XL C/C++ compilers require +/// -qarch=pwr9 -qaltivec. Also see PowerPC's _ALTIVEC_ preprocessor macro. +/// \note This function is only available on PowerPC and PowerPC-64 platforms +inline bool HasDARN() +{ +#if CRYPTOPP_POWER9_AVAILABLE + if (!g_PowerPcDetectionDone) + DetectPowerPcFeatures(); + // see comments in cpu.cpp +# if defined(__ibmxl__) && defined(__linux__) + return false; +# else + return g_hasDARN; +# endif +#else + return false; +#endif +} + +/// \brief Provides the cache line size +/// \return lower bound on the size of a cache line in bytes, if available +/// \details GetCacheLineSize() returns the lower bound on the size of a cache line, if it +/// is available. If the value is not available at runtime, then 32 is returned for a 32-bit +/// processor and 64 is returned for a 64-bit processor. +/// \details x86/x32/x64 uses CPUID to determine the value and it is usually accurate. PowerPC +/// and AIX also makes the value available to user space and it is also usually accurate. The +/// ARM processor equivalent is a privileged instruction, so a compile time value is returned. +inline int GetCacheLineSize() +{ + if (!g_PowerPcDetectionDone) + DetectPowerPcFeatures(); + return g_cacheLineSize; +} + +//@} + +#endif // CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 + +// ***************************** L1 cache line ***************************** // + +// Non-Intel systems +#if !(CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) +/// \brief Provides the cache line size +/// \return lower bound on the size of a cache line in bytes, if available +/// \details GetCacheLineSize() returns the lower bound on the size of a cache line, if it +/// is available. If the value is not available at runtime, then 32 is returned for a 32-bit +/// processor and 64 is returned for a 64-bit processor. +/// \details x86/x32/x64 uses CPUID to determine the value and it is usually accurate. PowerPC +/// and AIX also makes the value available to user space and it is also usually accurate. The +/// ARM processor equivalent is a privileged instruction, so a compile time value is returned. +inline int GetCacheLineSize() +{ + return CRYPTOPP_L1_CACHE_LINE_SIZE; +} +#endif // Non-Intel systems + +#endif // CRYPTOPP_GENERATE_X64_MASM + +// ***************************** Inline ASM Helper ***************************** // + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + +#if CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + +#ifdef CRYPTOPP_GENERATE_X64_MASM + #define AS1(x) x*newline* + #define AS2(x, y) x, y*newline* + #define AS3(x, y, z) x, y, z*newline* + #define ASS(x, y, a, b, c, d) x, y, a*64+b*16+c*4+d*newline* + #define ASL(x) label##x:*newline* + #define ASJ(x, y, z) x label##y*newline* + #define ASC(x, y) x label##y*newline* + #define AS_HEX(y) 0##y##h +#elif defined(CRYPTOPP_MSC_VERSION) || defined(__BORLANDC__) + #define AS1(x) __asm {x} + #define AS2(x, y) __asm {x, y} + #define AS3(x, y, z) __asm {x, y, z} + #define ASS(x, y, a, b, c, d) __asm {x, y, (a)*64+(b)*16+(c)*4+(d)} + #define ASL(x) __asm {label##x:} + #define ASJ(x, y, z) __asm {x label##y} + #define ASC(x, y) __asm {x label##y} + #define CRYPTOPP_NAKED __declspec(naked) + #define AS_HEX(y) 0x##y +#else + // define these in two steps to allow arguments to be expanded + #define GNU_AS1(x) #x ";" NEW_LINE + #define GNU_AS2(x, y) #x ", " #y ";" NEW_LINE + #define GNU_AS3(x, y, z) #x ", " #y ", " #z ";" NEW_LINE + #define GNU_ASL(x) "\n" #x ":" NEW_LINE +// clang 5.0.0 and apple clang 9.0.0 don't support numerical backward jumps +#if (CRYPTOPP_LLVM_CLANG_VERSION >= 50000) || (CRYPTOPP_APPLE_CLANG_VERSION >= 90000) + #define GNU_ASJ(x, y, z) ATT_PREFIX ";" NEW_LINE #x " " #y #z ";" NEW_LINE INTEL_PREFIX ";" NEW_LINE +#else + #define GNU_ASJ(x, y, z) #x " " #y #z ";" NEW_LINE +#endif + #define AS1(x) GNU_AS1(x) + #define AS2(x, y) GNU_AS2(x, y) + #define AS3(x, y, z) GNU_AS3(x, y, z) + #define ASS(x, y, a, b, c, d) #x ", " #y ", " #a "*64+" #b "*16+" #c "*4+" #d ";" + #define ASL(x) GNU_ASL(x) + #define ASJ(x, y, z) GNU_ASJ(x, y, z) + #define ASC(x, y) #x " " #y ";" + #define CRYPTOPP_NAKED + #define AS_HEX(y) 0x##y +#endif + +#define IF0(y) +#define IF1(y) y + +#ifdef CRYPTOPP_GENERATE_X64_MASM +#define ASM_MOD(x, y) ((x) MOD (y)) +#define XMMWORD_PTR XMMWORD PTR +#else +// GNU assembler doesn't seem to have mod operator +#define ASM_MOD(x, y) ((x)-((x)/(y))*(y)) +// GAS 2.15 doesn't support XMMWORD PTR. it seems necessary only for MASM +#define XMMWORD_PTR +#endif + +#if CRYPTOPP_BOOL_X86 + #define AS_REG_1 ecx + #define AS_REG_2 edx + #define AS_REG_3 esi + #define AS_REG_4 edi + #define AS_REG_5 eax + #define AS_REG_6 ebx + #define AS_REG_7 ebp + #define AS_REG_1d ecx + #define AS_REG_2d edx + #define AS_REG_3d esi + #define AS_REG_4d edi + #define AS_REG_5d eax + #define AS_REG_6d ebx + #define AS_REG_7d ebp + #define WORD_SZ 4 + #define WORD_REG(x) e##x + #define WORD_PTR DWORD PTR + #define AS_PUSH_IF86(x) AS1(push e##x) + #define AS_POP_IF86(x) AS1(pop e##x) + #define AS_JCXZ jecxz +#elif CRYPTOPP_BOOL_X32 + #define AS_REG_1 ecx + #define AS_REG_2 edx + #define AS_REG_3 r8d + #define AS_REG_4 r9d + #define AS_REG_5 eax + #define AS_REG_6 r10d + #define AS_REG_7 r11d + #define AS_REG_1d ecx + #define AS_REG_2d edx + #define AS_REG_3d r8d + #define AS_REG_4d r9d + #define AS_REG_5d eax + #define AS_REG_6d r10d + #define AS_REG_7d r11d + #define WORD_SZ 4 + #define WORD_REG(x) e##x + #define WORD_PTR DWORD PTR + #define AS_PUSH_IF86(x) AS1(push r##x) + #define AS_POP_IF86(x) AS1(pop r##x) + #define AS_JCXZ jecxz +#elif CRYPTOPP_BOOL_X64 + #ifdef CRYPTOPP_GENERATE_X64_MASM + #define AS_REG_1 rcx + #define AS_REG_2 rdx + #define AS_REG_3 r8 + #define AS_REG_4 r9 + #define AS_REG_5 rax + #define AS_REG_6 r10 + #define AS_REG_7 r11 + #define AS_REG_1d ecx + #define AS_REG_2d edx + #define AS_REG_3d r8d + #define AS_REG_4d r9d + #define AS_REG_5d eax + #define AS_REG_6d r10d + #define AS_REG_7d r11d + #else + #define AS_REG_1 rdi + #define AS_REG_2 rsi + #define AS_REG_3 rdx + #define AS_REG_4 rcx + #define AS_REG_5 r8 + #define AS_REG_6 r9 + #define AS_REG_7 r10 + #define AS_REG_1d edi + #define AS_REG_2d esi + #define AS_REG_3d edx + #define AS_REG_4d ecx + #define AS_REG_5d r8d + #define AS_REG_6d r9d + #define AS_REG_7d r10d + #endif + #define WORD_SZ 8 + #define WORD_REG(x) r##x + #define WORD_PTR QWORD PTR + #define AS_PUSH_IF86(x) + #define AS_POP_IF86(x) + #define AS_JCXZ jrcxz +#endif + +// helper macro for stream cipher output +#define AS_XMM_OUTPUT4(labelPrefix, inputPtr, outputPtr, x0, x1, x2, x3, t, p0, p1, p2, p3, increment)\ + AS2( test inputPtr, inputPtr)\ + ASC( jz, labelPrefix##3)\ + AS2( test inputPtr, 15)\ + ASC( jnz, labelPrefix##7)\ + AS2( pxor xmm##x0, [inputPtr+p0*16])\ + AS2( pxor xmm##x1, [inputPtr+p1*16])\ + AS2( pxor xmm##x2, [inputPtr+p2*16])\ + AS2( pxor xmm##x3, [inputPtr+p3*16])\ + AS2( add inputPtr, increment*16)\ + ASC( jmp, labelPrefix##3)\ + ASL(labelPrefix##7)\ + AS2( movdqu xmm##t, [inputPtr+p0*16])\ + AS2( pxor xmm##x0, xmm##t)\ + AS2( movdqu xmm##t, [inputPtr+p1*16])\ + AS2( pxor xmm##x1, xmm##t)\ + AS2( movdqu xmm##t, [inputPtr+p2*16])\ + AS2( pxor xmm##x2, xmm##t)\ + AS2( movdqu xmm##t, [inputPtr+p3*16])\ + AS2( pxor xmm##x3, xmm##t)\ + AS2( add inputPtr, increment*16)\ + ASL(labelPrefix##3)\ + AS2( test outputPtr, 15)\ + ASC( jnz, labelPrefix##8)\ + AS2( movdqa [outputPtr+p0*16], xmm##x0)\ + AS2( movdqa [outputPtr+p1*16], xmm##x1)\ + AS2( movdqa [outputPtr+p2*16], xmm##x2)\ + AS2( movdqa [outputPtr+p3*16], xmm##x3)\ + ASC( jmp, labelPrefix##9)\ + ASL(labelPrefix##8)\ + AS2( movdqu [outputPtr+p0*16], xmm##x0)\ + AS2( movdqu [outputPtr+p1*16], xmm##x1)\ + AS2( movdqu [outputPtr+p2*16], xmm##x2)\ + AS2( movdqu [outputPtr+p3*16], xmm##x3)\ + ASL(labelPrefix##9)\ + AS2( add outputPtr, increment*16) + +#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64 + +#endif // Not CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_END + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif // CRYPTOPP_CPU_H diff --git a/third_party/cryptoppwin/include/cryptopp/crc.h b/third_party/cryptoppwin/include/cryptopp/crc.h new file mode 100644 index 00000000..17e5977b --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/crc.h @@ -0,0 +1,90 @@ +// crc.h - originally written and placed in the public domain by Wei Dai + +/// \file crc.h +/// \brief Classes for CRC-32 and CRC-32C checksum algorithm + +#ifndef CRYPTOPP_CRC32_H +#define CRYPTOPP_CRC32_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +const word32 CRC32_NEGL = 0xffffffffL; + +#if (CRYPTOPP_LITTLE_ENDIAN) +#define CRC32_INDEX(c) (c & 0xff) +#define CRC32_SHIFTED(c) (c >> 8) +#else +#define CRC32_INDEX(c) (c >> 24) +#define CRC32_SHIFTED(c) (c << 8) +#endif + +/// \brief CRC-32 Checksum Calculation +/// \details Uses CRC polynomial 0xEDB88320 +class CRC32 : public HashTransformation +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = 4); + CRC32(); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *hash, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CRC32";} + std::string AlgorithmName() const {return StaticAlgorithmName();} + + /// \brief Updates a CRC with additional input + /// \param b the additional input as a byte + void UpdateByte(byte b) {m_crc = m_tab[CRC32_INDEX(m_crc) ^ b] ^ CRC32_SHIFTED(m_crc);} + + /// \brief Retrieves the i-th byte of the CRC + /// \param i the additional input as a byte + /// \return the byte at the i-th position + byte GetCrcByte(size_t i) const {return reinterpret_cast(&m_crc)[i];} + + std::string AlgorithmProvider() const; + +protected: + void Reset() {m_crc = CRC32_NEGL;} + +private: + static const word32 m_tab[256]; + word32 m_crc; +}; + +/// \brief CRC-32C Checksum Calculation +/// \details Uses CRC polynomial 0x82F63B78 +/// \since Crypto++ 5.6.4 +class CRC32C : public HashTransformation +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = 4); + CRC32C(); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *hash, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "CRC32C";} + std::string AlgorithmName() const {return StaticAlgorithmName();} + + /// \brief Updates a CRC with additional input + /// \param b the additional input as a byte + void UpdateByte(byte b) {m_crc = m_tab[CRC32_INDEX(m_crc) ^ b] ^ CRC32_SHIFTED(m_crc);} + + /// \brief Retrieves the i-th byte of the CRC + /// \param i the additional input as a byte + /// \return the byte at the i-th position + byte GetCrcByte(size_t i) const {return reinterpret_cast(&m_crc)[i];} + + std::string AlgorithmProvider() const; + +protected: + void Reset() {m_crc = CRC32_NEGL;} + +private: + static const word32 m_tab[256]; + word32 m_crc; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/cryptlib.h b/third_party/cryptoppwin/include/cryptopp/cryptlib.h new file mode 100644 index 00000000..4a5c83bf --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/cryptlib.h @@ -0,0 +1,3384 @@ +// cryptlib.h - originally written and placed in the public domain by Wei Dai + +/// \file cryptlib.h +/// \brief Abstract base classes that provide a uniform interface to this library. + +/*! \mainpage Crypto++ Library 8.9 API Reference +
+
Abstract Base Classes
+ cryptlib.h +
Authenticated Encryption Modes
+ CCM, EAX, \ref GCM "GCM (2K tables)", \ref GCM "GCM (64K tables)" +
Block Ciphers
+ \ref Rijndael "AES", ARIA, Weak::ARC4, Blowfish, BTEA, \ref CHAM128 "CHAM (64/128)", Camellia, + \ref CAST128 "CAST (128/256)", DES, \ref DES_EDE2 "2-key Triple-DES", \ref DES_EDE3 "3-key Triple-DES", + \ref DES_XEX3 "DESX", GOST, HIGHT, IDEA, LEA, \ref LR "Luby-Rackoff", \ref Kalyna128 "Kalyna (128/256/512)", + MARS, RC2, RC5, RC6, \ref SAFER_K "SAFER-K", \ref SAFER_SK "SAFER-SK", SEED, Serpent, + \ref SHACAL2 "SHACAL-2", SHARK, \ref SIMECK64 "SIMECK (32/64)" SKIPJACK, SM4, Square, TEA, + \ref ThreeWay "3-Way", \ref Threefish256 "Threefish (256/512/1024)", Twofish, XTEA +
Stream Ciphers
+ \ref ChaCha "ChaCha (8/12/20)", \ref HC128 "HC-128/256", \ref Panama "Panama-LE", \ref Panama "Panama-BE", + Rabbit, Salsa20, \ref SEAL "SEAL-LE", \ref SEAL "SEAL-BE", WAKE, XSalsa20 +
Hash Functions
+ BLAKE2s, BLAKE2b, \ref Keccak "Keccak (F1600)", SHA1, SHA224, SHA256, SHA384, SHA512, + \ref SHA3 "SHA-3", SM3, LSH (256/512), Tiger, RIPEMD160, RIPEMD256, SipHash, Whirlpool, + Weak::MD2, Weak::MD4, Weak::MD5 +
Non-Cryptographic Checksums
+ CRC32, CRC32C, Adler32 +
Message Authentication Codes
+ BLAKE2b, BLAKE2s, CBC_MAC, CMAC, DMAC, \ref GCM "GCM (GMAC)", HMAC, Poly1305, TTMAC, VMAC +
Random Number Generators
+ NullRNG, LC_RNG, RandomPool, BlockingRng, NonblockingRng, AutoSeededRandomPool, AutoSeededX917RNG, + NIST Hash_DRBG and HMAC_DRBG, \ref MersenneTwister "MersenneTwister (MT19937 and MT19937-AR)", + DARN, RDRAND, RDSEED +
Key Derivation and Password-based Cryptography
+ HKDF, \ref PKCS12_PBKDF "PBKDF (PKCS #12)", \ref PKCS5_PBKDF1 "PBKDF-1 (PKCS #5)", + \ref PKCS5_PBKDF2_HMAC "PBKDF-2/HMAC (PKCS #5)" +
Public Key Cryptosystems
+ DLIES, ECIES, LUCES, RSAES, RabinES, LUC_IES +
Public Key Signature Schemes
+ DSA, DSA2, \ref ed25519 "Ed25519", GDSA, ECDSA, NR, ECNR, LUCSS, RSASS, RSASS_ISO, + RabinSS, RWSS, ESIGN +
Key Agreement
+ DH, DH2, \ref x25519 "X25519", \ref MQV_Domain "MQV", \ref HMQV_Domain "HMQV", + \ref FHMQV_Domain "FHMQV", ECDH, x25519, ECMQV, ECHMQV, ECFHMQV, XTR_DH +
Algebraic Structures
+ Integer, PolynomialMod2, PolynomialOver, RingOfPolynomialsOver, + ModularArithmetic, MontgomeryRepresentation, GFP2_ONB, GF2NP, GF256, GF2_32, EC2N, ECP +
Secret Sharing and Information Dispersal
+ SecretSharing, SecretRecovery, InformationDispersal, InformationRecovery +
Compression
+ Deflator, Inflator, Gzip, Gunzip, ZlibCompressor, ZlibDecompressor +
Input Source Classes
+ StringSource, ArraySource, VectorSource, FileSource, RandomNumberSource +
Output Sink Classes
+ StringSinkTemplate, StringSink, VectorSink, ArraySink, FileSink, RandomNumberSink +
Filter Wrappers
+ StreamTransformationFilter, AuthenticatedEncryptionFilter, AuthenticatedDecryptionFilter, HashFilter, + HashVerificationFilter, SignerFilter, SignatureVerificationFilter +
Binary to Text Encoders and Decoders
+ HexEncoder, HexDecoder, Base64Encoder, Base64Decoder, Base64URLEncoder, Base64URLDecoder, Base32Encoder, + Base32Decoder +
Wrappers for OS features
+ Timer, ThreadUserTimer + +
+ + + +

This reference manual is a work in progress. Some classes lack detailed descriptions. +

Click here to download a zip archive containing this manual. +

Thanks to Ryan Phillips for providing the Doxygen configuration file +and getting us started on the manual. +*/ + +#ifndef CRYPTOPP_CRYPTLIB_H +#define CRYPTOPP_CRYPTLIB_H + +#include "config.h" +#include "stdcpp.h" +#include "trap.h" + +// C5264 new for VS2022/v17.4, MSC v17.3.4 +// https://github.com/weidai11/cryptopp/issues/1185 +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189 4505 4702) +# if (CRYPTOPP_MSC_VERSION >= 1933) +# pragma warning(disable: 5264) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// forward declarations +class Integer; +class RandomNumberGenerator; +class BufferedTransformation; + +/// \brief Specifies a direction for a cipher to operate +/// \sa BlockTransformation::IsForwardTransformation(), BlockTransformation::IsPermutation(), BlockTransformation::GetCipherDirection() +enum CipherDir { + /// \brief the cipher is performing encryption + ENCRYPTION, + /// \brief the cipher is performing decryption + DECRYPTION}; + +/// \brief Represents infinite time +CRYPTOPP_CONST_OR_CONSTEXPR unsigned long INFINITE_TIME = ULONG_MAX; + +// VC60 workaround: using enums as template parameters causes problems +/// \brief Converts an enumeration to a type suitable for use as a template parameter +template +struct EnumToType +{ + static ENUM_TYPE ToEnum() {return static_cast(VALUE);} +}; + +/// \brief Provides the byte ordering +/// \details Big-endian and little-endian modes are supported. Bi-endian and PDP-endian modes +/// are not supported. +enum ByteOrder { + /// \brief byte order is little-endian + LITTLE_ENDIAN_ORDER = 0, + /// \brief byte order is big-endian + BIG_ENDIAN_ORDER = 1}; + +/// \brief Provides a constant for LittleEndian +typedef EnumToType LittleEndian; +/// \brief Provides a constant for BigEndian +typedef EnumToType BigEndian; + +/// \brief Base class for all exceptions thrown by the library +/// \details All library exceptions directly or indirectly inherit from the Exception class. +/// The Exception class itself inherits from std::exception. The library does not use +/// std::runtime_error derived classes. +class CRYPTOPP_DLL Exception : public std::exception +{ +public: + /// \enum ErrorType + /// \brief Error types or categories + enum ErrorType { + /// \brief A method was called which was not implemented + NOT_IMPLEMENTED, + /// \brief An invalid argument was detected + INVALID_ARGUMENT, + /// \brief BufferedTransformation received a Flush(true) signal but can't flush buffers + CANNOT_FLUSH, + /// \brief Data integerity check, such as CRC or MAC, failed + DATA_INTEGRITY_CHECK_FAILED, + /// \brief Input data was received that did not conform to expected format + INVALID_DATA_FORMAT, + /// \brief Error reading from input device or writing to output device + IO_ERROR, + /// \brief Some other error occurred not belonging to other categories + OTHER_ERROR + }; + + virtual ~Exception() throw() {} + + /// \brief Construct a new Exception + explicit Exception(ErrorType errorType, const std::string &s) : m_errorType(errorType), m_what(s) {} + + /// \brief Retrieves a C-string describing the exception + const char *what() const throw() {return (m_what.c_str());} + /// \brief Retrieves a string describing the exception + const std::string &GetWhat() const {return m_what;} + /// \brief Sets the error string for the exception + void SetWhat(const std::string &s) {m_what = s;} + /// \brief Retrieves the error type for the exception + ErrorType GetErrorType() const {return m_errorType;} + /// \brief Sets the error type for the exceptions + void SetErrorType(ErrorType errorType) {m_errorType = errorType;} + +private: + ErrorType m_errorType; + std::string m_what; +}; + +/// \brief An invalid argument was detected +class CRYPTOPP_DLL InvalidArgument : public Exception +{ +public: + /// \brief Construct an InvalidArgument + /// \param s the message for the exception + /// \details The member function what() returns s. + explicit InvalidArgument(const std::string &s) : Exception(INVALID_ARGUMENT, s) {} +}; + +/// \brief Input data was received that did not conform to expected format +class CRYPTOPP_DLL InvalidDataFormat : public Exception +{ +public: + /// \brief Construct an InvalidDataFormat + /// \param s the message for the exception + /// \details The member function what() returns s. + explicit InvalidDataFormat(const std::string &s) : Exception(INVALID_DATA_FORMAT, s) {} +}; + +/// \brief A decryption filter encountered invalid ciphertext +class CRYPTOPP_DLL InvalidCiphertext : public InvalidDataFormat +{ +public: + /// \brief Construct an InvalidCiphertext + /// \param s the message for the exception + /// \details The member function what() returns s. + explicit InvalidCiphertext(const std::string &s) : InvalidDataFormat(s) {} +}; + +/// \brief A method was called which was not implemented +class CRYPTOPP_DLL NotImplemented : public Exception +{ +public: + /// \brief Construct an NotImplemented + /// \param s the message for the exception + /// \details The member function what() returns s. + explicit NotImplemented(const std::string &s) : Exception(NOT_IMPLEMENTED, s) {} +}; + +/// \brief Flush(true) was called but it can't completely flush its buffers +class CRYPTOPP_DLL CannotFlush : public Exception +{ +public: + /// \brief Construct an CannotFlush + /// \param s the message for the exception + /// \details The member function what() returns s. + explicit CannotFlush(const std::string &s) : Exception(CANNOT_FLUSH, s) {} +}; + +/// \brief The operating system reported an error +class CRYPTOPP_DLL OS_Error : public Exception +{ +public: + virtual ~OS_Error() throw() {} + + /// \brief Construct an OS_Error + /// \param errorType the error type + /// \param s the message for the exception + /// \param operation the operation for the exception + /// \param errorCode the error code + /// \details The member function what() returns s. + OS_Error(ErrorType errorType, const std::string &s, const std::string& operation, int errorCode) + : Exception(errorType, s), m_operation(operation), m_errorCode(errorCode) {} + + /// \brief Retrieve the operating system API that reported the error + const std::string & GetOperation() const {return m_operation;} + /// \brief Retrieve the error code returned by the operating system + int GetErrorCode() const {return m_errorCode;} + +protected: + std::string m_operation; + int m_errorCode; +}; + +/// \brief Returns a decoding results +struct CRYPTOPP_DLL DecodingResult +{ + /// \brief Constructs a DecodingResult + /// \details isValidCoding is initialized to false and messageLength is + /// initialized to 0. + explicit DecodingResult() : isValidCoding(false), messageLength(0) {} + /// \brief Constructs a DecodingResult + /// \param len the message length + /// \details isValidCoding is initialized to true. + explicit DecodingResult(size_t len) : isValidCoding(true), messageLength(len) {} + + /// \brief Compare two DecodingResult + /// \param rhs the other DecodingResult + /// \return true if either isValidCoding or messageLength is \a not equal, + /// false otherwise + bool operator==(const DecodingResult &rhs) const {return isValidCoding == rhs.isValidCoding && messageLength == rhs.messageLength;} + /// \brief Compare two DecodingResult + /// \param rhs the other DecodingResult + /// \return true if either isValidCoding or messageLength is \a not equal, + /// false otherwise + /// \details Returns !operator==(rhs). + bool operator!=(const DecodingResult &rhs) const {return !operator==(rhs);} + + /// \brief Flag to indicate the decoding is valid + bool isValidCoding; + /// \brief Recovered message length if isValidCoding is true, undefined otherwise + size_t messageLength; +}; + +/// \brief Interface for retrieving values given their names +/// \details This class is used to safely pass a variable number of arbitrarily +/// typed arguments to functions and to read values from keys and crypto parameters. +/// \details To obtain an object that implements NameValuePairs for the purpose of +/// parameter passing, use the MakeParameters() function. +/// \details To get a value from NameValuePairs, you need to know the name and the +/// type of the value. Call GetValueNames() on a NameValuePairs object to obtain a +/// list of value names that it supports. then look at the Name namespace +/// documentation to see what the type of each value is, or alternatively, call +/// GetIntValue() with the value name, and if the type is not int, a +/// ValueTypeMismatch exception will be thrown and you can get the actual type from +/// the exception object. +/// \sa NullNameValuePairs, g_nullNameValuePairs, +/// NameValuePairs on the +/// Crypto++ wiki +class NameValuePairs +{ +public: + virtual ~NameValuePairs() {} + + /// \brief Thrown when an unexpected type is encountered + /// \details Exception thrown when trying to retrieve a value using a different + /// type than expected + class CRYPTOPP_DLL ValueTypeMismatch : public InvalidArgument + { + public: + /// \brief Construct a ValueTypeMismatch + /// \param name the name of the value + /// \param stored the \a actual type of the value stored + /// \param retrieving the \a presumed type of the value retrieved + ValueTypeMismatch(const std::string &name, const std::type_info &stored, const std::type_info &retrieving) + : InvalidArgument("NameValuePairs: type mismatch for '" + name + "', stored '" + stored.name() + "', trying to retrieve '" + retrieving.name() + "'") + , m_stored(stored), m_retrieving(retrieving) {} + + /// \brief Provides the stored type + /// \return the C++ mangled name of the type + const std::type_info & GetStoredTypeInfo() const {return m_stored;} + + /// \brief Provides the retrieveing type + /// \return the C++ mangled name of the type + const std::type_info & GetRetrievingTypeInfo() const {return m_retrieving;} + + private: + const std::type_info &m_stored; + const std::type_info &m_retrieving; + }; + + /// \brief Get a copy of this object or subobject + /// \tparam T class or type + /// \param object reference to a variable that receives the value + template + bool GetThisObject(T &object) const + { + return GetValue((std::string("ThisObject:")+typeid(T).name()).c_str(), object); + } + + /// \brief Get a pointer to this object + /// \tparam T class or type + /// \param ptr reference to a pointer to a variable that receives the value + template + bool GetThisPointer(T *&ptr) const + { + return GetValue((std::string("ThisPointer:")+typeid(T).name()).c_str(), ptr); + } + + /// \brief Get a named value + /// \tparam T class or type + /// \param name the name of the object or value to retrieve + /// \param value reference to a variable that receives the value + /// \return true if the value was retrieved, false otherwise + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + template + bool GetValue(const char *name, T &value) const + { + return GetVoidValue(name, typeid(T), &value); + } + + /// \brief Get a named value + /// \tparam T class or type + /// \param name the name of the object or value to retrieve + /// \param defaultValue the default value of the class or type if it does not exist + /// \return the object or value + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + template + T GetValueWithDefault(const char *name, T defaultValue) const + { + T value; + bool result = GetValue(name, value); + // No assert... this recovers from failure + if (result) {return value;} + return defaultValue; + } + + /// \brief Get a list of value names that can be retrieved + /// \return a list of names available to retrieve + /// \details the items in the list are delimited with a colon. + CRYPTOPP_DLL std::string GetValueNames() const + {std::string result; GetValue("ValueNames", result); return result;} + + /// \brief Get a named value with type int + /// \param name the name of the value to retrieve + /// \param value the value retrieved upon success + /// \return true if an int value was retrieved, false otherwise + /// \details GetIntValue() is used to ensure we don't accidentally try to get an + /// unsigned int or some other type when we mean int (which is the most common case) + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL bool GetIntValue(const char *name, int &value) const + {return GetValue(name, value);} + + /// \brief Get a named value with type int, with default + /// \param name the name of the value to retrieve + /// \param defaultValue the default value if the name does not exist + /// \return the value retrieved on success or the default value + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL int GetIntValueWithDefault(const char *name, int defaultValue) const + {return GetValueWithDefault(name, defaultValue);} + + /// \brief Get a named value with type word64 + /// \param name the name of the value to retrieve + /// \param value the value retrieved upon success + /// \return true if an word64 value was retrieved, false otherwise + /// \sa GetValue(), GetValueWithDefault(), GetWord64ValueWithDefault(), GetIntValue(), + /// GetIntValueWithDefault(), GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL bool GetWord64Value(const char *name, word64 &value) const + {return GetValue(name, value);} + + /// \brief Get a named value with type word64, with default + /// \param name the name of the value to retrieve + /// \param defaultValue the default value if the name does not exist + /// \return the value retrieved on success or the default value + /// \sa GetValue(), GetValueWithDefault(), GetWord64Value(), GetIntValue(), + /// GetIntValueWithDefault(), GetRequiredParameter() and GetRequiredWord64Parameter() + CRYPTOPP_DLL word64 GetWord64ValueWithDefault(const char *name, word64 defaultValue) const + {return GetValueWithDefault(name, defaultValue);} + + /// \brief Ensures an expected name and type is present + /// \param name the name of the value + /// \param stored the type that was stored for the name + /// \param retrieving the type that is being retrieved for the name + /// \throw ValueTypeMismatch + /// \details ThrowIfTypeMismatch() effectively performs a type safety check. + /// stored and retrieving are C++ mangled names for the type. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL static void CRYPTOPP_API ThrowIfTypeMismatch(const char *name, const std::type_info &stored, const std::type_info &retrieving) + {if (stored != retrieving) throw ValueTypeMismatch(name, stored, retrieving);} + + /// \brief Retrieves a required name/value pair + /// \tparam T class or type + /// \param className the name of the class + /// \param name the name of the value + /// \param value reference to a variable to receive the value + /// \throw InvalidArgument + /// \details GetRequiredParameter() throws InvalidArgument if the name + /// is not present or not of the expected type T. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + template + void GetRequiredParameter(const char *className, const char *name, T &value) const + { + if (!GetValue(name, value)) + throw InvalidArgument(std::string(className) + ": missing required parameter '" + name + "'"); + } + + /// \brief Retrieves a required name/value pair + /// \param className the name of the class + /// \param name the name of the value + /// \param value reference to a variable to receive the value + /// \throw InvalidArgument + /// \details GetRequiredParameter() throws InvalidArgument if the name + /// is not present or not of the expected type T. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL void GetRequiredIntParameter(const char *className, const char *name, int &value) const + { + if (!GetIntValue(name, value)) + throw InvalidArgument(std::string(className) + ": missing required parameter '" + name + "'"); + } + + /// \brief Get a named value + /// \param name the name of the object or value to retrieve + /// \param valueType reference to a variable that receives the value + /// \param pValue void pointer to a variable that receives the value + /// \return true if the value was retrieved, false otherwise + /// \details GetVoidValue() retrieves the value of name if it exists. + /// \note GetVoidValue() is an internal function and should be implemented + /// by derived classes. Users should use one of the other functions instead. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + CRYPTOPP_DLL virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const =0; +}; + +// Doxygen cannot handle initialization +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Default channel for BufferedTransformation +/// \details DEFAULT_CHANNEL is equal to an empty string +/// \details The definition for DEFAULT_CHANNEL is in cryptlib.cpp. +/// It can be subject to Static +/// Initialization Order Fiasco. If you experience a crash in +/// DEFAULT_CHANNEL where the string object is NULL, then you probably have +/// a global object using DEFAULT_CHANNEL before it has been constructed. +const std::string DEFAULT_CHANNEL; + +/// \brief Channel for additional authenticated data +/// \details AAD_CHANNEL is equal to "AAD" +/// \details The definition for AAD_CHANNEL is in cryptlib.cpp. +/// It can be subject to Static +/// Initialization Order Fiasco. If you experience a crash in +/// AAD_CHANNEL where the string object is NULL, then you probably have a +/// global object using AAD_CHANNEL before it has been constructed. +const std::string AAD_CHANNEL; + +/// \brief An empty set of name-value pairs +/// \details The definition for g_nullNameValuePairs is in cryptlib.cpp. +/// It can be subject to Static +/// Initialization Order Fiasco. If you experience a crash in +/// g_nullNameValuePairs where the string object is NULL, then you probably +/// have a global object using g_nullNameValuePairs before it has been +/// constructed. +const NameValuePairs& g_nullNameValuePairs; + +#else +extern CRYPTOPP_DLL const std::string DEFAULT_CHANNEL; +extern CRYPTOPP_DLL const std::string AAD_CHANNEL; +extern CRYPTOPP_DLL const NameValuePairs& g_nullNameValuePairs; +#endif + +// Document additional name spaces which show up elsewhere in the sources. +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Namespace containing value name definitions. +/// \details Name is part of the CryptoPP namespace. +/// \details The semantics of value names, types are: +///

+///     ThisObject:ClassName (ClassName, copy of this object or a subobject)
+///     ThisPointer:ClassName (const ClassName *, pointer to this object or a subobject)
+/// 
+DOCUMENTED_NAMESPACE_BEGIN(Name) +// more names defined in argnames.h +DOCUMENTED_NAMESPACE_END + +/// \brief Namespace containing weak and wounded algorithms. +/// \details Weak is part of the CryptoPP namespace. Schemes and algorithms are moved into Weak +/// when their security level is reduced to an unacceptable level by contemporary standards. +/// \details To use an algorithm in the Weak namespace, you must \c \#define +/// CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 before including a header for a weak or wounded +/// algorithm. For example: +///
  \c \#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
+///   \c \#include 
+///   ...
+///   CryptoPP::Weak::MD5 md5;
+///   
+DOCUMENTED_NAMESPACE_BEGIN(Weak) +// weak and wounded algorithms +DOCUMENTED_NAMESPACE_END +#endif + +/// \brief Namespace containing NaCl library functions +/// \details TweetNaCl is a compact and portable reimplementation of the NaCl library. +DOCUMENTED_NAMESPACE_BEGIN(NaCl) +// crypto_box, crypto_box_open, crypto_sign, and crypto_sign_open (and friends) +DOCUMENTED_NAMESPACE_END + +/// \brief Namespace containing testing and benchmark classes. +/// \details Source files for classes in the Test namespaces include +/// test.cpp, validat#.cpp and bench#.cpp. +DOCUMENTED_NAMESPACE_BEGIN(Test) +// testing and benchmark classes +DOCUMENTED_NAMESPACE_END + +// ******************************************************** + +/// \brief Interface for cloning objects +/// \note this is \a not implemented by most classes +/// \sa ClonableImpl, NotCopyable +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Clonable +{ +public: + virtual ~Clonable() {} + + /// \brief Copies this object + /// \return a copy of this object + /// \throw NotImplemented + /// \note this is \a not implemented by most classes + /// \sa NotCopyable + virtual Clonable* Clone() const {throw NotImplemented("Clone() is not implemented yet.");} // TODO: make this =0 +}; + +/// \brief Interface for all crypto algorithms +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Algorithm : public Clonable +{ +public: + virtual ~Algorithm() {} + + /// \brief Interface for all crypto algorithms + /// \param checkSelfTestStatus determines whether the object can proceed if the self + /// tests have not been run or failed. + /// \details When FIPS 140-2 compliance is enabled and checkSelfTestStatus == true, + /// this constructor throws SelfTestFailure if the self test hasn't been run or fails. + /// \details FIPS 140-2 compliance is disabled by default. It is only used by certain + /// versions of the library when the library is built as a DLL on Windows. Also see + /// CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 in config.h. + Algorithm(bool checkSelfTestStatus = true); + + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like AES or AES/GCM. + /// Some algorithms do not have standard names yet. For example, there is no standard + /// algorithm name for Shoup's ECIES. + /// \note AlgorithmName is not universally implemented yet. + virtual std::string AlgorithmName() const {return "unknown";} + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2". + /// Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics + /// instead of ASM. + /// \details Algorithms which combine different instructions or ISAs provide the + /// dominant one. For example on x86 AES/GCM returns "AESNI" rather than + /// "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL". + /// \note Provider is not universally implemented yet. + /// \since Crypto++ 8.0 + virtual std::string AlgorithmProvider() const {return "C++";} +}; + +/// \brief Interface for algorithms that take byte strings as keys +/// \sa FixedKeyLength(), VariableKeyLength(), SameKeyLengthAs(), SimpleKeyingInterfaceImpl() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SimpleKeyingInterface +{ +public: + virtual ~SimpleKeyingInterface() {} + + /// \brief Returns smallest valid key length + /// \return the minimum key length, in bytes + virtual size_t MinKeyLength() const =0; + + /// \brief Returns largest valid key length + /// \return the maximum key length, in bytes + virtual size_t MaxKeyLength() const =0; + + /// \brief Returns default key length + /// \return the default key length, in bytes + virtual size_t DefaultKeyLength() const =0; + + /// \brief Returns a valid key length for the algorithm + /// \param keylength the size of the key, in bytes + /// \return the valid key length, in bytes + /// \details keylength is provided in bytes, not bits. If keylength is less than MIN_KEYLENGTH, + /// then the function returns MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, + /// then the function returns MAX_KEYLENGTH. if If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns a \a lower multiple of + /// KEYLENGTH_MULTIPLE. + virtual size_t GetValidKeyLength(size_t keylength) const =0; + + /// \brief Returns whether keylength is a valid key length + /// \param keylength the requested keylength + /// \return true if keylength is valid, false otherwise + /// \details Internally the function calls GetValidKeyLength() + virtual bool IsValidKeyLength(size_t keylength) const + {return keylength == GetValidKeyLength(keylength);} + + /// \brief Sets or reset the key of this object + /// \param key the key to use when keying the object + /// \param length the size of the key, in bytes + /// \param params additional initialization parameters to configure this object + virtual void SetKey(const byte *key, size_t length, const NameValuePairs ¶ms = g_nullNameValuePairs); + + /// \brief Sets or reset the key of this object + /// \param key the key to use when keying the object + /// \param length the size of the key, in bytes + /// \param rounds the number of rounds to apply the transformation function, + /// if applicable + /// \details SetKeyWithRounds() calls SetKey() with a NameValuePairs + /// object that only specifies rounds. rounds is an integer parameter, + /// and -1 means use the default number of rounds. + void SetKeyWithRounds(const byte *key, size_t length, int rounds); + + /// \brief Sets or reset the key of this object + /// \param key the key to use when keying the object + /// \param length the size of the key, in bytes + /// \param iv the initialization vector to use when keying the object + /// \param ivLength the size of the iv, in bytes + /// \details SetKeyWithIV() calls SetKey() with a NameValuePairs + /// that only specifies IV. The IV is a byte buffer with size ivLength. + /// ivLength is an integer parameter, and -1 means use IVSize(). + void SetKeyWithIV(const byte *key, size_t length, const byte *iv, size_t ivLength); + + /// \brief Sets or reset the key of this object + /// \param key the key to use when keying the object + /// \param length the size of the key, in bytes + /// \param iv the initialization vector to use when keying the object + /// \details SetKeyWithIV() calls SetKey() with a NameValuePairs() object + /// that only specifies iv. iv is a byte buffer, and it must have + /// a size IVSize(). + void SetKeyWithIV(const byte *key, size_t length, const byte *iv) + {SetKeyWithIV(key, length, iv, IVSize());} + + /// \brief Secure IVs requirements as enumerated values. + /// \details Provides secure IV requirements as a monotonically increasing enumerated values. + /// Requirements can be compared using less than (<) and greater than (>). For example, + /// UNIQUE_IV < RANDOM_IV and UNPREDICTABLE_RANDOM_IV > RANDOM_IV. + /// \details Objects that use SimpleKeyingInterface do not support an optional IV. That is, + /// an IV must be present or it must be absent. If you wish to support an optional IV then + /// provide two classes - one with an IV and one without an IV. + /// \sa IsResynchronizable(), CanUseRandomIVs(), CanUsePredictableIVs(), CanUseStructuredIVs() + enum IV_Requirement { + /// \brief The IV must be unique + UNIQUE_IV = 0, + /// \brief The IV must be random and possibly predictable + RANDOM_IV, + /// \brief The IV must be random and unpredictable + UNPREDICTABLE_RANDOM_IV, + /// \brief The IV is set by the object + INTERNALLY_GENERATED_IV, + /// \brief The object does not use an IV + NOT_RESYNCHRONIZABLE + }; + + /// \brief Minimal requirement for secure IVs + /// \return the secure IV requirement of the algorithm + virtual IV_Requirement IVRequirement() const =0; + + /// \brief Determines if the object can be resynchronized + /// \return true if the object can be resynchronized (i.e. supports initialization vectors), false otherwise + /// \note If this function returns true, and no IV is passed to SetKey() and CanUseStructuredIVs()==true, + /// an IV of all 0's will be assumed. + bool IsResynchronizable() const {return IVRequirement() < NOT_RESYNCHRONIZABLE;} + + /// \brief Determines if the object can use random IVs + /// \return true if the object can use random IVs (in addition to ones returned by GetNextIV), false otherwise + bool CanUseRandomIVs() const {return IVRequirement() <= UNPREDICTABLE_RANDOM_IV;} + + /// \brief Determines if the object can use random but possibly predictable IVs + /// \return true if the object can use random but possibly predictable IVs (in addition to ones returned by + /// GetNextIV), false otherwise + bool CanUsePredictableIVs() const {return IVRequirement() <= RANDOM_IV;} + + /// \brief Determines if the object can use structured IVs + /// \return true if the object can use structured IVs, false otherwise + /// \details CanUseStructuredIVs() indicates whether the object can use structured IVs; for example a counter + /// (in addition to ones returned by GetNextIV). + bool CanUseStructuredIVs() const {return IVRequirement() <= UNIQUE_IV;} + + /// \brief Returns length of the IV accepted by this object + /// \return the size of an IV, in bytes + /// \throw NotImplemented() if the object does not support resynchronization + /// \details The default implementation throws NotImplemented + virtual unsigned int IVSize() const + {throw NotImplemented(GetAlgorithm().AlgorithmName() + ": this object doesn't support resynchronization");} + + /// \brief Provides the default size of an IV + /// \return default length of IVs accepted by this object, in bytes + unsigned int DefaultIVLength() const {return IVSize();} + + /// \brief Provides the minimum size of an IV + /// \return minimal length of IVs accepted by this object, in bytes + /// \throw NotImplemented() if the object does not support resynchronization + virtual unsigned int MinIVLength() const {return IVSize();} + + /// \brief Provides the maximum size of an IV + /// \return maximal length of IVs accepted by this object, in bytes + /// \throw NotImplemented() if the object does not support resynchronization + virtual unsigned int MaxIVLength() const {return IVSize();} + + /// \brief Resynchronize with an IV + /// \param iv the initialization vector + /// \param ivLength the size of the initialization vector, in bytes + /// \details Resynchronize() resynchronizes with an IV provided by the caller. ivLength=-1 means use IVSize(). + /// \throw NotImplemented() if the object does not support resynchronization + virtual void Resynchronize(const byte *iv, int ivLength=-1) { + CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(ivLength); + throw NotImplemented(GetAlgorithm().AlgorithmName() + ": this object doesn't support resynchronization"); + } + + /// \brief Retrieves a secure IV for the next message + /// \param rng a RandomNumberGenerator to produce keying material + /// \param iv a block of bytes to receive the IV + /// \details The IV must be at least IVSize() in length. + /// \details This method should be called after you finish encrypting one message and are ready + /// to start the next one. After calling it, you must call SetKey() or Resynchronize(). + /// before using this object again. + /// \details Internally, the base class implementation calls RandomNumberGenerator's GenerateBlock() + /// \note This method is not implemented on decryption objects. + virtual void GetNextIV(RandomNumberGenerator &rng, byte *iv); + +protected: + /// \brief Returns the base class Algorithm + /// \return the base class Algorithm + virtual const Algorithm & GetAlgorithm() const =0; + + /// \brief Sets the key for this object without performing parameter validation + /// \param key a byte buffer used to key the cipher + /// \param length the length of the byte buffer + /// \param params additional parameters passed as NameValuePairs + /// \details key must be at least DEFAULT_KEYLENGTH in length. + virtual void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) =0; + + /// \brief Validates the key length + /// \param length the size of the keying material, in bytes + /// \throw InvalidKeyLength if the key length is invalid + void ThrowIfInvalidKeyLength(size_t length); + + /// \brief Validates the object + /// \throw InvalidArgument if the IV is present + /// \details Internally, the default implementation calls IsResynchronizable() and throws + /// InvalidArgument if the function returns true. + /// \note called when no IV is passed + void ThrowIfResynchronizable(); + + /// \brief Validates the IV + /// \param iv the IV with a length of IVSize, in bytes + /// \throw InvalidArgument on failure + /// \details Internally, the default implementation checks the iv. If iv is not NULL or nullptr, + /// then the function succeeds. If iv is NULL, then IVRequirement is checked against + /// UNPREDICTABLE_RANDOM_IV. If IVRequirement is UNPREDICTABLE_RANDOM_IV, then + /// then the function succeeds. Otherwise, an exception is thrown. + void ThrowIfInvalidIV(const byte *iv); + + /// \brief Validates the IV length + /// \param length the size of an IV, in bytes + /// \throw InvalidArgument if the IV length is invalid + size_t ThrowIfInvalidIVLength(int length); + + /// \brief Retrieves and validates the IV + /// \param params NameValuePairs with the IV supplied as a ConstByteArrayParameter + /// \param size the length of the IV, in bytes + /// \return a pointer to the first byte of the IV + /// \throw InvalidArgument if the number of rounds are invalid + const byte * GetIVAndThrowIfInvalid(const NameValuePairs ¶ms, size_t &size); + + /// \brief Validates the key length + /// \param length the size of the keying material, in bytes + inline void AssertValidKeyLength(size_t length) const + {CRYPTOPP_UNUSED(length); CRYPTOPP_ASSERT(IsValidKeyLength(length));} +}; + +/// \brief Interface for the data processing part of block ciphers +/// \details Classes derived from BlockTransformation are block ciphers +/// in ECB mode (for example the DES::Encryption class), which are stateless. +/// These classes should not be used directly, but only in combination with +/// a mode class (see CipherModeDocumentation in modes.h). +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockTransformation : public Algorithm +{ +public: + virtual ~BlockTransformation() {} + + /// \brief Encrypt or decrypt a block + /// \param inBlock the input message before processing + /// \param outBlock the output message after processing + /// \param xorBlock an optional XOR mask + /// \details ProcessAndXorBlock encrypts or decrypts inBlock, xor with xorBlock, and write to outBlock. + /// \details The size of the block is determined by the block cipher and its documentation. Use + /// BLOCKSIZE at compile time, or BlockSize() at runtime. + /// \note The message can be transformed in-place, or the buffers must \a not overlap + /// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize() + virtual void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const =0; + + /// \brief Encrypt or decrypt a block + /// \param inBlock the input message before processing + /// \param outBlock the output message after processing + /// \details ProcessBlock encrypts or decrypts inBlock and write to outBlock. + /// \details The size of the block is determined by the block cipher and its documentation. + /// Use BLOCKSIZE at compile time, or BlockSize() at runtime. + /// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize() + /// \note The message can be transformed in-place, or the buffers must \a not overlap + void ProcessBlock(const byte *inBlock, byte *outBlock) const + {ProcessAndXorBlock(inBlock, NULLPTR, outBlock);} + + /// \brief Encrypt or decrypt a block in place + /// \param inoutBlock the input message before processing + /// \details ProcessBlock encrypts or decrypts inoutBlock in-place. + /// \details The size of the block is determined by the block cipher and its documentation. + /// Use BLOCKSIZE at compile time, or BlockSize() at runtime. + /// \sa FixedBlockSize, BlockCipherFinal from seckey.h and BlockSize() + void ProcessBlock(byte *inoutBlock) const + {ProcessAndXorBlock(inoutBlock, NULLPTR, inoutBlock);} + + /// Provides the block size of the cipher + /// \return the block size of the cipher, in bytes + virtual unsigned int BlockSize() const =0; + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + virtual unsigned int OptimalDataAlignment() const; + + /// \brief Determines if the transformation is a permutation + /// \return true if this is a permutation (i.e. there is an inverse transformation) + virtual bool IsPermutation() const {return true;} + + /// \brief Determines if the cipher is being operated in its forward direction + /// \return true if DIR is ENCRYPTION, false otherwise + /// \sa IsForwardTransformation(), IsPermutation(), GetCipherDirection() + virtual bool IsForwardTransformation() const =0; + + /// \brief Determines the number of blocks that can be processed in parallel + /// \return the number of blocks that can be processed in parallel, for bit-slicing implementations + /// \details Bit-slicing is often used to improve throughput and minimize timing attacks. + virtual unsigned int OptimalNumberOfParallelBlocks() const {return 1;} + + /// \brief Bit flags that control AdvancedProcessBlocks() behavior + enum FlagsForAdvancedProcessBlocks { + /// \brief inBlock is a counter + BT_InBlockIsCounter=1, + /// \brief should not modify block pointers + BT_DontIncrementInOutPointers=2, + /// \brief Xor inputs before transformation + BT_XorInput=4, + /// \brief perform the transformation in reverse + BT_ReverseDirection=8, + /// \brief Allow parallel transformations + BT_AllowParallel=16}; + + /// \brief Encrypt and xor multiple blocks using additional flags + /// \param inBlocks the input message before processing + /// \param xorBlocks an optional XOR mask + /// \param outBlocks the output message after processing + /// \param length the size of the blocks, in bytes + /// \param flags additional flags to control processing + /// \details Encrypt and xor multiple blocks according to FlagsForAdvancedProcessBlocks flags. + /// \note If BT_InBlockIsCounter is set, then the last byte of inBlocks may be modified. + virtual size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; + + /// \brief Provides the direction of the cipher + /// \return ENCRYPTION if IsForwardTransformation() is true, DECRYPTION otherwise + /// \sa IsForwardTransformation(), IsPermutation() + inline CipherDir GetCipherDirection() const {return IsForwardTransformation() ? ENCRYPTION : DECRYPTION;} +}; + +/// \brief Interface for the data processing portion of stream ciphers +/// \sa StreamTransformationFilter() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE StreamTransformation : public Algorithm +{ +public: + virtual ~StreamTransformation() {} + + /// \brief Provides a reference to this object + /// \return A reference to this object + /// \details Useful for passing a temporary object to a function that takes a non-const reference + StreamTransformation& Ref() {return *this;} + + /// \brief Provides the mandatory block size of the cipher + /// \return The block size of the cipher if input must be processed in blocks, 1 otherwise + /// \details Stream ciphers and some block ciphers modes of operation return 1. Modes that + /// return 1 must be able to process a single byte at a time, like counter mode. If a + /// mode of operation or block cipher cannot stream then it must not return 1. + /// \details When filters operate the mode or cipher, ProcessData will be called with a + /// string of bytes that is determined by MandatoryBlockSize and OptimalBlockSize. When a + /// policy is set, like 16-byte strings for a 16-byte block cipher, the filter will buffer + /// bytes until the specified number of bytes is available to the object. + /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + virtual unsigned int MandatoryBlockSize() const {return 1;} + + /// \brief Provides the input block size most efficient for this cipher + /// \return The input block size that is most efficient for the cipher + /// \details The base class implementation returns MandatoryBlockSize(). + /// \note Optimal input length is + /// n * OptimalBlockSize() - GetOptimalBlockSizeUsed() for any n \> 0. + virtual unsigned int OptimalBlockSize() const {return MandatoryBlockSize();} + + /// \brief Provides the number of bytes used in the current block when processing at optimal block size. + /// \return the number of bytes used in the current block when processing at the optimal block size + virtual unsigned int GetOptimalBlockSizeUsed() const {return 0;} + + /// \brief Provides input and output data alignment for optimal performance + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + virtual unsigned int OptimalDataAlignment() const; + + /// \brief Encrypt or decrypt an array of bytes + /// \param outString the output byte buffer + /// \param inString the input byte buffer + /// \param length the size of the input and output byte buffers, in bytes + /// \details ProcessData is called with a string of bytes whose size depends on MandatoryBlockSize. + /// Either inString == outString, or they must not overlap. + /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + virtual void ProcessData(byte *outString, const byte *inString, size_t length) =0; + + /// \brief Encrypt or decrypt the last block of data + /// \param outString the output byte buffer + /// \param outLength the size of the output byte buffer, in bytes + /// \param inString the input byte buffer + /// \param inLength the size of the input byte buffer, in bytes + /// \return the number of bytes used in outString + /// \details ProcessLastBlock is used when the last block of data is special and requires handling + /// by the cipher. The current implementation provides an output buffer with a size + /// inLength+2*MandatoryBlockSize(). The return value allows the cipher to expand cipher + /// text during encryption or shrink plain text during decryption. + /// \details This member function is used by CBC-CTS and OCB modes. + /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + virtual size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); + + /// \brief Provides the size of the last block + /// \return the minimum size of the last block + /// \details MinLastBlockSize() returns the minimum size of the last block. 0 indicates the last + /// block is not special. + /// \details MandatoryBlockSize() enlists one of two behaviors. First, if MandatoryBlockSize() + /// returns 1, then the cipher can be streamed and ProcessData() is called with the tail bytes. + /// Second, if MandatoryBlockSize() returns non-0, then the string of bytes is padded to + /// MandatoryBlockSize() according to the padding mode. Then, ProcessData() is called with the + /// padded string of bytes. + /// \details Some authenticated encryption modes are not expressed well with MandatoryBlockSize() + /// and MinLastBlockSize(). For example, AES/OCB uses 16-byte blocks (MandatoryBlockSize = 16) + /// and the last block requires special processing (MinLastBlockSize = 0). However, 0 is a valid + /// last block size for OCB and the special processing is custom padding, and not standard PKCS + /// padding. In response an unambiguous IsLastBlockSpecial() was added. + /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + virtual unsigned int MinLastBlockSize() const {return 0;} + + /// \brief Determines if the last block receives special processing + /// \return true if the last block receives special processing, false otherwise. + /// \details Some authenticated encryption modes are not expressed well with + /// MandatoryBlockSize() and MinLastBlockSize(). For example, AES/OCB uses + /// 16-byte blocks (MandatoryBlockSize = 16) and the last block requires special processing + /// (MinLastBlockSize = 0). However, 0 is a valid last block size for OCB and the special + /// processing is custom padding, and not standard PKCS padding. In response an + /// unambiguous IsLastBlockSpecial() was added. + /// \details When IsLastBlockSpecial() returns false nothing special happens. All the former + /// rules and behaviors apply. This is the default behavior of IsLastBlockSpecial(). + /// \details When IsLastBlockSpecial() returns true four things happen. First, MinLastBlockSize = 0 + /// means 0 is a valid block size that should be processed. Second, standard block cipher padding is + /// \a not \a applied. Third, the caller supplies an outString is larger than inString by + /// 2*MandatoryBlockSize(). That is, there's a reserve available when processing the last block. + /// Fourth, the cipher is responsible for finalization like custom padding. The cipher will tell + /// the library how many bytes were processed or used by returning the appropriate value from + /// ProcessLastBlock(). + /// \details The return value of ProcessLastBlock() indicates how many bytes were written to + /// outString. A filter pipelining data will send outString and up to outLength + /// to an AttachedTransformation() for additional processing. Below is an example of the code + /// used in StreamTransformationFilter::LastPut. + ///
  if (m_cipher.IsLastBlockSpecial())
+	///   {
+	///     size_t reserve = 2*m_cipher.MandatoryBlockSize();
+	///     space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, length+reserve);
+	///     length = m_cipher.ProcessLastBlock(space, length+reserve, inString, length);
+	///     AttachedTransformation()->Put(space, length);
+	///     return;
+	///   }
+ /// \sa ProcessData, ProcessLastBlock, MandatoryBlockSize, MinLastBlockSize, BlockPaddingSchemeDef, IsLastBlockSpecial + /// \since Crypto++ 6.0 + virtual bool IsLastBlockSpecial() const {return false;} + + /// \brief Encrypt or decrypt a string of bytes + /// \param inoutString the string to process + /// \param length the size of the inoutString, in bytes + /// \details Internally, the base class implementation calls ProcessData(). + inline void ProcessString(byte *inoutString, size_t length) + {ProcessData(inoutString, inoutString, length);} + + /// \brief Encrypt or decrypt a string of bytes + /// \param outString the output string to process + /// \param inString the input string to process + /// \param length the size of the input and output strings, in bytes + /// \details Internally, the base class implementation calls ProcessData(). + inline void ProcessString(byte *outString, const byte *inString, size_t length) + {ProcessData(outString, inString, length);} + + /// \brief Encrypt or decrypt a byte + /// \param input the input byte to process + /// \details Internally, the base class implementation calls ProcessData() with a size of 1. + inline byte ProcessByte(byte input) + {ProcessData(&input, &input, 1); return input;} + + /// \brief Determines whether the cipher supports random access + /// \return true if the cipher supports random access, false otherwise + virtual bool IsRandomAccess() const =0; + + /// \brief Seek to an absolute position + /// \param pos position to seek + /// \throw NotImplemented + /// \details The base class implementation throws NotImplemented. The function + /// \ref CRYPTOPP_ASSERT "asserts" IsRandomAccess() in debug builds. + virtual void Seek(lword pos) + { + CRYPTOPP_UNUSED(pos); + CRYPTOPP_ASSERT(!IsRandomAccess()); + throw NotImplemented("StreamTransformation: this object doesn't support random access"); + } + + /// \brief Determines whether the cipher is self-inverting + /// \return true if the cipher is self-inverting, false otherwise + /// \details IsSelfInverting determines whether this transformation is + /// self-inverting (e.g. xor with a keystream). + virtual bool IsSelfInverting() const =0; + + /// \brief Determines if the cipher is being operated in its forward direction + /// \return true if DIR is ENCRYPTION, false otherwise + /// \sa IsForwardTransformation(), IsPermutation(), GetCipherDirection() + virtual bool IsForwardTransformation() const =0; +}; + +/// \brief Interface for hash functions and data processing part of MACs +/// \details HashTransformation objects are stateful. They are created in an initial state, +/// change state as Update() is called, and return to the initial +/// state when Final() is called. This interface allows a large message to +/// be hashed in pieces by calling Update() on each piece followed by +/// calling Final(). +/// \sa HashFilter(), HashVerificationFilter() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE HashTransformation : public Algorithm +{ +public: + virtual ~HashTransformation() {} + + /// \brief Provides a reference to this object + /// \return A reference to this object + /// \details Useful for passing a temporary object to a function that takes a non-const reference + HashTransformation& Ref() {return *this;} + + /// \brief Updates a hash with additional input + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + virtual void Update(const byte *input, size_t length) =0; + + /// \brief Request space which can be written into by the caller + /// \param size the requested size of the buffer + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL or nullptr. + /// \note Some objects, like ArraySink, cannot create a space because its fixed. + virtual byte * CreateUpdateSpace(size_t &size) {size=0; return NULLPTR;} + + /// \brief Computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \details Final() restarts the hash for a new message. + /// \pre COUNTOF(digest) <= DigestSize() or COUNTOF(digest) <= HASH::DIGESTSIZE ensures + /// the output byte buffer is large enough for the digest. + virtual void Final(byte *digest) + {TruncatedFinal(digest, DigestSize());} + + /// \brief Restart the hash + /// \details Discards the current state, and restart for a new message + virtual void Restart() + {TruncatedFinal(NULLPTR, 0);} + + /// Provides the digest size of the hash + /// \return the digest size of the hash. + virtual unsigned int DigestSize() const =0; + + /// Provides the tag size of the hash + /// \return the tag size of the hash. + /// \details Same as DigestSize(). + unsigned int TagSize() const {return DigestSize();} + + /// \brief Provides the block size of the compression function + /// \return block size of the compression function, in bytes + /// \details BlockSize() will return 0 if the hash is not block based + /// or does not have an equivalent block size. For example, Keccak + /// and SHA-3 do not have a block size, but they do have an equivalent + /// block size called rate expressed as r. + virtual unsigned int BlockSize() const {return 0;} + + /// \brief Provides the input block size most efficient for this hash. + /// \return The input block size that is most efficient for the cipher + /// \details The base class implementation returns MandatoryBlockSize(). + /// \details Optimal input length is + /// n * OptimalBlockSize() - GetOptimalBlockSizeUsed() for any n \> 0. + virtual unsigned int OptimalBlockSize() const {return 1;} + + /// \brief Provides input and output data alignment for optimal performance + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + virtual unsigned int OptimalDataAlignment() const; + + /// \brief Updates the hash with additional input and computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + /// \details Use this if your input is in one piece and you don't want to call Update() + /// and Final() separately + /// \details CalculateDigest() restarts the hash for the next message. + /// \pre COUNTOF(digest) == DigestSize() or COUNTOF(digest) == HASH::DIGESTSIZE ensures + /// the output byte buffer is a valid size. + virtual void CalculateDigest(byte *digest, const byte *input, size_t length) + {Update(input, length); Final(digest);} + + /// \brief Verifies the hash of the current message + /// \param digest a pointer to the buffer of an \a existing hash + /// \return \p true if the existing hash matches the computed hash, \p false otherwise + /// \throw InvalidArgument() if the existing hash's size exceeds DigestSize() + /// \details Verify() performs a bitwise compare on the buffers using VerifyBufsEqual(), which is + /// a constant time comparison function. digestLength cannot exceed DigestSize(). + /// \details Verify() restarts the hash for the next message. + /// \pre COUNTOF(digest) == DigestSize() or COUNTOF(digest) == HASH::DIGESTSIZE ensures + /// the input byte buffer is a valid size. + virtual bool Verify(const byte *digest) + {return TruncatedVerify(digest, DigestSize());} + + /// \brief Updates the hash with additional input and verifies the hash of the current message + /// \param digest a pointer to the buffer of an \a existing hash + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + /// \return \p true if the existing hash matches the computed hash, \p false otherwise + /// \throw InvalidArgument() if the existing hash's size exceeds DigestSize() + /// \details Use this if your input is in one piece and you don't want to call Update() + /// and Verify() separately + /// \details VerifyDigest() performs a bitwise compare on the buffers using VerifyBufsEqual(), + /// which is a constant time comparison function. + /// \details VerifyDigest() restarts the hash for the next message. + /// \pre COUNTOF(digest) == DigestSize() or COUNTOF(digest) == HASH::DIGESTSIZE ensures + /// the output byte buffer is a valid size. + virtual bool VerifyDigest(const byte *digest, const byte *input, size_t length) + {Update(input, length); return Verify(digest);} + + /// \brief Computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param digestSize the size of the truncated digest, in bytes + /// \details TruncatedFinal() calls Final() and then copies digestSize bytes to digest. + /// The hash is restarted the hash for the next message. + /// \pre COUNTOF(digest) <= DigestSize() or COUNTOF(digest) <= HASH::DIGESTSIZE ensures + /// the output byte buffer is a valid size. + virtual void TruncatedFinal(byte *digest, size_t digestSize) =0; + + /// \brief Updates the hash with additional input and computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param digestSize the length of the truncated hash, in bytes + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + /// \details Use this if your input is in one piece and you don't want to call Update() + /// and CalculateDigest() separately. + /// \details CalculateTruncatedDigest() restarts the hash for the next message. + /// \pre digestSize <= DigestSize() or digestSize <= HASH::DIGESTSIZE ensures + /// the output byte buffer is a valid size. + virtual void CalculateTruncatedDigest(byte *digest, size_t digestSize, const byte *input, size_t length) + {Update(input, length); TruncatedFinal(digest, digestSize);} + + /// \brief Verifies the hash of the current message + /// \param digest a pointer to the buffer of an \a existing hash + /// \param digestLength the size of the truncated hash, in bytes + /// \return \p true if the existing hash matches the computed hash, \p false otherwise + /// \throw InvalidArgument() if digestLength exceeds DigestSize() + /// \details TruncatedVerify() is a truncated version of Verify(). It can operate on a + /// buffer smaller than DigestSize(). However, digestLength cannot exceed DigestSize(). + /// \details Verify() performs a bitwise compare on the buffers using VerifyBufsEqual(), which is + /// a constant time comparison function. digestLength cannot exceed DigestSize(). + /// \details TruncatedVerify() restarts the hash for the next message. + /// \pre digestLength <= DigestSize() or digestLength <= HASH::DIGESTSIZE ensures + /// the input byte buffer is a valid size. + virtual bool TruncatedVerify(const byte *digest, size_t digestLength); + + /// \brief Updates the hash with additional input and verifies the hash of the current message + /// \param digest a pointer to the buffer of an \a existing hash + /// \param digestLength the size of the truncated hash, in bytes + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + /// \return \p true if the existing hash matches the computed hash, \p false otherwise + /// \throw InvalidArgument() if digestLength exceeds DigestSize() + /// \details Use this if your input is in one piece and you don't want to call Update() + /// and TruncatedVerify() separately. + /// \details VerifyTruncatedDigest() is a truncated version of VerifyDigest(). It can operate + /// on a buffer smaller than DigestSize(). However, digestLength cannot exceed DigestSize(). + /// \details VerifyTruncatedDigest() restarts the hash for the next message. + /// \pre digestLength <= DigestSize() or digestLength <= HASH::DIGESTSIZE ensures + /// the input byte buffer is a valid size. + virtual bool VerifyTruncatedDigest(const byte *digest, size_t digestLength, const byte *input, size_t length) + {Update(input, length); return TruncatedVerify(digest, digestLength);} + +protected: + /// \brief Validates a truncated digest size + /// \param size the requested digest size + /// \throw InvalidArgument if the algorithm's digest size cannot be truncated to the requested size + /// \details Throws an exception when the truncated digest size is greater than DigestSize() + void ThrowIfInvalidTruncatedSize(size_t size) const; +}; + +/// \brief Interface for one direction (encryption or decryption) of a block cipher +/// \details These objects usually should not be used directly. See BlockTransformation for more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockCipher : public SimpleKeyingInterface, public BlockTransformation +{ +protected: + const Algorithm & GetAlgorithm() const {return *this;} +}; + +/// \brief Interface for one direction (encryption or decryption) of a stream cipher or cipher mode +/// \details These objects usually should not be used directly. See StreamTransformation for more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SymmetricCipher : public SimpleKeyingInterface, public StreamTransformation +{ +protected: + const Algorithm & GetAlgorithm() const {return *this;} +}; + +/// \brief Interface for message authentication codes +/// \details These objects usually should not be used directly. See HashTransformation for more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE MessageAuthenticationCode : public SimpleKeyingInterface, public HashTransformation +{ +protected: + const Algorithm & GetAlgorithm() const {return *this;} +}; + +/// \brief Interface for authenticated encryption modes of operation +/// \details AuthenticatedSymmetricCipher() provides the interface for one direction +/// (encryption or decryption) of a stream cipher or block cipher mode with authentication. The +/// StreamTransformation() part of this interface is used to encrypt or decrypt the data. The +/// MessageAuthenticationCode() part of the interface is used to input additional authenticated +/// data (AAD), which is MAC'ed but not encrypted. The MessageAuthenticationCode() part is also +/// used to generate and verify the MAC. +/// \details Crypto++ provides four authenticated encryption modes of operation - CCM, EAX, GCM +/// and OCB mode. All modes implement AuthenticatedSymmetricCipher() and the motivation for +/// the API, like calling AAD a "header", can be found in Bellare, Rogaway and +/// Wagner's The EAX Mode of +/// Operation. The EAX paper suggested a basic API to help standardize AEAD schemes in +/// software and promote adoption of the modes. +/// \sa Authenticated +/// Encryption on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedSymmetricCipher : public MessageAuthenticationCode, public StreamTransformation +{ +public: + virtual ~AuthenticatedSymmetricCipher() {} + + /// \brief Exception thrown when the object is in the wrong state for the operation + /// \details this indicates that a member function was called in the wrong state, for example trying to encrypt + /// a message before having set the key or IV + class BadState : public Exception + { + public: + explicit BadState(const std::string &name, const char *message) : Exception(OTHER_ERROR, name + ": " + message) {} + explicit BadState(const std::string &name, const char *function, const char *state) : Exception(OTHER_ERROR, name + ": " + function + " was called before " + state) {} + }; + + /// \brief Provides the maximum length of AAD that can be input + /// \return the maximum length of AAD that can be input before the encrypted data + virtual lword MaxHeaderLength() const =0; + + /// \brief Provides the maximum length of encrypted data + /// \return the maximum length of encrypted data + virtual lword MaxMessageLength() const =0; + + /// \brief Provides the maximum length of AAD + /// \return the maximum length of AAD that can be input after the encrypted data + virtual lword MaxFooterLength() const {return 0;} + + /// \brief Determines if data lengths must be specified prior to inputting data + /// \return true if the data lengths are required before inputting data, false otherwise + /// \details if this function returns true, SpecifyDataLengths() must be called before attempting to input data. + /// This is the case for some schemes, such as CCM. + /// \sa SpecifyDataLengths() + virtual bool NeedsPrespecifiedDataLengths() const {return false;} + + /// \brief Prescribes the data lengths + /// \param headerLength size of data before message is input, in bytes + /// \param messageLength size of the message, in bytes + /// \param footerLength size of data after message is input, in bytes + /// \details SpecifyDataLengths() only needs to be called if NeedsPrespecifiedDataLengths() returns true. + /// If true, then headerLength will be validated against MaxHeaderLength(), + /// messageLength will be validated against MaxMessageLength(), and + /// footerLength will be validated against MaxFooterLength(). + /// \sa NeedsPrespecifiedDataLengths() + void SpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength=0); + + /// \brief Encrypts and calculates a MAC in one call + /// \param ciphertext the encryption buffer + /// \param mac the mac buffer + /// \param macSize the size of the MAC buffer, in bytes + /// \param iv the iv buffer + /// \param ivLength the size of the IV buffer, in bytes + /// \param header the AAD buffer + /// \param headerLength the size of the AAD buffer, in bytes + /// \param message the message buffer + /// \param messageLength the size of the messagetext buffer, in bytes + /// \details EncryptAndAuthenticate() encrypts and generates the MAC in one call. The function + /// truncates the MAC if macSize < TagSize(). + virtual void EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *header, size_t headerLength, const byte *message, size_t messageLength); + + /// \brief Decrypts and verifies a MAC in one call + /// \param message the decryption buffer + /// \param mac the mac buffer + /// \param macSize the size of the MAC buffer, in bytes + /// \param iv the iv buffer + /// \param ivLength the size of the IV buffer, in bytes + /// \param header the AAD buffer + /// \param headerLength the size of the AAD buffer, in bytes + /// \param ciphertext the ciphertext buffer + /// \param ciphertextLength the size of the ciphertext buffer, in bytes + /// \return true if the MAC is valid and the decoding succeeded, false otherwise + /// \details DecryptAndVerify() decrypts and verifies the MAC in one call. + /// message is a decryption buffer and should be at least as large as the ciphertext buffer. + /// \details The function returns true iff MAC is valid. DecryptAndVerify() assumes the MAC + /// is truncated if macLength < TagSize(). + virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *header, size_t headerLength, const byte *ciphertext, size_t ciphertextLength); + + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like \a AES or \a AES/GCM. Some algorithms + /// do not have standard names yet. For example, there is no standard algorithm name for + /// Shoup's ECIES. + virtual std::string AlgorithmName() const; + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2". + /// Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics + /// instead of ASM. + /// \details Algorithms which combine different instructions or ISAs provide the + /// dominant one. For example on x86 AES/GCM returns "AESNI" rather than + /// "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL". + /// \note Provider is not universally implemented yet. + /// \since Crypto++ 8.0 + virtual std::string AlgorithmProvider() const {return "C++";} + +protected: + const Algorithm & GetAlgorithm() const + {return *static_cast(this);} + virtual void UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength) + {CRYPTOPP_UNUSED(headerLength); CRYPTOPP_UNUSED(messageLength); CRYPTOPP_UNUSED(footerLength);} +}; + +/// \brief Interface for random number generators +/// \details The library provides a number of random number generators, from software based +/// to hardware based generators. +/// \details All generated values are uniformly distributed over the range specified. +/// \since Crypto++ 3.1 +/// \sa RandomNumberGenerator +/// on the Crypto++ wiki +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE RandomNumberGenerator : public Algorithm +{ +public: + virtual ~RandomNumberGenerator() {} + + /// \brief Update RNG state with additional unpredictable values + /// \param input the entropy to add to the generator + /// \param length the size of the input buffer + /// \throw NotImplemented + /// \details A generator may or may not accept additional entropy. Call CanIncorporateEntropy() + /// to test for the ability to use additional entropy. + /// \details If a derived class does not override IncorporateEntropy(), then the base class + /// throws NotImplemented. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + throw NotImplemented("RandomNumberGenerator: IncorporateEntropy not implemented"); + } + + /// \brief Determines if a generator can accept additional entropy + /// \return true if IncorporateEntropy() is implemented + virtual bool CanIncorporateEntropy() const {return false;} + + /// \brief Generate new random byte and return it + /// \return a random 8-bit byte + /// \details Default implementation calls GenerateBlock() with one byte. + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + virtual byte GenerateByte(); + + /// \brief Generate new random bit and return it + /// \return a random bit + /// \details The default implementation calls GenerateByte() and return its lowest bit. + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + virtual unsigned int GenerateBit(); + + /// \brief Generate a random 32 bit word in the range min to max, inclusive + /// \param min the lower bound of the range + /// \param max the upper bound of the range + /// \return a random 32-bit word + /// \details The default implementation calls Crop() on the difference between max and + /// min, and then returns the result added to min. + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + virtual word32 GenerateWord32(word32 min=0, word32 max=0xffffffffUL); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + /// \note A derived generator \a must override either GenerateBlock() or + /// GenerateIntoBufferedTransformation(). They can override both, or have one call the other. + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate random bytes into a BufferedTransformation + /// \param target the BufferedTransformation object which receives the bytes + /// \param channel the channel on which the bytes should be pumped + /// \param length the number of bytes to generate + /// \details The default implementation calls GenerateBlock() and pumps the result into + /// the DEFAULT_CHANNEL of the target. + /// \details All generated values are uniformly distributed over the range specified within the + /// the constraints of a particular generator. + /// \note A derived generator \a must override either GenerateBlock() or + /// GenerateIntoBufferedTransformation(). They can override both, or have one call the other. + virtual void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword length); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + virtual void DiscardBytes(size_t n); + + /// \brief Randomly shuffle the specified array + /// \param begin an iterator to the first element in the array + /// \param end an iterator beyond the last element in the array + /// \details The resulting permutation is uniformly distributed. + template void Shuffle(IT begin, IT end) + { + // TODO: What happens if there are more than 2^32 elements? + for (; begin != end; ++begin) + std::iter_swap(begin, begin + GenerateWord32(0, static_cast(end-begin-1))); + } +}; + +/// \brief Interface for key derivation functions +/// \since Crypto++ 7.0 +/// \sa KeyDerivationFunction +/// on the Crypto++ wiki +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE KeyDerivationFunction : public Algorithm +{ +public: + virtual ~KeyDerivationFunction() {} + + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + virtual std::string AlgorithmName() const =0; + + /// \brief Determine minimum number of bytes + /// \return Minimum number of bytes which can be derived + virtual size_t MinDerivedKeyLength() const; + + /// \brief Determine maximum number of bytes + /// \return Maximum number of bytes which can be derived + virtual size_t MaxDerivedKeyLength() const; + + /// \brief Returns a valid key length for the derivation function + /// \param keylength the size of the derived key, in bytes + /// \return the valid key length, in bytes + virtual size_t GetValidDerivedLength(size_t keylength) const =0; + + /// \brief Returns whether keylength is a valid key length + /// \param keylength the requested keylength + /// \return true if the derived keylength is valid, false otherwise + /// \details Internally the function calls GetValidKeyLength() + virtual bool IsValidDerivedLength(size_t keylength) const { + return keylength == GetValidDerivedLength(keylength); + } + + /// \brief Derive a key from a seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param params additional initialization parameters to configure this object + /// \return the number of iterations performed + /// \throw InvalidDerivedKeyLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a secret seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details the number of iterations performed by DeriveKey() may be 1. For example, a + /// scheme like HKDF does not use the iteration count so it returns 1. + virtual size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs& params = g_nullNameValuePairs) const =0; + + /// \brief Set or change parameters + /// \param params additional initialization parameters to configure this object + /// \details SetParameters() is useful for setting common parameters when an object is + /// reused. Some derivation function classes may choose to implement it. + virtual void SetParameters(const NameValuePairs& params); + +protected: + /// \brief Returns the base class Algorithm + /// \return the base class Algorithm + virtual const Algorithm & GetAlgorithm() const =0; + + /// \brief Validates the derived key length + /// \param length the size of the derived key material, in bytes + /// \throw InvalidKeyLength if the key length is invalid + void ThrowIfInvalidDerivedKeyLength(size_t length) const; +}; + +/// \brief Interface for password based key derivation functions +/// \since Crypto++ 7.0 +struct PasswordBasedKeyDerivationFunction : public KeyDerivationFunction +{ +}; + +/// \brief Random Number Generator that does not produce random numbers +/// \return reference that can be passed to functions that require a RandomNumberGenerator +/// \details NullRNG() returns a reference that can be passed to functions that require a +/// RandomNumberGenerator but don't actually use it. The NullRNG() throws NotImplemented +/// when a generation function is called. +/// \sa ClassNullRNG, PK_SignatureScheme::IsProbabilistic() +CRYPTOPP_DLL RandomNumberGenerator & CRYPTOPP_API NullRNG(); + +class WaitObjectContainer; +class CallStack; + +/// \brief Interface for objects that can be waited on. +class CRYPTOPP_NO_VTABLE Waitable +{ +public: + virtual ~Waitable() {} + + /// \brief Maximum number of wait objects that this object can return + /// \return the maximum number of wait objects + virtual unsigned int GetMaxWaitObjectCount() const =0; + + /// \brief Retrieves waitable objects + /// \param container the wait container to receive the references to the objects. + /// \param callStack CallStack() object used to select waitable objects + /// \details GetWaitObjects() is usually called in one of two ways. First, it can + /// be called like something.GetWaitObjects(c, CallStack("my func after X", 0));. + /// Second, if in an outer GetWaitObjects() method that itself takes a callStack + /// parameter, it can be called like + /// innerThing.GetWaitObjects(c, CallStack("MyClass::GetWaitObjects at X", &callStack));. + virtual void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) =0; + + /// \brief Wait on this object + /// \return true if the wait succeeded, false otherwise + /// \details Wait() is the same as creating an empty container, calling GetWaitObjects(), and then calling + /// Wait() on the container. + bool Wait(unsigned long milliseconds, CallStack const& callStack); +}; + +/// \brief Interface for buffered transformations +/// \details BufferedTransformation is a generalization of BlockTransformation, +/// StreamTransformation and HashTransformation. +/// \details A buffered transformation is an object that takes a stream of bytes as input (this may +/// be done in stages), does some computation on them, and then places the result into an internal +/// buffer for later retrieval. Any partial result already in the output buffer is not modified +/// by further input. +/// \details If a method takes a "blocking" parameter, and you pass false for it, then the method +/// will return before all input has been processed if the input cannot be processed without waiting +/// (for network buffers to become available, for example). In this case the method will return true +/// or a non-zero integer value. When this happens you must continue to call the method with the same +/// parameters until it returns false or zero, before calling any other method on it or attached +/// BufferedTransformation. The integer return value in this case is approximately +/// the number of bytes left to be processed, and can be used to implement a progress bar. +/// \details For functions that take a "propagation" parameter, propagation != 0 means pass on +/// the signal to attached BufferedTransformation objects, with propagation decremented at each +/// step until it reaches 0. -1 means unlimited propagation. +/// \details \a All of the retrieval functions, like Get() and GetWord32(), return the actual +/// number of bytes retrieved, which is the lesser of the request number and MaxRetrievable(). +/// \details \a Most of the input functions, like Put() and PutWord32(), return the number of +/// bytes remaining to be processed. A 0 value means all bytes were processed, and a non-0 value +/// means bytes remain to be processed. +/// \nosubgrouping +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BufferedTransformation : public Algorithm, public Waitable +{ +public: + virtual ~BufferedTransformation() {} + + /// \brief Construct a BufferedTransformation + BufferedTransformation() : Algorithm(false) {} + + /// \brief Provides a reference to this object + /// \return A reference to this object + /// \details Useful for passing a temporary object to a function that takes a non-const reference + BufferedTransformation& Ref() {return *this;} + + /// \name INPUT + //@{ + + /// \brief Input a byte for processing + /// \param inByte the 8-bit byte (octet) to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + /// \details Put(byte) calls Put(byte*, size_t). + size_t Put(byte inByte, bool blocking=true) + {return Put(&inByte, 1, blocking);} + + /// \brief Input a byte buffer for processing + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + /// \details Internally, Put() calls Put2(). + size_t Put(const byte *inString, size_t length, bool blocking=true) + {return Put2(inString, length, 0, blocking);} + + /// Input a 16-bit word for processing. + /// \param value the 16-bit value to be processed + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + size_t PutWord16(word16 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// Input a 32-bit word for processing. + /// \param value the 32-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + size_t PutWord32(word32 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// Input a 64-bit word for processing. + /// \param value the 64-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + size_t PutWord64(word64 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// \brief Request space which can be written into by the caller + /// \param size the requested size of the buffer + /// \return byte pointer to the space to input data + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink, cannot create a space because its fixed. In the case of + /// an ArraySink, the pointer to the array is returned and the size is remaining size. + virtual byte * CreatePutSpace(size_t &size) + {size=0; return NULLPTR;} + + /// \brief Determines whether input can be modified by the callee + /// \return true if input can be modified, false otherwise + /// \details The base class implementation returns false. + virtual bool CanModifyInput() const + {return false;} + + /// \brief Input multiple bytes that may be modified by callee. + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + size_t PutModifiable(byte *inString, size_t length, bool blocking=true) + {return PutModifiable2(inString, length, 0, blocking);} + + /// \brief Signals the end of messages to the object + /// \param propagation the number of attached transformations the MessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + bool MessageEnd(int propagation=-1, bool blocking=true) + {return !!Put2(NULLPTR, 0, propagation < 0 ? -1 : propagation+1, blocking);} + + /// \brief Input multiple bytes for processing and signal the end of a message + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param propagation the number of attached transformations the MessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + /// \details Internally, PutMessageEnd() calls Put2() with a modified propagation to + /// ensure all attached transformations finish processing the message. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + size_t PutMessageEnd(const byte *inString, size_t length, int propagation=-1, bool blocking=true) + {return Put2(inString, length, propagation < 0 ? -1 : propagation+1, blocking);} + + /// \brief Input multiple bytes for processing + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + /// \details Derived classes must implement Put2(). + virtual size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) =0; + + /// \brief Input multiple bytes that may be modified by callee. + /// \param inString the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). 0 indicates all + /// bytes were processed. + /// \details Internally, PutModifiable2() calls Put2(). + virtual size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking) + {return Put2(inString, length, messageEnd, blocking);} + + /// \brief Exception thrown by objects that have \a not implemented nonblocking input processing + /// \details BlockingInputOnly inherits from NotImplemented + struct BlockingInputOnly : public NotImplemented + {BlockingInputOnly(const std::string &s) : NotImplemented(s + ": Nonblocking input is not implemented by this object.") {}}; + //@} + + /// \name WAITING + //@{ + /// \brief Retrieves the maximum number of waitable objects + unsigned int GetMaxWaitObjectCount() const; + + /// \brief Retrieves waitable objects + /// \param container the wait container to receive the references to the objects + /// \param callStack CallStack() object used to select waitable objects + /// \details GetWaitObjects is usually called in one of two ways. First, it can + /// be called like something.GetWaitObjects(c, CallStack("my func after X", 0));. + /// Second, if in an outer GetWaitObjects() method that itself takes a callStack + /// parameter, it can be called like + /// innerThing.GetWaitObjects(c, CallStack("MyClass::GetWaitObjects at X", &callStack));. + void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack); + //@} // WAITING + + /// \name SIGNALS + //@{ + + /// \brief Initialize or reinitialize this object, without signal propagation + /// \param parameters a set of NameValuePairs to initialize this object + /// \throw NotImplemented + /// \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + /// number of arbitrarily typed arguments. The function avoids the need for multiple constructors providing + /// all possible combintations of configurable parameters. + /// \details IsolatedInitialize() does not call Initialize() on attached transformations. If initialization + /// should be propagated, then use the Initialize() function. + /// \details If a derived class does not override IsolatedInitialize(), then the base class throws + /// NotImplemented. + virtual void IsolatedInitialize(const NameValuePairs ¶meters) { + CRYPTOPP_UNUSED(parameters); + throw NotImplemented("BufferedTransformation: this object can't be reinitialized"); + } + + /// \brief Flushes data buffered by this object, without signal propagation + /// \param hardFlush indicates whether all data should be flushed + /// \param blocking specifies whether the object should block when processing input + /// \return true if the flush was successful, false otherwise + /// \note hardFlush must be used with care + virtual bool IsolatedFlush(bool hardFlush, bool blocking) =0; + + /// \brief Marks the end of a series of messages, without signal propagation + /// \param blocking specifies whether the object should block when completing the processing on + /// the current series of messages + /// \return true if the message was successful, false otherwise + virtual bool IsolatedMessageSeriesEnd(bool blocking) + {CRYPTOPP_UNUSED(blocking); return false;} + + /// \brief Initialize or reinitialize this object, with signal propagation + /// \param parameters a set of NameValuePairs to initialize or reinitialize this object + /// \param propagation the number of attached transformations the Initialize() signal should be passed + /// \details Initialize() is used to initialize or reinitialize an object using a variable number of + /// arbitrarily typed arguments. The function avoids the need for multiple constructors providing + /// all possible combintations of configurable parameters. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + virtual void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + + /// \brief Flush buffered input and/or output, with signal propagation + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the Flush() + /// signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true if the flush was successful, false otherwise + /// \details propagation count includes this object. Setting propagation to + /// 1 means this object only. Setting propagation to -1 + /// means unlimited propagation. + /// \note Hard flushes must be used with care. It means try to process and + /// output everything, even if there may not be enough data to complete the + /// action. For example, hard flushing a HexDecoder would cause an error if + /// you do it after inputing an odd number of hex encoded characters. + /// \note For some types of filters, like ZlibDecompressor, hard flushes can + /// only be done at "synchronization points". These synchronization points + /// are positions in the data stream that are created by hard flushes on the + /// corresponding reverse filters, in this example ZlibCompressor. This is + /// useful when zlib compressed data is moved across a network in packets + /// and compression state is preserved across packets, as in the SSH2 protocol. + virtual bool Flush(bool hardFlush, int propagation=-1, bool blocking=true); + + /// \brief Marks the end of a series of messages, with signal propagation + /// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true if the message was successful, false otherwise + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + virtual bool MessageSeriesEnd(int propagation=-1, bool blocking=true); + + /// \brief Set propagation of automatically generated and transferred signals + /// \param propagation then new value + /// \details Setting propagation to 0 means do not automatically generate signals. Setting + /// propagation to -1 means unlimited propagation. + virtual void SetAutoSignalPropagation(int propagation) + {CRYPTOPP_UNUSED(propagation);} + + /// \brief Retrieve automatic signal propagation value + /// \return the number of attached transformations the signal is propagated to. 0 indicates + /// the signal is only witnessed by this object + virtual int GetAutoSignalPropagation() const {return 0;} +public: + + /// \name RETRIEVAL OF ONE MESSAGE + //@{ + + /// \brief Provides the number of bytes ready for retrieval + /// \return the number of bytes ready for retrieval + /// \details The number of bytes available are dependent on the source. If an exact value is + /// available, then the exact value is returned. The exact value can include 0 if the source + /// is exhausted. + /// \details Some stream-based sources do not allow seeking() on the underlying stream, such + /// as some FileSource(). If the stream does not allow seeking() then MaxRetrievable() + /// returns LWORD_MAX to indicate there are still bytes to be retrieved. + virtual lword MaxRetrievable() const; + + /// \brief Determines whether bytes are ready for retrieval + /// \return true if bytes are available for retrieval, false otherwise + virtual bool AnyRetrievable() const; + + /// \brief Retrieve a 8-bit byte + /// \param outByte the 8-bit value to be retrieved + /// \return the number of bytes consumed during the call. + /// \details Use the return value of Get to detect short reads. + virtual size_t Get(byte &outByte); + + /// \brief Retrieve a block of bytes + /// \param outString a block of bytes + /// \param getMax the number of bytes to Get + /// \return the number of bytes consumed during the call. + /// \details Use the return value of Get to detect short reads. + virtual size_t Get(byte *outString, size_t getMax); + + /// \brief Peek a 8-bit byte + /// \param outByte the 8-bit value to be retrieved + /// \return the number of bytes read during the call. + /// \details Peek does not remove bytes from the object. Use the return value of + /// Get() to detect short reads. + virtual size_t Peek(byte &outByte) const; + + /// \brief Peek a block of bytes + /// \param outString a block of bytes + /// \param peekMax the number of bytes to Peek + /// \return the number of bytes read during the call. + /// \details Peek does not remove bytes from the object. Use the return value of + /// Peek() to detect short reads. + virtual size_t Peek(byte *outString, size_t peekMax) const; + + /// \brief Retrieve a 16-bit word + /// \param value the 16-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Use the return value of GetWord16() to detect short reads. + size_t GetWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER); + + /// \brief Retrieve a 32-bit word + /// \param value the 32-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Use the return value of GetWord32() to detect short reads. + size_t GetWord32(word32 &value, ByteOrder order=BIG_ENDIAN_ORDER); + + /// \brief Retrieve a 64-bit word + /// \param value the 64-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Use the return value of GetWord64() to detect short reads. + /// \since Crypto++ 8.3 + size_t GetWord64(word64 &value, ByteOrder order=BIG_ENDIAN_ORDER); + + /// \brief Peek a 16-bit word + /// \param value the 16-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Peek does not consume bytes in the stream. Use the return value + /// of PeekWord16() to detect short reads. + size_t PeekWord16(word16 &value, ByteOrder order=BIG_ENDIAN_ORDER) const; + + /// \brief Peek a 32-bit word + /// \param value the 32-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Peek does not consume bytes in the stream. Use the return value + /// of PeekWord32() to detect short reads. + size_t PeekWord32(word32 &value, ByteOrder order=BIG_ENDIAN_ORDER) const; + + /// \brief Peek a 64-bit word + /// \param value the 64-bit value to be retrieved + /// \param order the ByteOrder of the value to be processed. + /// \return the number of bytes consumed during the call. + /// \details Peek does not consume bytes in the stream. Use the return value + /// of PeekWord64() to detect short reads. + /// \since Crypto++ 8.3 + size_t PeekWord64(word64 &value, ByteOrder order=BIG_ENDIAN_ORDER) const; + + /// move transferMax bytes of the buffered output to target as input + + /// \brief Transfer bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param transferMax the number of bytes to transfer + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes transferred during the call. + /// \details TransferTo removes bytes from this object and moves them to the destination. + /// \details The function always returns transferMax. If an accurate count is needed, then use TransferTo2(). + lword TransferTo(BufferedTransformation &target, lword transferMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) + {TransferTo2(target, transferMax, channel); return transferMax;} + + /// \brief Discard skipMax bytes from the output buffer + /// \param skipMax the number of bytes to discard + /// \details Skip() discards bytes from the output buffer, which is the AttachedTransformation(), if present. + /// The function always returns the parameter skipMax. + /// \details If you want to skip bytes from a Source, then perform the following. + ///
  StringSource ss(str, false, new Redirector(TheBitBucket()));
+		///   ss.Pump(10);    // Skip 10 bytes from Source
+		///   ss.Detach(new FilterChain(...));
+		///   ss.PumpAll();
+		/// 
+ virtual lword Skip(lword skipMax=LWORD_MAX); + + /// \brief Copy bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param copyMax the number of bytes to copy + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes copied during the call. + /// \details CopyTo copies bytes from this object to the destination. The bytes are not removed from this object. + /// \details The function always returns copyMax. If an accurate count is needed, then use CopyRangeTo2(). + lword CopyTo(BufferedTransformation &target, lword copyMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) const + {return CopyRangeTo(target, 0, copyMax, channel);} + + /// \brief Copy bytes from this object using an index to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param position the 0-based index of the byte stream to begin the copying + /// \param copyMax the number of bytes to copy + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes copied during the call. + /// \details CopyTo copies bytes from this object to the destination. The bytes remain in this + /// object. Copying begins at the index position in the current stream, and not from an absolute + /// position in the stream. + /// \details The function returns the new position in the stream after transferring the bytes starting at the index. + lword CopyRangeTo(BufferedTransformation &target, lword position, lword copyMax=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL) const + {lword i = position; CopyRangeTo2(target, i, i+copyMax, channel); return i-position;} + //@} + + /// \name RETRIEVAL OF MULTIPLE MESSAGES + //@{ + + /// \brief Provides the number of bytes ready for retrieval + /// \return the number of bytes ready for retrieval + virtual lword TotalBytesRetrievable() const; + + /// \brief Provides the number of meesages processed by this object + /// \return the number of meesages processed by this object + /// \details NumberOfMessages returns number of times MessageEnd() has been + /// received minus messages retrieved or skipped + virtual unsigned int NumberOfMessages() const; + + /// \brief Determines if any messages are available for retrieval + /// \return true if NumberOfMessages() > 0, false otherwise + /// \details AnyMessages returns true if NumberOfMessages() > 0 + virtual bool AnyMessages() const; + + /// \brief Start retrieving the next message + /// \return true if a message is ready for retrieval + /// \details GetNextMessage() returns true if a message is ready for retrieval; false + /// if no more messages exist or this message is not completely retrieved. + virtual bool GetNextMessage(); + + /// \brief Skip a number of meessages + /// \param count number of messages to skip + /// \return 0 if the requested number of messages was skipped, non-0 otherwise + /// \details SkipMessages() skips count number of messages. If there is an AttachedTransformation() + /// then SkipMessages() is called on the attached transformation. If there is no attached + /// transformation, then count number of messages are sent to TheBitBucket() using TransferMessagesTo(). + virtual unsigned int SkipMessages(unsigned int count=UINT_MAX); + + /// \brief Transfer messages from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param count the number of messages to transfer + /// \param channel the channel on which the transfer should occur + /// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred) + /// \details TransferMessagesTo2() removes messages from this object and moves them to the destination. + /// If all bytes are not transferred for a message, then processing stops and the number of remaining + /// bytes is returned. TransferMessagesTo() does not proceed to the next message. + /// \details A return value of 0 indicates all messages were successfully transferred. + unsigned int TransferMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) + {TransferMessagesTo2(target, count, channel); return count;} + + /// \brief Copy messages from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param count the number of messages to copy + /// \param channel the channel on which the copy should occur + /// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred) + /// \details CopyMessagesTo copies messages from this object to the destination. + /// If all bytes are not transferred for a message, then processing stops and the number of remaining + /// bytes is returned. CopyMessagesTo() does not proceed to the next message. + /// \details A return value of 0 indicates all messages were successfully copied. + unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const; + + /// \brief Skip all messages in the series + virtual void SkipAll(); + + /// \brief Transfer all bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param channel the channel on which the transfer should occur + /// \details TransferMessagesTo2() removes messages from this object and moves them to the destination. + /// Internally TransferAllTo() calls TransferAllTo2(). + void TransferAllTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL) + {TransferAllTo2(target, channel);} + + /// \brief Copy messages from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param channel the channel on which the transfer should occur + /// \details CopyAllTo copies messages from this object and copies them to the destination. + void CopyAllTo(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL) const; + + /// \brief Retrieve the next message in a series + /// \return true if a message was retrieved, false otherwise + /// \details Internally, the base class implementation returns false. + virtual bool GetNextMessageSeries() {return false;} + /// \brief Provides the number of messages in a series + /// \return the number of messages in this series + virtual unsigned int NumberOfMessagesInThisSeries() const {return NumberOfMessages();} + /// \brief Provides the number of messages in a series + /// \return the number of messages in this series + virtual unsigned int NumberOfMessageSeries() const {return 0;} + //@} + + /// \name NON-BLOCKING TRANSFER OF OUTPUT + //@{ + + // upon return, byteCount contains number of bytes that have finished being transferred, + // and returns the number of bytes left in the current transfer block + + /// \brief Transfer bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param byteCount the number of bytes to transfer + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the transfer block (i.e., bytes not transferred) + /// \details TransferTo2() removes bytes from this object and moves them to the destination. + /// Transfer begins at the index position in the current stream, and not from an absolute + /// position in the stream. + /// \details byteCount is an \a IN and \a OUT parameter. When the call is made, + /// byteCount is the requested size of the transfer. When the call returns, byteCount is + /// the number of bytes that were transferred. + virtual size_t TransferTo2(BufferedTransformation &target, lword &byteCount, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) =0; + + // upon return, begin contains the start position of data yet to be finished copying, + // and returns the number of bytes left in the current transfer block + + /// \brief Copy bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param begin the 0-based index of the first byte to copy in the stream + /// \param end the 0-based index of the last byte to copy in the stream + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the copy block (i.e., bytes not copied) + /// \details CopyRangeTo2 copies bytes from this object to the destination. The bytes are not + /// removed from this object. Copying begins at the index position in the current stream, and + /// not from an absolute position in the stream. + /// \details begin is an \a IN and \a OUT parameter. When the call is made, begin is the + /// starting position of the copy. When the call returns, begin is the position of the first + /// byte that was \a not copied (which may be different than end). begin can be used for + /// subsequent calls to CopyRangeTo2(). + virtual size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const =0; + + // upon return, messageCount contains number of messages that have finished being transferred, + // and returns the number of bytes left in the current transfer block + + /// \brief Transfer messages from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param messageCount the number of messages to transfer + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred) + /// \details TransferMessagesTo2() removes messages from this object and moves them to the destination. + /// \details messageCount is an \a IN and \a OUT parameter. When the call is made, messageCount is the + /// the number of messages requested to be transferred. When the call returns, messageCount is the + /// number of messages actually transferred. + size_t TransferMessagesTo2(BufferedTransformation &target, unsigned int &messageCount, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + + // returns the number of bytes left in the current transfer block + + /// \brief Transfer all bytes from this object to another BufferedTransformation + /// \param target the destination BufferedTransformation + /// \param channel the channel on which the transfer should occur + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain in the current transfer block (i.e., bytes not transferred) + /// \details TransferMessagesTo2() removes messages from this object and moves them to the destination. + size_t TransferAllTo2(BufferedTransformation &target, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + //@} + + /// \name CHANNELS + //@{ + /// \brief Exception thrown when a filter does not support named channels + struct NoChannelSupport : public NotImplemented + {NoChannelSupport(const std::string &name) : NotImplemented(name + ": this object doesn't support multiple channels") {}}; + /// \brief Exception thrown when a filter does not recognize a named channel + struct InvalidChannelName : public InvalidArgument + {InvalidChannelName(const std::string &name, const std::string &channel) : InvalidArgument(name + ": unexpected channel name \"" + channel + "\"") {}}; + + /// \brief Input a byte for processing on a channel + /// \param channel the channel to process the data. + /// \param inByte the 8-bit byte (octet) to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPut(const std::string &channel, byte inByte, bool blocking=true) + {return ChannelPut(channel, &inByte, 1, blocking);} + + /// \brief Input a byte buffer for processing on a channel + /// \param channel the channel to process the data + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param blocking specifies whether the object should block when processing input + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPut(const std::string &channel, const byte *inString, size_t length, bool blocking=true) + {return ChannelPut2(channel, inString, length, 0, blocking);} + + /// \brief Input multiple bytes that may be modified by callee on a channel + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param blocking specifies whether the object should block when processing input + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPutModifiable(const std::string &channel, byte *inString, size_t length, bool blocking=true) + {return ChannelPutModifiable2(channel, inString, length, 0, blocking);} + + /// \brief Input a 16-bit word for processing on a channel. + /// \param channel the channel to process the data. + /// \param value the 16-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPutWord16(const std::string &channel, word16 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// \brief Input a 32-bit word for processing on a channel. + /// \param channel the channel to process the data. + /// \param value the 32-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPutWord32(const std::string &channel, word32 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// \brief Input a 64-bit word for processing on a channel. + /// \param channel the channel to process the data. + /// \param value the 64-bit value to be processed. + /// \param order the ByteOrder of the value to be processed. + /// \param blocking specifies whether the object should block when processing input. + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + size_t ChannelPutWord64(const std::string &channel, word64 value, ByteOrder order=BIG_ENDIAN_ORDER, bool blocking=true); + + /// \brief Signal the end of a message + /// \param channel the channel to process the data. + /// \param propagation the number of attached transformations the ChannelMessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return 0 indicates all bytes were processed during the call. Non-0 indicates the + /// number of bytes that were not processed. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + bool ChannelMessageEnd(const std::string &channel, int propagation=-1, bool blocking=true) + {return !!ChannelPut2(channel, NULLPTR, 0, propagation < 0 ? -1 : propagation+1, blocking);} + + /// \brief Input multiple bytes for processing and signal the end of a message + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param propagation the number of attached transformations the ChannelPutMessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + size_t ChannelPutMessageEnd(const std::string &channel, const byte *inString, size_t length, int propagation=-1, bool blocking=true) + {return ChannelPut2(channel, inString, length, propagation < 0 ? -1 : propagation+1, blocking);} + + /// \brief Request space which can be written into by the caller + /// \param channel the channel to process the data + /// \param size the requested size of the buffer + /// \return a pointer to a memory block with length size + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink(), cannot create a space because its fixed. In the case of + /// an ArraySink(), the pointer to the array is returned and the size is remaining size. + virtual byte * ChannelCreatePutSpace(const std::string &channel, size_t &size); + + /// \brief Input multiple bytes for processing on a channel. + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + virtual size_t ChannelPut2(const std::string &channel, const byte *inString, size_t length, int messageEnd, bool blocking); + + /// \brief Input multiple bytes that may be modified by callee on a channel + /// \param channel the channel to process the data + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + virtual size_t ChannelPutModifiable2(const std::string &channel, byte *inString, size_t length, int messageEnd, bool blocking); + + /// \brief Flush buffered input and/or output on a channel + /// \param channel the channel to flush the data + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the ChannelFlush() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true of the Flush was successful + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + virtual bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true); + + /// \brief Marks the end of a series of messages on a channel + /// \param channel the channel to signal the end of a series of messages + /// \param propagation the number of attached transformations the ChannelMessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true if the message was successful, false otherwise + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + virtual bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true); + + /// \brief Sets the default retrieval channel + /// \param channel the channel to signal the end of a series of messages + /// \note this function may not be implemented in all objects that should support it. + virtual void SetRetrievalChannel(const std::string &channel); + //@} + + /// \name ATTACHMENT + /// \details Some BufferedTransformation objects (e.g. Filter objects) allow other BufferedTransformation objects to be + /// attached. When this is done, the first object instead of buffering its output, sends that output to the attached + /// object as input. The entire attachment chain is deleted when the anchor object is destructed. + + //@{ + /// \brief Determines whether the object allows attachment + /// \return true if the object allows an attachment, false otherwise + /// \details Sources and Filters will returns true, while Sinks and other objects will return false. + virtual bool Attachable() {return false;} + + /// \brief Returns the object immediately attached to this object + /// \return the attached transformation + /// \details AttachedTransformation() returns NULL if there is no attachment. The non-const + /// version of AttachedTransformation() always returns NULL. + virtual BufferedTransformation *AttachedTransformation() {CRYPTOPP_ASSERT(!Attachable()); return NULLPTR;} + + /// \brief Returns the object immediately attached to this object + /// \return the attached transformation + /// \details AttachedTransformation() returns NULL if there is no attachment. The non-const + /// version of AttachedTransformation() always returns NULL. + virtual const BufferedTransformation *AttachedTransformation() const + {return const_cast(this)->AttachedTransformation();} + + /// \brief Delete the current attachment chain and attach a new one + /// \param newAttachment the new BufferedTransformation to attach + /// \throw NotImplemented + /// \details Detach() deletes the current attachment chain and replace it with an optional newAttachment + /// \details If a derived class does not override Detach(), then the base class throws + /// NotImplemented. + virtual void Detach(BufferedTransformation *newAttachment = NULLPTR) { + CRYPTOPP_UNUSED(newAttachment); CRYPTOPP_ASSERT(!Attachable()); + throw NotImplemented("BufferedTransformation: this object is not attachable"); + } + + /// \brief Add newAttachment to the end of attachment chain + /// \param newAttachment the attachment to add to the end of the chain + virtual void Attach(BufferedTransformation *newAttachment); + //@} + +protected: + /// \brief Decrements the propagation count while clamping at 0 + /// \return the decremented propagation or 0 + static int DecrementPropagation(int propagation) + {return propagation != 0 ? propagation - 1 : 0;} + +private: + // for ChannelPutWord16, ChannelPutWord32 and ChannelPutWord64, + // to ensure the buffer isn't deallocated before non-blocking + // operation completes + byte m_buf[8]; +}; + +/// \brief An input discarding BufferedTransformation +/// \return a reference to a BufferedTransformation object that discards all input +CRYPTOPP_DLL BufferedTransformation & TheBitBucket(); + +/// \brief Interface for crypto material +/// \details CryptoMaterial() is an interface for crypto material, such as +/// public keys, private keys and crypto parameters. Derived classes generally +/// do not offer public methods such as GenerateRandom() and +/// GenerateRandomWithKeySize(). +/// \sa GeneratableCryptoMaterial() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CryptoMaterial : public NameValuePairs +{ +public: + /// Exception thrown when invalid crypto material is detected + class CRYPTOPP_DLL InvalidMaterial : public InvalidDataFormat + { + public: + explicit InvalidMaterial(const std::string &s) : InvalidDataFormat(s) {} + }; + + virtual ~CryptoMaterial() {} + + /// \brief Assign values to this object + /// \details This function can be used to create a public key from a private key. + virtual void AssignFrom(const NameValuePairs &source) =0; + + /// \brief Check this object for errors + /// \param rng a RandomNumberGenerator for objects which use randomized testing + /// \param level the level of thoroughness + /// \return true if the tests succeed, false otherwise + /// \details There are four levels of thoroughness: + ///
    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other operations correctly + ///
  • 2 - ensure this object will function correctly, and perform reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may take a long time + ///
+ /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can be used for level 0. + /// Level 1 may not check for weak keys and such. Levels 2 and 3 are recommended. + /// \sa ThrowIfInvalid() + virtual bool Validate(RandomNumberGenerator &rng, unsigned int level) const =0; + + /// \brief Check this object for errors + /// \param rng a RandomNumberGenerator for objects which use randomized testing + /// \param level the level of thoroughness + /// \throw InvalidMaterial + /// \details Internally, ThrowIfInvalid() calls Validate() and throws InvalidMaterial() if validation fails. + /// \sa Validate() + virtual void ThrowIfInvalid(RandomNumberGenerator &rng, unsigned int level) const + {if (!Validate(rng, level)) throw InvalidMaterial("CryptoMaterial: this object contains invalid values");} + + /// \brief Saves a key to a BufferedTransformation + /// \param bt the destination BufferedTransformation + /// \throw NotImplemented + /// \details Save() writes the material to a BufferedTransformation. + /// \details If the material is a key, then the key is written with ASN.1 DER encoding. The key + /// includes an object identifier with an algorithm id, like a subjectPublicKeyInfo. + /// \details A "raw" key without the "key info" can be saved using a key's DEREncode() method. + /// \details If a derived class does not override Save(), then the base class throws + /// NotImplemented(). + virtual void Save(BufferedTransformation &bt) const + {CRYPTOPP_UNUSED(bt); throw NotImplemented("CryptoMaterial: this object does not support saving");} + + /// \brief Loads a key from a BufferedTransformation + /// \param bt the source BufferedTransformation + /// \throw KeyingErr + /// \details Load() attempts to read material from a BufferedTransformation. If the + /// material is a key that was generated outside the library, then the following + /// usually applies: + ///
    + ///
  • the key should be ASN.1 BER encoded + ///
  • the key should be a "key info" + ///
+ /// \details "key info" means the key should have an object identifier with an algorithm id, + /// like a subjectPublicKeyInfo. + /// \details To read a "raw" key without the "key info", then call the key's BERDecode() method. + /// \note Load() generally does not check that the key is valid. Call Validate(), if needed. + virtual void Load(BufferedTransformation &bt) + {CRYPTOPP_UNUSED(bt); throw NotImplemented("CryptoMaterial: this object does not support loading");} + + /// \brief Determines whether the object supports precomputation + /// \return true if the object supports precomputation, false otherwise + /// \sa Precompute() + virtual bool SupportsPrecomputation() const {return false;} + + /// \brief Perform precomputation + /// \param precomputationStorage the suggested number of objects for the precompute table + /// \throw NotImplemented + /// \details The exact semantics of Precompute() varies, but it typically means calculate + /// a table of n objects that can be used later to speed up computation. + /// \details If a derived class does not override Precompute(), then the base class throws + /// NotImplemented. + /// \sa SupportsPrecomputation(), LoadPrecomputation(), SavePrecomputation() + virtual void Precompute(unsigned int precomputationStorage) { + CRYPTOPP_UNUSED(precomputationStorage); CRYPTOPP_ASSERT(!SupportsPrecomputation()); + throw NotImplemented("CryptoMaterial: this object does not support precomputation"); + } + + /// \brief Retrieve previously saved precomputation + /// \param storedPrecomputation BufferedTransformation with the saved precomputation + /// \throw NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + virtual void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + {CRYPTOPP_UNUSED(storedPrecomputation); CRYPTOPP_ASSERT(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");} + + /// \brief Save precomputation for later use + /// \param storedPrecomputation BufferedTransformation to write the precomputation + /// \throw NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + virtual void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + {CRYPTOPP_UNUSED(storedPrecomputation); CRYPTOPP_ASSERT(!SupportsPrecomputation()); throw NotImplemented("CryptoMaterial: this object does not support precomputation");} + + /// \brief Perform a quick sanity check + /// \details DoQuickSanityCheck() is for internal library use, and it should not be called by library users. + void DoQuickSanityCheck() const {ThrowIfInvalid(NullRNG(), 0);} + +#if defined(__SUNPRO_CC) + // Sun Studio 11/CC 5.8 workaround: it generates incorrect code + // when casting to an empty virtual base class. JW, 2018: It is + // still a problem in Sun Studio 12.6/CC 5.15 on i386. Just enable + // it everywhere in case it affects SPARC (which we don't test). + char m_sunCCworkaround; +#endif +}; + +/// \brief Interface for crypto material +/// \details GeneratableCryptoMaterial() is an interface for crypto material, +/// such as private keys and crypto parameters. Derived classes offer public +/// methods such as GenerateRandom() and GenerateRandomWithKeySize(). +/// \sa CryptoMaterial() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE GeneratableCryptoMaterial : virtual public CryptoMaterial +{ +public: + virtual ~GeneratableCryptoMaterial() {} + + /// \brief Generate a random key or crypto parameters + /// \param rng a RandomNumberGenerator to produce keying material + /// \param params additional initialization parameters + /// \throw KeyingErr if a key can't be generated or algorithm parameters are invalid + /// \details If a derived class does not override GenerateRandom(), then the base class throws + /// NotImplemented. + virtual void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs) { + CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(params); + throw NotImplemented("GeneratableCryptoMaterial: this object does not support key/parameter generation"); + } + + /// \brief Generate a random key or crypto parameters + /// \param rng a RandomNumberGenerator to produce keying material + /// \param keySize the size of the key, in bits + /// \throw KeyingErr if a key can't be generated or algorithm parameters are invalid + /// \details GenerateRandomWithKeySize calls GenerateRandom() with a NameValuePairs + /// object with only "KeySize" + void GenerateRandomWithKeySize(RandomNumberGenerator &rng, unsigned int keySize); +}; + +/// \brief Interface for public keys +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PublicKey : virtual public CryptoMaterial +{ +}; + +/// \brief Interface for private keys +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PrivateKey : public GeneratableCryptoMaterial +{ +}; + +/// \brief Interface for crypto parameters +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CryptoParameters : public GeneratableCryptoMaterial +{ +}; + +/// \brief Interface for certificates +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Certificate : virtual public CryptoMaterial +{ +}; + +/// \brief Interface for asymmetric algorithms +/// \details BERDecode() and DEREncode() were removed under Issue 569 +/// and Commit 9b174e84de7a. Programs should use AccessMaterial().Load(bt) +/// or GetMaterial().Save(bt) instead. +/// \sa Issue 569 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AsymmetricAlgorithm : public Algorithm +{ +public: + virtual ~AsymmetricAlgorithm() {} + + /// \brief Retrieves a reference to CryptoMaterial + /// \return a reference to the crypto material + virtual CryptoMaterial & AccessMaterial() =0; + + /// \brief Retrieves a reference to CryptoMaterial + /// \return a const reference to the crypto material + virtual const CryptoMaterial & GetMaterial() const =0; + +#if 0 + /// \brief Loads this object from a BufferedTransformation + /// \param bt a BufferedTransformation object + /// \details Use of BERDecode() changed to Load() at Issue 569. + /// \deprecated for backwards compatibility, calls AccessMaterial().Load(bt) + void BERDecode(BufferedTransformation &bt) + {AccessMaterial().Load(bt);} + + /// \brief Saves this object to a BufferedTransformation + /// \param bt a BufferedTransformation object + /// \details Use of DEREncode() changed to Save() at Issue 569. + /// \deprecated for backwards compatibility, calls GetMaterial().Save(bt) + void DEREncode(BufferedTransformation &bt) const + {GetMaterial().Save(bt);} +#endif +}; + +/// \brief Interface for asymmetric algorithms using public keys +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PublicKeyAlgorithm : public AsymmetricAlgorithm +{ +public: + virtual ~PublicKeyAlgorithm() {} + + // VC60 workaround: no co-variant return type + + /// \brief Retrieves a reference to a Public Key + /// \return a reference to the public key + CryptoMaterial & AccessMaterial() + {return AccessPublicKey();} + /// \brief Retrieves a reference to a Public Key + /// \return a const reference the public key + const CryptoMaterial & GetMaterial() const + {return GetPublicKey();} + + /// \brief Retrieves a reference to a Public Key + /// \return a reference to the public key + virtual PublicKey & AccessPublicKey() =0; + /// \brief Retrieves a reference to a Public Key + /// \return a const reference the public key + virtual const PublicKey & GetPublicKey() const + {return const_cast(this)->AccessPublicKey();} +}; + +/// \brief Interface for asymmetric algorithms using private keys +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PrivateKeyAlgorithm : public AsymmetricAlgorithm +{ +public: + virtual ~PrivateKeyAlgorithm() {} + + /// \brief Retrieves a reference to a Private Key + /// \return a reference the private key + CryptoMaterial & AccessMaterial() {return AccessPrivateKey();} + /// \brief Retrieves a reference to a Private Key + /// \return a const reference the private key + const CryptoMaterial & GetMaterial() const {return GetPrivateKey();} + + /// \brief Retrieves a reference to a Private Key + /// \return a reference the private key + virtual PrivateKey & AccessPrivateKey() =0; + /// \brief Retrieves a reference to a Private Key + /// \return a const reference the private key + virtual const PrivateKey & GetPrivateKey() const {return const_cast(this)->AccessPrivateKey();} +}; + +/// \brief Interface for key agreement algorithms +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE KeyAgreementAlgorithm : public AsymmetricAlgorithm +{ +public: + virtual ~KeyAgreementAlgorithm() {} + + /// \brief Retrieves a reference to Crypto Parameters + /// \return a reference the crypto parameters + CryptoMaterial & AccessMaterial() {return AccessCryptoParameters();} + /// \brief Retrieves a reference to Crypto Parameters + /// \return a const reference the crypto parameters + const CryptoMaterial & GetMaterial() const {return GetCryptoParameters();} + + /// \brief Retrieves a reference to Crypto Parameters + /// \return a reference the crypto parameters + virtual CryptoParameters & AccessCryptoParameters() =0; + /// \brief Retrieves a reference to Crypto Parameters + /// \return a const reference the crypto parameters + virtual const CryptoParameters & GetCryptoParameters() const {return const_cast(this)->AccessCryptoParameters();} +}; + +/// \brief Interface for public-key encryptors and decryptors +/// \details This class provides an interface common to encryptors and decryptors +/// for querying their plaintext and ciphertext lengths. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_CryptoSystem +{ +public: + virtual ~PK_CryptoSystem() {} + + /// \brief Provides the maximum length of plaintext for a given ciphertext length + /// \return the maximum size of the plaintext, in bytes + /// \details This function returns 0 if ciphertextLength is not valid (too long or too short). + virtual size_t MaxPlaintextLength(size_t ciphertextLength) const =0; + + /// \brief Calculate the length of ciphertext given length of plaintext + /// \return the maximum size of the ciphertext, in bytes + /// \details This function returns 0 if plaintextLength is not valid (too long). + virtual size_t CiphertextLength(size_t plaintextLength) const =0; + + /// \brief Determines whether this object supports the use of a named parameter + /// \param name the name of the parameter + /// \return true if the parameter name is supported, false otherwise + /// \details Some possible parameter names: EncodingParameters(), KeyDerivationParameters() + /// and others Parameters listed in argnames.h + virtual bool ParameterSupported(const char *name) const =0; + + /// \brief Provides the fixed ciphertext length, if one exists + /// \return the fixed ciphertext length if one exists, otherwise 0 + /// \details "Fixed" here means length of ciphertext does not depend on length of plaintext. + /// In this case, it usually does depend on the key length. + virtual size_t FixedCiphertextLength() const {return 0;} + + /// \brief Provides the maximum plaintext length given a fixed ciphertext length + /// \return maximum plaintext length given the fixed ciphertext length, if one exists, + /// otherwise return 0. + /// \details FixedMaxPlaintextLength(0 returns the maximum plaintext length given the fixed ciphertext + /// length, if one exists, otherwise return 0. + virtual size_t FixedMaxPlaintextLength() const {return 0;} +}; + +/// \brief Interface for public-key encryptors +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Encryptor : public PK_CryptoSystem, public PublicKeyAlgorithm +{ +public: + /// \brief Exception thrown when trying to encrypt plaintext of invalid length + class CRYPTOPP_DLL InvalidPlaintextLength : public Exception + { + public: + InvalidPlaintextLength() : Exception(OTHER_ERROR, "PK_Encryptor: invalid plaintext length") {} + }; + + /// \brief Encrypt a byte string + /// \param rng a RandomNumberGenerator derived class + /// \param plaintext the plaintext byte buffer + /// \param plaintextLength the size of the plaintext byte buffer + /// \param ciphertext a byte buffer to hold the encrypted string + /// \param parameters a set of NameValuePairs to initialize this object + /// \pre CiphertextLength(plaintextLength) != 0 ensures the plaintext isn't too large + /// \pre COUNTOF(ciphertext) == CiphertextLength(plaintextLength) ensures the output + /// byte buffer is large enough. + /// \sa PK_Decryptor + virtual void Encrypt(RandomNumberGenerator &rng, + const byte *plaintext, size_t plaintextLength, + byte *ciphertext, const NameValuePairs ¶meters = g_nullNameValuePairs) const =0; + + /// \brief Create a new encryption filter + /// \param rng a RandomNumberGenerator derived class + /// \param attachment an attached transformation + /// \param parameters a set of NameValuePairs to initialize this object + /// \details \p attachment can be \p NULL. The caller is responsible for deleting the returned pointer. + /// Encoding parameters should be passed in the "EP" channel. + virtual BufferedTransformation * CreateEncryptionFilter(RandomNumberGenerator &rng, + BufferedTransformation *attachment=NULLPTR, const NameValuePairs ¶meters = g_nullNameValuePairs) const; +}; + +/// \brief Interface for public-key decryptors +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Decryptor : public PK_CryptoSystem, public PrivateKeyAlgorithm +{ +public: + virtual ~PK_Decryptor() {} + + /// \brief Decrypt a byte string + /// \param rng a RandomNumberGenerator derived class + /// \param ciphertext the encrypted byte buffer + /// \param ciphertextLength the size of the encrypted byte buffer + /// \param plaintext a byte buffer to hold the decrypted string + /// \param parameters a set of NameValuePairs to initialize this object + /// \return the result of the decryption operation + /// \details If DecodingResult::isValidCoding is true, then DecodingResult::messageLength + /// is valid and holds the actual length of the plaintext recovered. The result is undefined + /// if decryption failed. If DecodingResult::isValidCoding is false, then DecodingResult::messageLength + /// is undefined. + /// \pre COUNTOF(plaintext) == MaxPlaintextLength(ciphertextLength) ensures the output + /// byte buffer is large enough + /// \sa PK_Encryptor + virtual DecodingResult Decrypt(RandomNumberGenerator &rng, + const byte *ciphertext, size_t ciphertextLength, + byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const =0; + + /// \brief Create a new decryption filter + /// \param rng a RandomNumberGenerator derived class + /// \param attachment an attached transformation + /// \param parameters a set of NameValuePairs to initialize this object + /// \return the newly created decryption filter + /// \note the caller is responsible for deleting the returned pointer + virtual BufferedTransformation * CreateDecryptionFilter(RandomNumberGenerator &rng, + BufferedTransformation *attachment=NULLPTR, const NameValuePairs ¶meters = g_nullNameValuePairs) const; + + /// \brief Decrypt a fixed size ciphertext + /// \param rng a RandomNumberGenerator derived class + /// \param ciphertext the encrypted byte buffer + /// \param plaintext a byte buffer to hold the decrypted string + /// \param parameters a set of NameValuePairs to initialize this object + /// \return the result of the decryption operation + /// \details If DecodingResult::isValidCoding is true, then DecodingResult::messageLength + /// is valid and holds the actual length of the plaintext recovered. The result is undefined + /// if decryption failed. If DecodingResult::isValidCoding is false, then DecodingResult::messageLength + /// is undefined. + /// \pre COUNTOF(plaintext) == MaxPlaintextLength(ciphertextLength) ensures the output + /// byte buffer is large enough + /// \sa PK_Encryptor + DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *ciphertext, byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const + {return Decrypt(rng, ciphertext, FixedCiphertextLength(), plaintext, parameters);} +}; + +/// \brief Interface for public-key signers and verifiers +/// \details This class provides an interface common to signers and verifiers for querying scheme properties +/// \sa DL_SignatureSchemeBase, TF_SignatureSchemeBase, DL_SignerBase, TF_SignerBase +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_SignatureScheme +{ +public: + /// \brief Exception throw when the private or public key has a length that can't be used + /// \details InvalidKeyLength() may be thrown by any function in this class if the private + /// or public key has a length that can't be used + class CRYPTOPP_DLL InvalidKeyLength : public Exception + { + public: + InvalidKeyLength(const std::string &message) : Exception(OTHER_ERROR, message) {} + }; + + /// \brief Exception throw when the private or public key is too short to sign or verify + /// \details KeyTooShort() may be thrown by any function in this class if the private or public + /// key is too short to sign or verify anything + class CRYPTOPP_DLL KeyTooShort : public InvalidKeyLength + { + public: + KeyTooShort() : InvalidKeyLength("PK_Signer: key too short for this signature scheme") {} + }; + + virtual ~PK_SignatureScheme() {} + + /// \brief Provides the signature length if it only depends on the key + /// \return the signature length if it only depends on the key, in bytes + /// \details SignatureLength() returns the signature length if it only depends on the key, otherwise 0. + virtual size_t SignatureLength() const =0; + + /// \brief Provides the maximum signature length produced given the length of the recoverable message part + /// \param recoverablePartLength the length of the recoverable message part, in bytes + /// \return the maximum signature length produced for a given length of recoverable message part, in bytes + /// \details MaxSignatureLength() returns the maximum signature length produced given the length of the + /// recoverable message part. + virtual size_t MaxSignatureLength(size_t recoverablePartLength = 0) const + {CRYPTOPP_UNUSED(recoverablePartLength); return SignatureLength();} + + /// \brief Provides the length of longest message that can be recovered + /// \return the length of longest message that can be recovered, in bytes + /// \details MaxRecoverableLength() returns the length of longest message that can be recovered, or 0 if + /// this signature scheme does not support message recovery. + virtual size_t MaxRecoverableLength() const =0; + + /// \brief Provides the length of longest message that can be recovered from a signature of given length + /// \param signatureLength the length of the signature, in bytes + /// \return the length of longest message that can be recovered from a signature of given length, in bytes + /// \details MaxRecoverableLengthFromSignatureLength() returns the length of longest message that can be + /// recovered from a signature of given length, or 0 if this signature scheme does not support message + /// recovery. + virtual size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const =0; + + /// \brief Determines whether a signature scheme requires a random number generator + /// \return true if the signature scheme requires a RandomNumberGenerator() to sign + /// \details if IsProbabilistic() returns false, then NullRNG() can be passed to functions that take + /// RandomNumberGenerator(). + virtual bool IsProbabilistic() const =0; + + /// \brief Determines whether the non-recoverable message part can be signed + /// \return true if the non-recoverable message part can be signed + virtual bool AllowNonrecoverablePart() const =0; + + /// \brief Determines whether the signature must be input before the message + /// \return true if the signature must be input before the message during verifcation + /// \details if SignatureUpfront() returns true, then you must input the signature before the message + /// during verification. Otherwise you can input the signature at anytime. + virtual bool SignatureUpfront() const {return false;} + + /// \brief Determines whether the recoverable part must be input before the non-recoverable part + /// \return true if the recoverable part must be input before the non-recoverable part during signing + /// \details RecoverablePartFirst() determines whether you must input the recoverable part before the + /// non-recoverable part during signing + virtual bool RecoverablePartFirst() const =0; +}; + +/// \brief Interface for accumulating messages to be signed or verified +/// \details Only Update() should be called from the PK_MessageAccumulator() class. No other functions +/// inherited from HashTransformation, like DigestSize() and TruncatedFinal(), should be called. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_MessageAccumulator : public HashTransformation +{ +public: + /// \warning DigestSize() should not be called on PK_MessageAccumulator + unsigned int DigestSize() const + {throw NotImplemented("PK_MessageAccumulator: DigestSize() should not be called");} + + /// \warning TruncatedFinal() should not be called on PK_MessageAccumulator + void TruncatedFinal(byte *digest, size_t digestSize) + { + CRYPTOPP_UNUSED(digest); CRYPTOPP_UNUSED(digestSize); + throw NotImplemented("PK_MessageAccumulator: TruncatedFinal() should not be called"); + } +}; + +/// \brief Interface for public-key signers +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Signer : public PK_SignatureScheme, public PrivateKeyAlgorithm +{ +public: + virtual ~PK_Signer() {} + + /// \brief Create a new HashTransformation to accumulate the message to be signed + /// \param rng a RandomNumberGenerator derived class + /// \return a pointer to a PK_MessageAccumulator + /// \details NewSignatureAccumulator() can be used with all signing methods. Sign() will automatically delete the + /// accumulator pointer. The caller is responsible for deletion if a method is called that takes a reference. + virtual PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng) const =0; + + /// \brief Input a recoverable message to an accumulator + /// \param messageAccumulator a reference to a PK_MessageAccumulator + /// \param recoverableMessage a pointer to the recoverable message part to be signed + /// \param recoverableMessageLength the size of the recoverable message part + virtual void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const =0; + + /// \brief Sign and delete the messageAccumulator + /// \param rng a RandomNumberGenerator derived class + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \param signature a block of bytes for the signature + /// \return actual signature length + /// \details Sign() deletes the messageAccumulator, even if an exception is thrown. + /// \pre COUNTOF(signature) == MaxSignatureLength() + virtual size_t Sign(RandomNumberGenerator &rng, PK_MessageAccumulator *messageAccumulator, byte *signature) const; + + /// \brief Sign and restart messageAccumulator + /// \param rng a RandomNumberGenerator derived class + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \param signature a block of bytes for the signature + /// \param restart flag indicating whether the messageAccumulator should be restarted + /// \return actual signature length + /// \pre COUNTOF(signature) == MaxSignatureLength() + virtual size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart=true) const =0; + + /// \brief Sign a message + /// \param rng a RandomNumberGenerator derived class + /// \param message a pointer to the message + /// \param messageLen the size of the message to be signed + /// \param signature a block of bytes for the signature + /// \return actual signature length + /// \pre COUNTOF(signature) == MaxSignatureLength() + virtual size_t SignMessage(RandomNumberGenerator &rng, const byte *message, size_t messageLen, byte *signature) const; + + /// \brief Sign a recoverable message + /// \param rng a RandomNumberGenerator derived class + /// \param recoverableMessage a pointer to the recoverable message part to be signed + /// \param recoverableMessageLength the size of the recoverable message part + /// \param nonrecoverableMessage a pointer to the non-recoverable message part to be signed + /// \param nonrecoverableMessageLength the size of the non-recoverable message part + /// \param signature a block of bytes for the signature + /// \return actual signature length + /// \pre COUNTOF(signature) == MaxSignatureLength(recoverableMessageLength) + virtual size_t SignMessageWithRecovery(RandomNumberGenerator &rng, const byte *recoverableMessage, size_t recoverableMessageLength, + const byte *nonrecoverableMessage, size_t nonrecoverableMessageLength, byte *signature) const; +}; + +/// \brief Interface for public-key signature verifiers +/// \details The Recover* functions throw NotImplemented if the signature scheme does not support +/// message recovery. +/// \details The Verify* functions throw InvalidDataFormat if the scheme does support message +/// recovery and the signature contains a non-empty recoverable message part. The +/// Recover* functions should be used in that case. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_Verifier : public PK_SignatureScheme, public PublicKeyAlgorithm +{ +public: + virtual ~PK_Verifier() {} + + /// \brief Create a new HashTransformation to accumulate the message to be verified + /// \return a pointer to a PK_MessageAccumulator + /// \details NewVerificationAccumulator() can be used with all verification methods. Verify() will automatically delete + /// the accumulator pointer. The caller is responsible for deletion if a method is called that takes a reference. + virtual PK_MessageAccumulator * NewVerificationAccumulator() const =0; + + /// \brief Input signature into a message accumulator + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \param signature the signature on the message + /// \param signatureLength the size of the signature + virtual void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const =0; + + /// \brief Check whether messageAccumulator contains a valid signature and message + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \return true if the signature is valid, false otherwise + /// \details Verify() deletes the messageAccumulator, even if an exception is thrown. + virtual bool Verify(PK_MessageAccumulator *messageAccumulator) const; + + /// \brief Check whether messageAccumulator contains a valid signature and message, and restart messageAccumulator + /// \param messageAccumulator a reference to a PK_MessageAccumulator derived class + /// \return true if the signature is valid, false otherwise + /// \details VerifyAndRestart() restarts the messageAccumulator + virtual bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const =0; + + /// \brief Check whether input signature is a valid signature for input message + /// \param message a pointer to the message to be verified + /// \param messageLen the size of the message + /// \param signature a pointer to the signature over the message + /// \param signatureLen the size of the signature + /// \return true if the signature is valid, false otherwise + virtual bool VerifyMessage(const byte *message, size_t messageLen, + const byte *signature, size_t signatureLen) const; + + /// \brief Recover a message from its signature + /// \param recoveredMessage a pointer to the recoverable message part to be verified + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \return the result of the verification operation + /// \details Recover() deletes the messageAccumulator, even if an exception is thrown. + /// \pre COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength) + virtual DecodingResult Recover(byte *recoveredMessage, PK_MessageAccumulator *messageAccumulator) const; + + /// \brief Recover a message from its signature + /// \param recoveredMessage a pointer to the recoverable message part to be verified + /// \param messageAccumulator a pointer to a PK_MessageAccumulator derived class + /// \return the result of the verification operation + /// \details RecoverAndRestart() restarts the messageAccumulator + /// \pre COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength) + virtual DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const =0; + + /// \brief Recover a message from its signature + /// \param recoveredMessage a pointer for the recovered message + /// \param nonrecoverableMessage a pointer to the non-recoverable message part to be signed + /// \param nonrecoverableMessageLength the size of the non-recoverable message part + /// \param signature the signature on the message + /// \param signatureLength the size of the signature + /// \return the result of the verification operation + /// \pre COUNTOF(recoveredMessage) == MaxRecoverableLengthFromSignatureLength(signatureLength) + virtual DecodingResult RecoverMessage(byte *recoveredMessage, + const byte *nonrecoverableMessage, size_t nonrecoverableMessageLength, + const byte *signature, size_t signatureLength) const; +}; + +/// \brief Interface for domains of simple key agreement protocols +/// \details A key agreement domain is a set of parameters that must be shared +/// by two parties in a key agreement protocol, along with the algorithms +/// for generating key pairs and deriving agreed values. +/// \since Crypto++ 3.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE SimpleKeyAgreementDomain : public KeyAgreementAlgorithm +{ +public: + virtual ~SimpleKeyAgreementDomain() {} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + virtual unsigned int AgreedValueLength() const =0; + + /// \brief Provides the size of the private key + /// \return size of private keys in this domain + virtual unsigned int PrivateKeyLength() const =0; + + /// \brief Provides the size of the public key + /// \return size of public keys in this domain + virtual unsigned int PublicKeyLength() const =0; + + /// \brief Generate private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == PrivateKeyLength() + virtual void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0; + + /// \brief Generate a public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == PublicKeyLength() + virtual void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0; + + /// \brief Generate a private/public key pair + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details GenerateKeyPair() is equivalent to calling GeneratePrivateKey() and then GeneratePublicKey(). + /// \pre COUNTOF(privateKey) == PrivateKeyLength() + /// \pre COUNTOF(publicKey) == PublicKeyLength() + virtual void GenerateKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const; + + /// \brief Derive agreed value + /// \param agreedValue a byte buffer for the shared secret + /// \param privateKey a byte buffer with your private key in this domain + /// \param otherPublicKey a byte buffer with the other party's public key in this domain + /// \param validateOtherPublicKey a flag indicating if the other party's public key should be validated + /// \return true upon success, false in case of failure + /// \details Agree() derives an agreed value from your private keys and couterparty's public keys. + /// \details The other party's public key is validated by default. If you have previously validated the + /// static public key, use validateStaticOtherPublicKey=false to save time. + /// \pre COUNTOF(agreedValue) == AgreedValueLength() + /// \pre COUNTOF(privateKey) == PrivateKeyLength() + /// \pre COUNTOF(otherPublicKey) == PublicKeyLength() + virtual bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const =0; +}; + +/// \brief Interface for domains of authenticated key agreement protocols +/// \details In an authenticated key agreement protocol, each party has two +/// key pairs. The long-lived key pair is called the static key pair, +/// and the short-lived key pair is called the ephemeral key pair. +/// \since Crypto++ 3.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AuthenticatedKeyAgreementDomain : public KeyAgreementAlgorithm +{ +public: + virtual ~AuthenticatedKeyAgreementDomain() {} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + virtual unsigned int AgreedValueLength() const =0; + + /// \brief Provides the size of the static private key + /// \return size of static private keys in this domain + virtual unsigned int StaticPrivateKeyLength() const =0; + + /// \brief Provides the size of the static public key + /// \return size of static public keys in this domain + virtual unsigned int StaticPublicKeyLength() const =0; + + /// \brief Generate static private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + virtual void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0; + + /// \brief Generate a static public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + virtual void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0; + + /// \brief Generate a static private/public key pair + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details GenerateStaticKeyPair() is equivalent to calling GenerateStaticPrivateKey() and then GenerateStaticPublicKey(). + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + virtual void GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const; + + /// \brief Provides the size of ephemeral private key + /// \return the size of ephemeral private key in this domain + virtual unsigned int EphemeralPrivateKeyLength() const =0; + + /// \brief Provides the size of ephemeral public key + /// \return the size of ephemeral public key in this domain + virtual unsigned int EphemeralPublicKeyLength() const =0; + + /// \brief Generate ephemeral private key + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == PrivateEphemeralKeyLength() + virtual void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const =0; + + /// \brief Generate ephemeral public key + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == PublicEphemeralKeyLength() + virtual void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const =0; + + /// \brief Generate private/public key pair + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details GenerateEphemeralKeyPair() is equivalent to calling GenerateEphemeralPrivateKey() and then GenerateEphemeralPublicKey() + virtual void GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const; + + /// \brief Derive agreed value + /// \param agreedValue a byte buffer for the shared secret + /// \param staticPrivateKey a byte buffer with your static private key in this domain + /// \param ephemeralPrivateKey a byte buffer with your ephemeral private key in this domain + /// \param staticOtherPublicKey a byte buffer with the other party's static public key in this domain + /// \param ephemeralOtherPublicKey a byte buffer with the other party's ephemeral public key in this domain + /// \param validateStaticOtherPublicKey a flag indicating if the other party's public key should be validated + /// \return true upon success, false in case of failure + /// \details Agree() derives an agreed value from your private keys and couterparty's public keys. + /// \details The other party's ephemeral public key is validated by default. If you have previously validated + /// the static public key, use validateStaticOtherPublicKey=false to save time. + /// \pre COUNTOF(agreedValue) == AgreedValueLength() + /// \pre COUNTOF(staticPrivateKey) == StaticPrivateKeyLength() + /// \pre COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength() + /// \pre COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength() + /// \pre COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength() + virtual bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const =0; +}; + +// interface for password authenticated key agreement protocols, not implemented yet +#if 0 +/// \brief Interface for protocol sessions +/*! The methods should be called in the following order: + + InitializeSession(rng, parameters); // or call initialize method in derived class + while (true) + { + if (OutgoingMessageAvailable()) + { + length = GetOutgoingMessageLength(); + GetOutgoingMessage(message); + ; // send outgoing message + } + + if (LastMessageProcessed()) + break; + + ; // receive incoming message + ProcessIncomingMessage(message); + } + ; // call methods in derived class to obtain result of protocol session +*/ +class ProtocolSession +{ +public: + /// Exception thrown when an invalid protocol message is processed + class ProtocolError : public Exception + { + public: + ProtocolError(ErrorType errorType, const std::string &s) : Exception(errorType, s) {} + }; + + /// Exception thrown when a function is called unexpectedly + /*! for example calling ProcessIncomingMessage() when ProcessedLastMessage() == true */ + class UnexpectedMethodCall : public Exception + { + public: + UnexpectedMethodCall(const std::string &s) : Exception(OTHER_ERROR, s) {} + }; + + virtual ~ProtocolSession() {} + + ProtocolSession() : m_rng(NULLPTR), m_throwOnProtocolError(true), m_validState(false) {} + + virtual void InitializeSession(RandomNumberGenerator &rng, const NameValuePairs ¶meters) =0; + + bool GetThrowOnProtocolError() const {return m_throwOnProtocolError;} + void SetThrowOnProtocolError(bool throwOnProtocolError) {m_throwOnProtocolError = throwOnProtocolError;} + + bool HasValidState() const {return m_validState;} + + virtual bool OutgoingMessageAvailable() const =0; + virtual unsigned int GetOutgoingMessageLength() const =0; + virtual void GetOutgoingMessage(byte *message) =0; + + virtual bool LastMessageProcessed() const =0; + virtual void ProcessIncomingMessage(const byte *message, unsigned int messageLength) =0; + +protected: + void HandleProtocolError(Exception::ErrorType errorType, const std::string &s) const; + void CheckAndHandleInvalidState() const; + void SetValidState(bool valid) {m_validState = valid;} + + RandomNumberGenerator *m_rng; + +private: + bool m_throwOnProtocolError, m_validState; +}; + +class KeyAgreementSession : public ProtocolSession +{ +public: + virtual ~KeyAgreementSession() {} + + virtual unsigned int GetAgreedValueLength() const =0; + virtual void GetAgreedValue(byte *agreedValue) const =0; +}; + +class PasswordAuthenticatedKeyAgreementSession : public KeyAgreementSession +{ +public: + virtual ~PasswordAuthenticatedKeyAgreementSession() {} + + void InitializePasswordAuthenticatedKeyAgreementSession(RandomNumberGenerator &rng, + const byte *myId, unsigned int myIdLength, + const byte *counterPartyId, unsigned int counterPartyIdLength, + const byte *passwordOrVerifier, unsigned int passwordOrVerifierLength); +}; + +/// \brief Password based key agreement domain +/// \since Crypto++ 3.0 +class PasswordAuthenticatedKeyAgreementDomain : public KeyAgreementAlgorithm +{ +public: + virtual ~PasswordAuthenticatedKeyAgreementDomain() {} + + /// return whether the domain parameters stored in this object are valid + virtual bool ValidateDomainParameters(RandomNumberGenerator &rng) const + {return GetCryptoParameters().Validate(rng, 2);} + + virtual unsigned int GetPasswordVerifierLength(const byte *password, unsigned int passwordLength) const =0; + virtual void GeneratePasswordVerifier(RandomNumberGenerator &rng, const byte *userId, unsigned int userIdLength, const byte *password, unsigned int passwordLength, byte *verifier) const =0; + + enum RoleFlags {CLIENT=1, SERVER=2, INITIATOR=4, RESPONDER=8}; + + virtual bool IsValidRole(unsigned int role) =0; + virtual PasswordAuthenticatedKeyAgreementSession * CreateProtocolSession(unsigned int role) const =0; +}; +#endif + +/// \brief Exception thrown when an ASN.1 BER decoing error is encountered +class CRYPTOPP_DLL BERDecodeErr : public InvalidArgument +{ +public: + BERDecodeErr() : InvalidArgument("BER decode error") {} + BERDecodeErr(const std::string &s) : InvalidArgument(s) {} +}; + +/// \brief Interface for encoding and decoding ASN1 objects +/// \details Each class that derives from ASN1Object should provide a serialization format +/// that controls subobject layout. Most of the time the serialization format is +/// taken from a standard, like P1363 or an RFC. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ASN1Object +{ +public: + virtual ~ASN1Object() {} + + /// \brief Decode this object from a BufferedTransformation + /// \param bt BufferedTransformation object + /// \details Uses Basic Encoding Rules (BER) + virtual void BERDecode(BufferedTransformation &bt) =0; + + /// \brief Encode this object into a BufferedTransformation + /// \param bt BufferedTransformation object + /// \details Uses Distinguished Encoding Rules (DER) + virtual void DEREncode(BufferedTransformation &bt) const =0; + + /// \brief Encode this object into a BufferedTransformation + /// \param bt BufferedTransformation object + /// \details Uses Basic Encoding Rules (BER). + /// \details This may be useful if DEREncode() would be too inefficient. + virtual void BEREncode(BufferedTransformation &bt) const {DEREncode(bt);} +}; + +/// \brief Specifies the build-time version of the library +/// \return integer representing the build-time version +/// \details LibraryVersion can help detect inadvertent mixing and matching of library +/// versions. When using Crypto++ distributed by a third party, LibraryVersion() +/// records the version of the shared object that was built by the third party. +/// The LibraryVersion() record resides in cryptlib.o on Unix compatibles +/// and cryptlib.obj on Windows. It does not change when an app links +/// to the library. +/// \details LibraryVersion() is declared with C linkage (extern "C") within the +/// CryptoPP namespace to help programs locate the symbol. If the symbol is present, then +/// the library version is 5.7 or above. If it is missing, then the library version is +/// 5.6.5 or below. +/// \details The function could be used as shown below. +///
  if (LibraryVersion() != HeaderVersion())
+///   {
+///      cout << "Potential version mismatch" << endl;
+///
+///      const int lmaj = (LibraryVersion() / 100U) % 10;
+///      const int lmin = (LibraryVersion() / 10U) % 10;
+///      const int hmaj = (HeaderVersion() / 100U) % 10;
+///      const int hmin = (HeaderVersion() / 10U) % 10;
+///
+///      if(lmaj != hmaj)
+///         cout << "Major version mismatch" << endl;
+///      else if(lmin != hmin)
+///         cout << "Minor version mismatch" << endl;
+///   }
+/// 
+/// \sa HeaderVersion(), GitHub Issue 371. +/// \since Crypto++ 6.0 +extern "C" { + int LibraryVersion(CRYPTOPP_NOINLINE_DOTDOTDOT); +} // C linkage + +/// \brief Specifies the runtime version of the library +/// \return integer representing the runtime version +/// \details HeaderVersion() can help detect inadvertent mixing and matching of library +/// versions. When using Crypto++ distributed by a third party, HeaderVersion() +/// records the version of the headers used by the app when the app is compiled. +/// \details HeaderVersion() is declared with C linkage (extern "C") within the +/// CryptoPP namespace to help programs locate the symbol. If the symbol is present, then +/// the library version is 5.7 or above. If it is missing, then the library version is +/// 5.6.5 or below. +/// \details The function could be used as shown below. +///
  if (LibraryVersion() != HeaderVersion())
+///   {
+///      cout << "Potential version mismatch" << endl;
+///
+///      const int lmaj = (LibraryVersion() / 100U) % 10;
+///      const int lmin = (LibraryVersion() / 10U) % 10;
+///      const int hmaj = (HeaderVersion() / 100U) % 10;
+///      const int hmin = (HeaderVersion() / 10U) % 10;
+///
+///      if(lmaj != hmaj)
+///         cout << "Major version mismatch" << endl;
+///      else if(lmin != hmin)
+///         cout << "Minor version mismatch" << endl;
+///   }
+/// 
+/// \sa LibraryVersion(), GitHub Issue 371. +/// \since Crypto++ 6.0 +extern "C" { +inline int HeaderVersion() +{ + return CRYPTOPP_VERSION; +} +} // C linkage + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/darn.h b/third_party/cryptoppwin/include/cryptopp/darn.h new file mode 100644 index 00000000..41062b32 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/darn.h @@ -0,0 +1,95 @@ +// darn.h - written and placed in public domain by Jeffrey Walton +// DARN requires POWER9/ISA 3.0. + +// At the moment only GCC 7.0 (and above) seems to support __builtin_darn() +// and __builtin_darn_32(). However, GCC generates incorrect code. Clang 7.0 +// does not provide them, but it does support assembly instructions. XLC is +// unknown, but there are no hits when searching IBM's site. To cover more +// platforms we provide GCC inline assembly like we do with RDRAND and RDSEED. +// Platforms that don't support GCC inline assembly or the builtin will fail +// to compile. Also see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91481 and +// https://gcc.gnu.org/onlinedocs/gcc/Basic-PowerPC-Built-in-Functions-Available-on-ISA-3_002e0.html + +/// \file darn.h +/// \brief Classes for DARN RNG +/// \sa Power +/// ISA Version 3.0B +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_DARN_H +#define CRYPTOPP_DARN_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when a DARN generator encounters +/// a generator related error. +/// \since Crypto++ 8.0 +class DARN_Err : public Exception +{ +public: + DARN_Err(const std::string &operation) + : Exception(OTHER_ERROR, "DARN: " + operation + " operation failed") {} +}; + +/// \brief Hardware generated random numbers using DARN instruction +/// \details DARN() provides access to Power9's random number generator. The +/// Crypto++ implementation provides conditioned random numbers from the +/// generator as opposed to raw random numbers. According to Power ISA 3.0B +/// manual, a conditioned random number has been processed by hardware to +/// reduce bias. A raw random number is unconditioned noise source output. +/// \details According to Power ISA 3.0B manual, the random number generator +/// provided by the darn instruction is NIST SP800-90B and SP800-90C +/// compliant to the extent possible given the completeness of the standards +/// at the time the hardware is designed. The random number generator provides +/// a minimum of 0.5 bits of entropy per bit. +/// \par Wraps +/// darn instruction +/// \sa Power +/// ISA Version 3.0B, MaurerRandomnessTest() for random bit generators +/// \since Crypto++ 8.0 +class DARN : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "DARN"; } + + virtual ~DARN() {} + + /// \brief Construct a DARN generator + /// \throw DARN_Err if the random number generator is not available + DARN(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + /// \details the RDSEED generator discards words, not bytes. If n is + /// not a multiple of a machine word, then it is rounded up to + /// that size. + virtual void DiscardBytes(size_t n); + + /// \brief Update RNG state with additional unpredictable values + /// \param input unused + /// \param length unused + /// \details The operation is a nop for this generator. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + // Override to avoid the base class' throw. + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + } + + std::string AlgorithmProvider() const { + return "Power9"; + } + +private: + SecBlock > m_temp; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_DARN_H diff --git a/third_party/cryptoppwin/include/cryptopp/default.h b/third_party/cryptoppwin/include/cryptopp/default.h new file mode 100644 index 00000000..cb24afb7 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/default.h @@ -0,0 +1,310 @@ +// default.h - originally written and placed in the public domain by Wei Dai + +/// \file default.h +/// \brief Classes for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC + +#ifndef CRYPTOPP_DEFAULT_H +#define CRYPTOPP_DEFAULT_H + +#include "sha.h" +#include "hmac.h" +#include "aes.h" +#include "des.h" +#include "modes.h" +#include "filters.h" +#include "smartptr.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Legacy block cipher for LegacyEncryptor, LegacyDecryptor, LegacyEncryptorWithMAC and LegacyDecryptorWithMAC +typedef DES_EDE2 LegacyBlockCipher; +/// \brief Legacy hash for use with LegacyEncryptorWithMAC and LegacyDecryptorWithMAC +typedef SHA1 LegacyHashModule; +/// \brief Legacy HMAC for use withLegacyEncryptorWithMAC and LegacyDecryptorWithMAC +typedef HMAC LegacyMAC; + +/// \brief Default block cipher for DefaultEncryptor, DefaultDecryptor, DefaultEncryptorWithMAC and DefaultDecryptorWithMAC +typedef AES DefaultBlockCipher; +/// \brief Default hash for use with DefaultEncryptorWithMAC and DefaultDecryptorWithMAC +typedef SHA256 DefaultHashModule; +/// \brief Default HMAC for use withDefaultEncryptorWithMAC and DefaultDecryptorWithMAC +typedef HMAC DefaultMAC; + +/// \brief Exception thrown when LegacyDecryptorWithMAC or DefaultDecryptorWithMAC decryption error is encountered +class DataDecryptorErr : public Exception +{ +public: + DataDecryptorErr(const std::string &s) + : Exception(DATA_INTEGRITY_CHECK_FAILED, s) {} +}; + +/// \brief Exception thrown when a bad key is encountered in DefaultDecryptorWithMAC and LegacyDecryptorWithMAC +class KeyBadErr : public DataDecryptorErr +{ + public: KeyBadErr() + : DataDecryptorErr("DataDecryptor: cannot decrypt message with this passphrase") {} +}; + +/// \brief Exception thrown when an incorrect MAC is encountered in DefaultDecryptorWithMAC and LegacyDecryptorWithMAC +class MACBadErr : public DataDecryptorErr +{ + public: MACBadErr() + : DataDecryptorErr("DataDecryptorWithMAC: MAC check failed") {} +}; + +/// \brief Algorithm information for password-based encryptors and decryptors +template +struct DataParametersInfo +{ + CRYPTOPP_CONSTANT(BLOCKSIZE = BlockSize); + CRYPTOPP_CONSTANT(KEYLENGTH = KeyLength); + CRYPTOPP_CONSTANT(SALTLENGTH = SaltSize); + CRYPTOPP_CONSTANT(DIGESTSIZE = DigestSize); + CRYPTOPP_CONSTANT(ITERATIONS = Iterations); +}; + +typedef DataParametersInfo LegacyParametersInfo; +typedef DataParametersInfo DefaultParametersInfo; + +/// \brief Password-based Encryptor +/// \tparam BC BlockCipher based class used for encryption +/// \tparam H HashTransformation based class used for mashing +/// \tparam Info Constants used by the algorithms +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. +/// \sa DefaultEncryptor, DefaultDecryptor, LegacyEncryptor, LegacyDecryptor +/// \since Crypto++ 2.0 +template +class DataEncryptor : public ProxyFilter, public Info +{ +public: + CRYPTOPP_CONSTANT(BLOCKSIZE = Info::BLOCKSIZE); + CRYPTOPP_CONSTANT(KEYLENGTH = Info::KEYLENGTH); + CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH); + CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS); + + /// \brief Construct a DataEncryptor + /// \param passphrase a C-String password + /// \param attachment a BufferedTransformation to attach to this object + DataEncryptor(const char *passphrase, BufferedTransformation *attachment = NULLPTR); + + /// \brief Construct a DataEncryptor + /// \param passphrase a byte string password + /// \param passphraseLength the length of the byte string password + /// \param attachment a BufferedTransformation to attach to this object + DataEncryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR); + +protected: + void FirstPut(const byte *); + void LastPut(const byte *inString, size_t length); + +private: + SecByteBlock m_passphrase; + typename CBC_Mode::Encryption m_cipher; +}; + +/// \brief Password-based Decryptor +/// \tparam BC BlockCipher based class used for encryption +/// \tparam H HashTransformation based class used for mashing +/// \tparam Info Constants used by the algorithms +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. +/// \sa DefaultEncryptor, DefaultDecryptor, LegacyEncryptor, LegacyDecryptor +/// \since Crypto++ 2.0 +template +class DataDecryptor : public ProxyFilter, public Info +{ +public: + CRYPTOPP_CONSTANT(BLOCKSIZE = Info::BLOCKSIZE); + CRYPTOPP_CONSTANT(KEYLENGTH = Info::KEYLENGTH); + CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH); + CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS); + + /// \brief Constructs a DataDecryptor + /// \param passphrase a C-String password + /// \param attachment a BufferedTransformation to attach to this object + /// \param throwException a flag specifying whether an Exception should be thrown on error + DataDecryptor(const char *passphrase, BufferedTransformation *attachment = NULLPTR, bool throwException=true); + + /// \brief Constructs a DataDecryptor + /// \param passphrase a byte string password + /// \param passphraseLength the length of the byte string password + /// \param attachment a BufferedTransformation to attach to this object + /// \param throwException a flag specifying whether an Exception should be thrown on error + DataDecryptor(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR, bool throwException=true); + + enum State {WAITING_FOR_KEYCHECK, KEY_GOOD, KEY_BAD}; + State CurrentState() const {return m_state;} + +protected: + void FirstPut(const byte *inString); + void LastPut(const byte *inString, size_t length); + + State m_state; + +private: + void CheckKey(const byte *salt, const byte *keyCheck); + + SecByteBlock m_passphrase; + typename CBC_Mode::Decryption m_cipher; + member_ptr m_decryptor; + bool m_throwException; + +}; + +/// \brief Password-based encryptor with MAC +/// \tparam BC BlockCipher based class used for encryption +/// \tparam H HashTransformation based class used for mashing +/// \tparam MAC HashTransformation based class used for authentication +/// \tparam Info Constants used by the algorithms +/// \details DataEncryptorWithMAC uses a non-standard mashup function called Mash() to derive key +/// bits from the password. +/// \details The purpose of the function Mash() is to take an arbitrary length input string and +/// *deterministically* produce an arbitrary length output string such that (1) it looks random, +/// (2) no information about the input is deducible from it, and (3) it contains as much entropy +/// as it can hold, or the amount of entropy in the input string, whichever is smaller. +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. +/// \sa DefaultEncryptorWithMAC, DefaultDecryptorWithMAC, LegacyDecryptorWithMAC, LegacyEncryptorWithMAC +/// \since Crypto++ 2.0 +template +class DataEncryptorWithMAC : public ProxyFilter +{ +public: + CRYPTOPP_CONSTANT(BLOCKSIZE = Info::BLOCKSIZE); + CRYPTOPP_CONSTANT(KEYLENGTH = Info::KEYLENGTH); + CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH); + CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS); + + /// \brief Constructs a DataEncryptorWithMAC + /// \param passphrase a C-String password + /// \param attachment a BufferedTransformation to attach to this object + DataEncryptorWithMAC(const char *passphrase, BufferedTransformation *attachment = NULLPTR); + + /// \brief Constructs a DataEncryptorWithMAC + /// \param passphrase a byte string password + /// \param passphraseLength the length of the byte string password + /// \param attachment a BufferedTransformation to attach to this object + DataEncryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR); + +protected: + void FirstPut(const byte *inString) {CRYPTOPP_UNUSED(inString);} + void LastPut(const byte *inString, size_t length); + +private: + member_ptr m_mac; + +}; + +/// \brief Password-based decryptor with MAC +/// \tparam BC BlockCipher based class used for encryption +/// \tparam H HashTransformation based class used for mashing +/// \tparam MAC HashTransformation based class used for authentication +/// \tparam Info Constants used by the algorithms +/// \details DataDecryptorWithMAC uses a non-standard mashup function called Mash() to derive key +/// bits from the password. +/// \details The purpose of the function Mash() is to take an arbitrary length input string and +/// *deterministically* produce an arbitrary length output string such that (1) it looks random, +/// (2) no information about the input is deducible from it, and (3) it contains as much entropy +/// as it can hold, or the amount of entropy in the input string, whichever is smaller. +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. +/// \sa DefaultEncryptorWithMAC, DefaultDecryptorWithMAC, LegacyDecryptorWithMAC, LegacyEncryptorWithMAC +/// \since Crypto++ 2.0 +template +class DataDecryptorWithMAC : public ProxyFilter +{ +public: + CRYPTOPP_CONSTANT(BLOCKSIZE = Info::BLOCKSIZE); + CRYPTOPP_CONSTANT(KEYLENGTH = Info::KEYLENGTH); + CRYPTOPP_CONSTANT(SALTLENGTH = Info::SALTLENGTH); + CRYPTOPP_CONSTANT(DIGESTSIZE = Info::DIGESTSIZE); + CRYPTOPP_CONSTANT(ITERATIONS = Info::ITERATIONS); + + /// \brief Constructs a DataDecryptor + /// \param passphrase a C-String password + /// \param attachment a BufferedTransformation to attach to this object + /// \param throwException a flag specifying whether an Exception should be thrown on error + DataDecryptorWithMAC(const char *passphrase, BufferedTransformation *attachment = NULLPTR, bool throwException=true); + + /// \brief Constructs a DataDecryptor + /// \param passphrase a byte string password + /// \param passphraseLength the length of the byte string password + /// \param attachment a BufferedTransformation to attach to this object + /// \param throwException a flag specifying whether an Exception should be thrown on error + DataDecryptorWithMAC(const byte *passphrase, size_t passphraseLength, BufferedTransformation *attachment = NULLPTR, bool throwException=true); + + typename DataDecryptor::State CurrentState() const; + bool CheckLastMAC() const; + +protected: + void FirstPut(const byte *inString) {CRYPTOPP_UNUSED(inString);} + void LastPut(const byte *inString, size_t length); + +private: + member_ptr m_mac; + HashVerificationFilter *m_hashVerifier; + bool m_throwException; +}; + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Password-based encryptor (deprecated) +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct LegacyEncryptor : public DataEncryptor {}; +/// \brief Password-based decryptor (deprecated) +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct LegacyDecryptor : public DataDecryptor {}; +/// \brief Password-based encryptor +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct DefaultEncryptor : public DataEncryptor {}; +/// \brief Password-based decryptor +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct DefaultDecryptor : public DataDecryptor {}; +/// \brief Password-based encryptor with MAC (deprecated) +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct LegacyEncryptorWithMAC : public DataEncryptorWithMAC {}; +/// \brief Password-based decryptor with MAC (deprecated) +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct LegacyDecryptorWithMAC : public DataDecryptorWithMAC {}; +/// \brief Password-based encryptor with MAC +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct DefaultEncryptorWithMAC : public DataEncryptorWithMAC {}; +/// \brief Password-based decryptor with MAC +/// \details Crypto++ 5.6.5 and earlier used the legacy algorithms, including DES_EDE2 and SHA1. +/// Crypto++ 5.7 switched to AES and SHA256. The updated algorithms are available with the +/// Default* classes, and the old algorithms are available with the Legacy* classes. +struct DefaultDecryptorWithMAC : public DataDecryptorWithMAC {}; +#else +typedef DataEncryptor LegacyEncryptor; +typedef DataDecryptor LegacyDecryptor; + +typedef DataEncryptor DefaultEncryptor; +typedef DataDecryptor DefaultDecryptor; + +typedef DataEncryptorWithMAC LegacyEncryptorWithMAC; +typedef DataDecryptorWithMAC LegacyDecryptorWithMAC; + +typedef DataEncryptorWithMAC DefaultEncryptorWithMAC; +typedef DataDecryptorWithMAC DefaultDecryptorWithMAC; +#endif + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/des.h b/third_party/cryptoppwin/include/cryptopp/des.h new file mode 100644 index 00000000..10ba0598 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/des.h @@ -0,0 +1,163 @@ +// des.h - originally written and placed in the public domain by Wei Dai + +/// \file des.h +/// \brief Classes for DES, 2-key Triple-DES, 3-key Triple-DES and DESX + +#ifndef CRYPTOPP_DES_H +#define CRYPTOPP_DES_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief DES block cipher base class +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL RawDES +{ +public: + void RawSetKey(CipherDir direction, const byte *userKey); + void RawProcessBlock(word32 &l, word32 &r) const; + +protected: + static const word32 Spbox[8][64]; + + FixedSizeSecBlock k; +}; + +/// \brief DES block cipher information +/// \since Crypto++ 1.0 +struct DES_Info : public FixedBlockSize<8>, public FixedKeyLength<8> +{ + // disable DES in DLL version by not exporting this function + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "DES";} +}; + +/// \brief DES block cipher +/// \details The DES implementation in Crypto++ ignores the parity bits +/// (the least significant bits of each byte) in the key. However you can use CheckKeyParityBits() +/// and CorrectKeyParityBits() to check or correct the parity bits if you wish. +/// \sa DES +/// \since Crypto++ 1.0 +class DES : public DES_Info, public BlockCipherDocumentation +{ + /// \brief DES block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl, public RawDES + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + /// check DES key parity bits + static bool CheckKeyParityBits(const byte *key); + /// correct DES key parity bits + static void CorrectKeyParityBits(byte *key); + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief 2-key TripleDES block cipher information +/// \since Crypto++ 1.0 +struct DES_EDE2_Info : public FixedBlockSize<8>, public FixedKeyLength<16> +{ + CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "DES-EDE2";} +}; + +/// \brief 2-key TripleDES block cipher +/// \sa DES-EDE2 +/// \since Crypto++ 1.0 +class DES_EDE2 : public DES_EDE2_Info, public BlockCipherDocumentation +{ + /// \brief DES_EDE2 block cipher default operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + RawDES m_des1, m_des2; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief 3-key TripleDES block cipher information +/// \since Crypto++ 1.0 +struct DES_EDE3_Info : public FixedBlockSize<8>, public FixedKeyLength<24> +{ + CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "DES-EDE3";} +}; + +/// \brief 3-key TripleDES block cipher +/// \sa DES-EDE3 +/// \since Crypto++ 1.0 +class DES_EDE3 : public DES_EDE3_Info, public BlockCipherDocumentation +{ + /// \brief DES_EDE3 block cipher default operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + RawDES m_des1, m_des2, m_des3; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief DESX block cipher information +/// \since Crypto++ 3.2 +struct DES_XEX3_Info : public FixedBlockSize<8>, public FixedKeyLength<24> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "DES-XEX3";} +}; + +/// \brief DESX block cipher +/// \sa DES-XEX3, AKA DESX +/// \since Crypto++ 3.2 +class DES_XEX3 : public DES_XEX3_Info, public BlockCipherDocumentation +{ + /// \brief DES_XEX3 block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + FixedSizeSecBlock m_x1, m_x3; + // VS2005 workaround: calling modules compiled with /clr gets unresolved external symbol DES::Base::ProcessAndXorBlock + // if we use DES::Encryption here directly without value_ptr. + value_ptr m_des; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef DES::Encryption DESEncryption; +typedef DES::Decryption DESDecryption; + +typedef DES_EDE2::Encryption DES_EDE2_Encryption; +typedef DES_EDE2::Decryption DES_EDE2_Decryption; + +typedef DES_EDE3::Encryption DES_EDE3_Encryption; +typedef DES_EDE3::Decryption DES_EDE3_Decryption; + +typedef DES_XEX3::Encryption DES_XEX3_Encryption; +typedef DES_XEX3::Decryption DES_XEX3_Decryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/dh.h b/third_party/cryptoppwin/include/cryptopp/dh.h new file mode 100644 index 00000000..e12adba1 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/dh.h @@ -0,0 +1,275 @@ +// dh.h - originally written and placed in the public domain by Wei Dai + +/// \file dh.h +/// \brief Classes for Diffie-Hellman key exchange + +#ifndef CRYPTOPP_DH_H +#define CRYPTOPP_DH_H + +#include "cryptlib.h" +#include "gfpcrypt.h" +#include "algebra.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Diffie-Hellman domain +/// \tparam GROUP_PARAMETERS group parameters +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \details A Diffie-Hellman domain is a set of parameters that must be shared +/// by two parties in a key agreement protocol, along with the algorithms +/// for generating key pairs and deriving agreed values. +/// \details For COFACTOR_OPTION, see CofactorMultiplicationOption. +/// \sa DL_SimpleKeyAgreementDomainBase +/// \since Crypto++ 1.0 +template +class DH_Domain : public DL_SimpleKeyAgreementDomainBase +{ + typedef DL_SimpleKeyAgreementDomainBase Base; + +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef DL_KeyAgreementAlgorithm_DH DH_Algorithm; + typedef DH_Domain Domain; + + virtual ~DH_Domain() {} + + /// \brief Construct a Diffie-Hellman domain + DH_Domain() {} + + /// \brief Construct a Diffie-Hellman domain + /// \param params group parameters and options + DH_Domain(const GroupParameters ¶ms) + : m_groupParameters(params) {} + + /// \brief Construct a Diffie-Hellman domain + /// \param bt BufferedTransformation with group parameters and options + DH_Domain(BufferedTransformation &bt) + {m_groupParameters.BERDecode(bt);} + + /// \brief Create a Diffie-Hellman domain + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 RandomNumberGenerator derived class + /// \param v2 second parameter + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(RandomNumberGenerator &v1, const T2 &v2) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Create a Diffie-Hellman domain + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 RandomNumberGenerator derived class + /// \param v2 second parameter + /// \param v3 third parameter + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(RandomNumberGenerator &v1, const T2 &v2, const T3 &v3) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Create a Diffie-Hellman domain + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 RandomNumberGenerator derived class + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 fourth parameter + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(RandomNumberGenerator &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + + /// \brief Construct a Diffie-Hellman domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(const T1 &v1, const T2 &v2) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Construct a Diffie-Hellman domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(const T1 &v1, const T2 &v2, const T3 &v3) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Construct a Diffie-Hellman domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 fourth parameter + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + template + DH_Domain(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a const reference + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a non-const reference + GroupParameters & AccessGroupParameters() {return m_groupParameters;} + + /// \brief Generate a public key from a private key in this domain + /// \param rng RandomNumberGenerator derived class + /// \param privateKey byte buffer with the previously generated private key + /// \param publicKey byte buffer for the generated public key in this domain + /// \details If using a FIPS 140-2 validated library on Windows, then this class will perform + /// a self test to ensure the key pair is pairwise consistent. Non-FIPS and non-Windows + /// builds of the library do not provide FIPS validated cryptography, so the code should be + /// removed by the optimizer. + /// \pre COUNTOF(publicKey) == PublicKeyLength() + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + Base::GeneratePublicKey(rng, privateKey, publicKey); + + if (FIPS_140_2_ComplianceEnabled()) + { + SecByteBlock privateKey2(this->PrivateKeyLength()); + this->GeneratePrivateKey(rng, privateKey2); + + SecByteBlock publicKey2(this->PublicKeyLength()); + Base::GeneratePublicKey(rng, privateKey2, publicKey2); + + SecByteBlock agreedValue(this->AgreedValueLength()), agreedValue2(this->AgreedValueLength()); + bool agreed1 = this->Agree(agreedValue, privateKey, publicKey2); + bool agreed2 = this->Agree(agreedValue2, privateKey2, publicKey); + + if (!agreed1 || !agreed2 || agreedValue != agreedValue2) + throw SelfTestFailure(this->AlgorithmName() + ": pairwise consistency test failed"); + } + } + + static std::string CRYPTOPP_API StaticAlgorithmName() + {return GroupParameters::StaticAlgorithmNamePrefix() + DH_Algorithm::StaticAlgorithmName();} + std::string AlgorithmName() const {return StaticAlgorithmName();} + +private: + const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const + {return Singleton().Ref();} + DL_GroupParameters & AccessAbstractGroupParameters() + {return m_groupParameters;} + + GroupParameters m_groupParameters; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DH_Domain; + +/// \brief Diffie-Hellman in GF(p) +/// \details DH() class is a typedef of DH_Domain(). The documentation that follows +/// does not exist. Rather the documentation was created in response to Issue +/// 328, Diffie-Hellman example code not compiling. +/// \details Generally speaking, a DH() object is ephemeral and is intended to execute one instance of the Diffie-Hellman protocol. The +/// private and public key parts are not intended to be set or persisted. Rather, a new set of domain parameters are generated each +/// time an object is created. +/// \details Once a DH() object is created, once can retrieve the ephemeral public key for the other party with code similar to the +/// following. +///
   AutoSeededRandomPool prng;
+///   Integer p, q, g;
+///   PrimeAndGenerator pg;
+///
+///   pg.Generate(1, prng, 512, 511);
+///   p = pg.Prime();
+///   q = pg.SubPrime();
+///   g = pg.Generator();
+///
+///   DH dh(p, q, g);
+///   SecByteBlock t1(dh.PrivateKeyLength()), t2(dh.PublicKeyLength());
+///   dh.GenerateKeyPair(prng, t1, t2);
+///   Integer k1(t1, t1.size()), k2(t2, t2.size());
+///
+///   cout << "Private key:\n";
+///   cout << hex << k1 << endl;
+///
+///   cout << "Public key:\n";
+///   cout << hex << k2 << endl;
+/// +/// \details Output of the program above will be similar to the following. +///
   $ ./cryptest.exe
+///   Private key:
+///   72b45a42371545e9d4880f48589aefh
+///   Public key:
+///   45fdb13f97b1840626f0250cec1dba4a23b894100b51fb5d2dd13693d789948f8bfc88f9200014b2
+///   ba8dd8a6debc471c69ef1e2326c61184a2eca88ec866346bh
+/// \sa Diffie-Hellman on the Crypto++ wiki and +/// Diffie-Hellman in GF(p) with key validation +/// \since Crypto++ 1.0 +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +struct DH : public DH_Domain +{ + typedef DH_Domain GroupParameters; + typedef GroupParameters::Element Element; + + virtual ~DH() {} + + /// \brief Create an uninitialized Diffie-Hellman object + DH() : DH_Domain() {} + + /// \brief Initialize a Diffie-Hellman object + /// \param bt BufferedTransformation with group parameters and options + DH(BufferedTransformation &bt) : DH_Domain(bt) {} + + /// \brief Initialize a Diffie-Hellman object + /// \param params group parameters and options + DH(const GroupParameters ¶ms) : DH_Domain(params) {} + + /// \brief Create a Diffie-Hellman object + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \details This function overload of Initialize() creates a new Diffie-Hellman object because it + /// takes a RandomNumberGenerator() as a parameter. + DH(RandomNumberGenerator &rng, unsigned int modulusBits) : DH_Domain(rng, modulusBits) {} + + /// \brief Initialize a Diffie-Hellman object + /// \param p the modulus + /// \param g the generator + DH(const Integer &p, const Integer &g) : DH_Domain(p, g) {} + + /// \brief Initialize a Diffie-Hellman object + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + DH(const Integer &p, const Integer &q, const Integer &g) : DH_Domain(p, q, g) {} + + /// \brief Creates a Diffie-Hellman object + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \details This function overload of Initialize() creates a new Diffie-Hellman object because it + /// takes a RandomNumberGenerator() as a parameter. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {AccessGroupParameters().Initialize(rng, modulusBits);} + + /// \brief Initialize a Diffie-Hellman object + /// \param p the modulus + /// \param g the generator + void Initialize(const Integer &p, const Integer &g) + {AccessGroupParameters().Initialize(p, g);} + + /// \brief Initialize a Diffie-Hellman object + /// \param p the modulus + /// \param q the subgroup order + /// \param g the generator + void Initialize(const Integer &p, const Integer &q, const Integer &g) + {AccessGroupParameters().Initialize(p, q, g);} +}; +#else +// The real DH class is a typedef. +typedef DH_Domain DH; +#endif + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/dh2.h b/third_party/cryptoppwin/include/cryptopp/dh2.h new file mode 100644 index 00000000..6cbfe46b --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/dh2.h @@ -0,0 +1,70 @@ +// dh2.h - originally written and placed in the public domain by Wei Dai + +/// \file dh2.h +/// \brief Classes for Unified Diffie-Hellman key exchange +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_DH2_H +#define CRYPTOPP_DH2_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Unified Diffie-Hellman in GF(p) +/// \details A Diffie-Hellman domain is a set of parameters that must be shared +/// by two parties in a key agreement protocol, along with the algorithms +/// for generating key pairs and deriving agreed values. +/// \sa AuthenticatedKeyAgreementDomain, Unified Diffie-Hellman +/// \since Crypto++ 3.0 +class DH2 : public AuthenticatedKeyAgreementDomain +{ +public: + virtual ~DH2() {} + + /// \brief Construct a DH2 + DH2(SimpleKeyAgreementDomain &domain) + : d1(domain), d2(domain) {} + /// \brief Construct a DH2 + DH2(SimpleKeyAgreementDomain &staticDomain, SimpleKeyAgreementDomain &ephemeralDomain) + : d1(staticDomain), d2(ephemeralDomain) {} + + CryptoParameters & AccessCryptoParameters() {return d1.AccessCryptoParameters();} + + unsigned int AgreedValueLength() const + {return d1.AgreedValueLength() + d2.AgreedValueLength();} + + unsigned int StaticPrivateKeyLength() const + {return d1.PrivateKeyLength();} + unsigned int StaticPublicKeyLength() const + {return d1.PublicKeyLength();} + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + {d1.GeneratePrivateKey(rng, privateKey);} + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + {d1.GeneratePublicKey(rng, privateKey, publicKey);} + void GenerateStaticKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const + {d1.GenerateKeyPair(rng, privateKey, publicKey);} + + unsigned int EphemeralPrivateKeyLength() const + {return d2.PrivateKeyLength();} + unsigned int EphemeralPublicKeyLength() const + {return d2.PublicKeyLength();} + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + {d2.GeneratePrivateKey(rng, privateKey);} + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + {d2.GeneratePublicKey(rng, privateKey, publicKey);} + void GenerateEphemeralKeyPair(RandomNumberGenerator &rng, byte *privateKey, byte *publicKey) const + {d2.GenerateKeyPair(rng, privateKey, publicKey);} + + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const; + +protected: + SimpleKeyAgreementDomain &d1, &d2; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/dll.h b/third_party/cryptoppwin/include/cryptopp/dll.h new file mode 100644 index 00000000..1537ee6d --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/dll.h @@ -0,0 +1,71 @@ +// dll.h - originally written and placed in the public domain by Wei Dai + +/// \file dll.h +/// \brief Functions and definitions required for building the FIPS-140 DLL on Windows + +#ifndef CRYPTOPP_DLL_H +#define CRYPTOPP_DLL_H + +#if !defined(CRYPTOPP_IMPORTS) && !defined(CRYPTOPP_EXPORTS) && !defined(CRYPTOPP_DEFAULT_NO_DLL) +#ifdef CRYPTOPP_CONFIG_H +#error To use the DLL version of Crypto++, this file must be included before any other Crypto++ header files. +#endif +#define CRYPTOPP_IMPORTS +#endif + +#include "aes.h" +#include "cbcmac.h" +#include "ccm.h" +#include "cmac.h" +#include "channels.h" +#include "des.h" +#include "dh.h" +#include "dsa.h" +#include "ec2n.h" +#include "eccrypto.h" +#include "ecp.h" +#include "files.h" +#include "fips140.h" +#include "gcm.h" +#include "hex.h" +#include "hmac.h" +#include "modes.h" +#include "mqueue.h" +#include "nbtheory.h" +#include "osrng.h" +#include "pkcspad.h" +#include "pssr.h" +#include "randpool.h" +#include "rsa.h" +#include "rw.h" +#include "sha.h" +#include "skipjack.h" + +#ifdef CRYPTOPP_IMPORTS + +#ifdef _DLL +// cause CRT DLL to be initialized before Crypto++ so that we can use malloc and free during DllMain() +#ifdef CRYPTOPP_DEBUG +# pragma comment(lib, "msvcrtd") +# pragma comment(lib, "cryptopp") +#else +# pragma comment(lib, "msvcrt") +# pragma comment(lib, "cryptopp") +#endif +#endif + +#endif // #ifdef CRYPTOPP_IMPORTS + +#include // for new_handler + +NAMESPACE_BEGIN(CryptoPP) + +typedef void * (CRYPTOPP_API * PNew)(size_t); +typedef void (CRYPTOPP_API * PDelete)(void *); +typedef void (CRYPTOPP_API * PGetNewAndDelete)(PNew &, PDelete &); +typedef std::new_handler (CRYPTOPP_API * PSetNewHandler)(std::new_handler); +typedef void (CRYPTOPP_API * PSetNewAndDelete)(PNew, PDelete, PSetNewHandler); + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/dmac.h b/third_party/cryptoppwin/include/cryptopp/dmac.h new file mode 100644 index 00000000..ef2fa189 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/dmac.h @@ -0,0 +1,114 @@ +// dmac.h - originally written and placed in the public domain by Wei Dai + +/// \file dmac.h +/// \brief Classes for DMAC message authentication code + +#ifndef CRYPTOPP_DMAC_H +#define CRYPTOPP_DMAC_H + +#include "cbcmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief DMAC message authentication code base class +/// \tparam T class derived from BlockCipherDocumentation +/// \since Crypto++ 3.1 +template +class CRYPTOPP_NO_VTABLE DMAC_Base : public SameKeyLengthAs, public MessageAuthenticationCode +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE=T::BLOCKSIZE); + static std::string StaticAlgorithmName() {return std::string("DMAC(") + T::StaticAlgorithmName() + ")";} + + virtual~DMAC_Base() {} + DMAC_Base() : m_subkeylength(0), m_counter(0) {} + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + + std::string AlgorithmProvider() const; + +private: + byte *GenerateSubKeys(const byte *key, size_t keylength); + + size_t m_subkeylength; + SecByteBlock m_subkeys; + CBC_MAC m_mac1; + typename T::Encryption m_f2; + unsigned int m_counter; +}; + +template +std::string DMAC_Base::AlgorithmProvider() const +{ + return m_f2.AlgorithmProvider(); +} + +/// \brief DMAC message authentication code +/// \tparam T class derived from BlockCipherDocumentation +/// \sa CBC MAC for Real-Time Data Sources (08.15.1997) +/// by Erez Petrank and Charles Rackoff +/// \since Crypto++ 3.1 +template +class DMAC : public MessageAuthenticationCodeFinal > +{ +public: + /// \brief Construct a DMAC + DMAC() {} + + /// \brief Construct a DMAC + /// \param key a byte array used to key the cipher + /// \param length the size of the byte array, in bytes + DMAC(const byte *key, size_t length=DMAC_Base::DEFAULT_KEYLENGTH) + {this->SetKey(key, length);} +}; + +template +void DMAC_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + m_subkeylength = T::StaticGetValidKeyLength(T::BLOCKSIZE); + m_subkeys.resize(2*UnsignedMin((unsigned int)T::BLOCKSIZE, m_subkeylength)); + m_mac1.SetKey(GenerateSubKeys(key, length), m_subkeylength, params); + m_f2.SetKey(m_subkeys+m_subkeys.size()/2, m_subkeylength, params); + m_counter = 0; + m_subkeys.resize(0); +} + +template +void DMAC_Base::Update(const byte *input, size_t length) +{ + m_mac1.Update(input, length); + m_counter = (unsigned int)((m_counter + length) % T::BLOCKSIZE); +} + +template +void DMAC_Base::TruncatedFinal(byte *mac, size_t size) +{ + ThrowIfInvalidTruncatedSize(size); + + byte pad[T::BLOCKSIZE]; + byte padByte = byte(T::BLOCKSIZE-m_counter); + std::memset(pad, padByte, padByte); + m_mac1.Update(pad, padByte); + m_mac1.TruncatedFinal(mac, size); + m_f2.ProcessBlock(mac); + + m_counter = 0; // reset for next message +} + +template +byte *DMAC_Base::GenerateSubKeys(const byte *key, size_t keylength) +{ + typename T::Encryption cipher(key, keylength); + std::memset(m_subkeys, 0, m_subkeys.size()); + cipher.ProcessBlock(m_subkeys); + m_subkeys[m_subkeys.size()/2 + T::BLOCKSIZE - 1] = 1; + cipher.ProcessBlock(m_subkeys+m_subkeys.size()/2); + return m_subkeys; +} + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/donna.h b/third_party/cryptoppwin/include/cryptopp/donna.h new file mode 100644 index 00000000..d37f2690 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/donna.h @@ -0,0 +1,179 @@ +// donna.h - written and placed in public domain by Jeffrey Walton +// Crypto++ specific implementation wrapped around Andrew +// Moon's public domain curve25519-donna and ed25519-donna, +// https://github.com/floodyberry/curve25519-donna and +// https://github.com/floodyberry/ed25519-donna. + +// The curve25519 and ed25519 source files multiplex different repos and +// architectures using namespaces. The repos are Andrew Moon's +// curve25519-donna and ed25519-donna. The architectures are 32-bit, 64-bit +// and SSE. For example, 32-bit x25519 uses symbols from Donna::X25519 and +// Donna::Arch32. + +// If needed, see Moon's commit "Go back to ignoring 256th bit [sic]", +// https://github.com/floodyberry/curve25519-donna/commit/57a683d18721a658 + +/// \file donna.h +/// \details Functions for curve25519 and ed25519 operations +/// \details This header provides the entry points into Andrew Moon's +/// curve25519 and ed25519 curve functions. The Crypto++ classes x25519 +/// and ed25519 use the functions. The functions are in the Donna +/// namespace and are curve25519_mult(), ed25519_publickey(), +/// ed25519_sign() and ed25519_sign_open(). +/// \details At the moment the hash function for signing is fixed at +/// SHA512. + +#ifndef CRYPTOPP_DONNA_H +#define CRYPTOPP_DONNA_H + +#include "config.h" +#include "cryptlib.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) + +//***************************** curve25519 *****************************// + +/// \brief Generate a public key +/// \param publicKey byte array for the public key +/// \param secretKey byte array with the private key +/// \return 0 on success, non-0 otherwise +/// \details curve25519_mult() generates a public key from an existing +/// secret key. Internally curve25519_mult() performs a scalar +/// multiplication using the base point and writes the result to +/// pubkey. +int curve25519_mult(byte publicKey[32], const byte secretKey[32]); + +/// \brief Generate a shared key +/// \param sharedKey byte array for the shared secret +/// \param secretKey byte array with the private key +/// \param othersKey byte array with the peer's public key +/// \return 0 on success, non-0 otherwise +/// \details curve25519_mult() generates a shared key from an existing +/// secret key and the other party's public key. Internally +/// curve25519_mult() performs a scalar multiplication using the two keys +/// and writes the result to sharedKey. +int curve25519_mult(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]); + +//******************************* ed25519 *******************************// + +/// \brief Creates a public key from a secret key +/// \param publicKey byte array for the public key +/// \param secretKey byte array with the private key +/// \return 0 on success, non-0 otherwise +/// \details ed25519_publickey() generates a public key from a secret key. +/// Internally ed25519_publickey() performs a scalar multiplication +/// using the secret key and then writes the result to publicKey. +int ed25519_publickey(byte publicKey[32], const byte secretKey[32]); + +/// \brief Creates a signature on a message +/// \param message byte array with the message +/// \param messageLength size of the message, in bytes +/// \param publicKey byte array with the public key +/// \param secretKey byte array with the private key +/// \param signature byte array for the signature +/// \return 0 on success, non-0 otherwise +/// \details ed25519_sign() generates a signature on a message using +/// the public and private keys. The various buffers can be exact +/// sizes, and do not require extra space like when using the +/// NaCl library functions. +/// \details At the moment the hash function for signing is fixed at +/// SHA512. +int ed25519_sign(const byte* message, size_t messageLength, const byte secretKey[32], const byte publicKey[32], byte signature[64]); + +/// \brief Creates a signature on a message +/// \param stream std::istream derived class +/// \param publicKey byte array with the public key +/// \param secretKey byte array with the private key +/// \param signature byte array for the signature +/// \return 0 on success, non-0 otherwise +/// \details ed25519_sign() generates a signature on a message using +/// the public and private keys. The various buffers can be exact +/// sizes, and do not require extra space like when using the +/// NaCl library functions. +/// \details This ed25519_sign() overload handles large streams. It +/// was added for signing and verifying files that are too large +/// for a memory allocation. +/// \details At the moment the hash function for signing is fixed at +/// SHA512. +int ed25519_sign(std::istream& stream, const byte secretKey[32], const byte publicKey[32], byte signature[64]); + +/// \brief Verifies a signature on a message +/// \param message byte array with the message +/// \param messageLength size of the message, in bytes +/// \param publicKey byte array with the public key +/// \param signature byte array with the signature +/// \return 0 on success, non-0 otherwise +/// \details ed25519_sign_open() verifies a signature on a message using +/// the public key. The various buffers can be exact sizes, and do not +/// require extra space like when using the NaCl library functions. +/// \details At the moment the hash function for signing is fixed at +/// SHA512. +int +ed25519_sign_open(const byte *message, size_t messageLength, const byte publicKey[32], const byte signature[64]); + +/// \brief Verifies a signature on a message +/// \param stream std::istream derived class +/// \param publicKey byte array with the public key +/// \param signature byte array with the signature +/// \return 0 on success, non-0 otherwise +/// \details ed25519_sign_open() verifies a signature on a message using +/// the public key. The various buffers can be exact sizes, and do not +/// require extra space like when using the NaCl library functions. +/// \details This ed25519_sign_open() overload handles large streams. It +/// was added for signing and verifying files that are too large +/// for a memory allocation. +/// \details At the moment the hash function for signing is fixed at +/// SHA512. +int +ed25519_sign_open(std::istream& stream, const byte publicKey[32], const byte signature[64]); + +//****************************** Internal ******************************// + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + +// CRYPTOPP_WORD128_AVAILABLE mostly depends upon GCC support for +// __SIZEOF_INT128__. If __SIZEOF_INT128__ is not available then Moon +// provides routines for MSC and GCC. It should cover most platforms, +// but there are gaps like MS ARM64 and XLC. We tried to enable the +// 64-bit path for SunCC from 12.5 but we got the dreaded compile +// error "The operand ___LCM cannot be assigned to". + +#if defined(CRYPTOPP_WORD128_AVAILABLE) || \ + (defined(CRYPTOPP_MSC_VERSION) && defined(_M_X64)) +# define CRYPTOPP_CURVE25519_64BIT 1 +#else +# define CRYPTOPP_CURVE25519_32BIT 1 +#endif + +// Benchmarking on a modern 64-bit Core i5-6400 @2.7 GHz shows SSE2 on Linux +// is not profitable. Here are the numbers in milliseconds/operation: +// +// * Langley, C++, 0.050 +// * Moon, C++: 0.040 +// * Moon, SSE2: 0.061 +// * Moon, native: 0.045 +// +// However, a modern 64-bit Core i5-3200 @2.5 GHz shows SSE2 is profitable +// for MS compilers. Here are the numbers in milliseconds/operation: +// +// * x86, no SSE2, 0.294 +// * x86, SSE2, 0.097 +// * x64, no SSE2, 0.081 +// * x64, SSE2, 0.071 + +#if defined(CRYPTOPP_MSC_VERSION) && (CRYPTOPP_SSE2_INTRIN_AVAILABLE) +# define CRYPTOPP_CURVE25519_SSE2 1 +#endif + +#if (CRYPTOPP_CURVE25519_SSE2) + extern int curve25519_mult_SSE2(byte sharedKey[32], const byte secretKey[32], const byte othersKey[32]); +#endif + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_DONNA_H diff --git a/third_party/cryptoppwin/include/cryptopp/donna_32.h b/third_party/cryptoppwin/include/cryptopp/donna_32.h new file mode 100644 index 00000000..50d6b820 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/donna_32.h @@ -0,0 +1,411 @@ +// donna_32.h - written and placed in public domain by Jeffrey Walton +// Crypto++ specific implementation wrapped around Andrew +// Moon's public domain curve25519-donna and ed25519-donna, +// https://github.com/floodyberry/curve25519-donna and +// https://github.com/floodyberry/ed25519-donna. + +// This source file multiplexes two different repos using namespaces. This +// was a little easier from a project management standpoint. We only need +// two files per architecture at the expense of namespaces and bloat. + +#ifndef CRYPTOPP_DONNA_32_H +#define CRYPTOPP_DONNA_32_H +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + +#include "config.h" + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) +NAMESPACE_BEGIN(Arch32) + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::word64; + +// ******************** x25519 Agreement ************************* // + +#define ALIGN(n) CRYPTOPP_ALIGN_DATA(n) +#define mul32x32_64(a,b) (((word64)(a))*(b)) + +typedef word32 bignum25519[10]; + +const byte basePoint[32] = {9}; +const word32 reduce_mask_25 = (1 << 25) - 1; +const word32 reduce_mask_26 = (1 << 26) - 1; + +// ****************** ed25519 Signatures *********************** // + +typedef byte hash_512bits[64]; + +const int bignum256modm_bits_per_limb = 30; +const int bignum256modm_limb_size = 9; +typedef word32 bignum256modm_element_t; +typedef bignum256modm_element_t bignum256modm[9]; + +struct ge25519 { + bignum25519 x, y, z, t; +}; + +struct ge25519_p1p1 { + bignum25519 x, y, z, t; +}; + +struct ge25519_niels { + bignum25519 ysubx, xaddy, t2d; +}; + +struct ge25519_pniels { + bignum25519 ysubx, xaddy, z, t2d; +}; + +#define S1_SWINDOWSIZE 5 +#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) +#define S2_SWINDOWSIZE 7 +#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) + +// *************** ed25519-donna-32bit-tables.h *************** // + +ALIGN(16) const ge25519 ge25519_basepoint = { + {0x0325d51a,0x018b5823,0x00f6592a,0x0104a92d,0x01a4b31d,0x01d6dc5c,0x027118fe,0x007fd814,0x013cd6e5,0x0085a4db}, + {0x02666658,0x01999999,0x00cccccc,0x01333333,0x01999999,0x00666666,0x03333333,0x00cccccc,0x02666666,0x01999999}, + {0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000}, + {0x01b7dda3,0x01a2ace9,0x025eadbb,0x0003ba8a,0x0083c27e,0x00abe37d,0x01274732,0x00ccacdd,0x00fd78b7,0x019e1d7c} +}; + +ALIGN(16) const bignum25519 ge25519_ecd = { + 0x035978a3,0x00d37284,0x03156ebd,0x006a0a0e,0x0001c029,0x0179e898,0x03a03cbb,0x01ce7198,0x02e2b6ff,0x01480db3 +}; + +ALIGN(16) const bignum25519 ge25519_ec2d = { + 0x02b2f159,0x01a6e509,0x022add7a,0x00d4141d,0x00038052,0x00f3d130,0x03407977,0x019ce331,0x01c56dff,0x00901b67 +}; + +ALIGN(16) const bignum25519 ge25519_sqrtneg1 = { + 0x020ea0b0,0x0186c9d2,0x008f189d,0x0035697f,0x00bd0c60,0x01fbd7a7,0x02804c9e,0x01e16569,0x0004fc1d,0x00ae0c92 +}; + +ALIGN(16) const ge25519_niels ge25519_niels_sliding_multiples[32] = { + {{0x0340913e,0x000e4175,0x03d673a2,0x002e8a05,0x03f4e67c,0x008f8a09,0x00c21a34,0x004cf4b8,0x01298f81,0x0113f4be},{0x018c3b85,0x0124f1bd,0x01c325f7,0x0037dc60,0x033e4cb7,0x003d42c2,0x01a44c32,0x014ca4e1,0x03a33d4b,0x001f3e74},{0x037aaa68,0x00448161,0x0093d579,0x011e6556,0x009b67a0,0x0143598c,0x01bee5ee,0x00b50b43,0x0289f0c6,0x01bc45ed}}, + {{0x00fcd265,0x0047fa29,0x034faacc,0x01ef2e0d,0x00ef4d4f,0x014bd6bd,0x00f98d10,0x014c5026,0x007555bd,0x00aae456},{0x00ee9730,0x016c2a13,0x017155e4,0x01874432,0x00096a10,0x01016732,0x01a8014f,0x011e9823,0x01b9a80f,0x01e85938},{0x01d0d889,0x01a4cfc3,0x034c4295,0x0110e1ae,0x0162508c,0x00f2db4c,0x0072a2c6,0x0098da2e,0x02f12b9b,0x0168a09a}}, + {{0x0047d6ba,0x0060b0e9,0x0136eff2,0x008a5939,0x03540053,0x0064a087,0x02788e5c,0x00be7c67,0x033eb1b5,0x005529f9},{0x00a5bb33,0x00af1102,0x01a05442,0x001e3af7,0x02354123,0x00bfec44,0x01f5862d,0x00dd7ba3,0x03146e20,0x00a51733},{0x012a8285,0x00f6fc60,0x023f9797,0x003e85ee,0x009c3820,0x01bda72d,0x01b3858d,0x00d35683,0x0296b3bb,0x010eaaf9}}, + {{0x023221b1,0x01cb26aa,0x0074f74d,0x0099ddd1,0x01b28085,0x00192c3a,0x013b27c9,0x00fc13bd,0x01d2e531,0x0075bb75},{0x004ea3bf,0x00973425,0x001a4d63,0x01d59cee,0x01d1c0d4,0x00542e49,0x01294114,0x004fce36,0x029283c9,0x01186fa9},{0x01b8b3a2,0x00db7200,0x00935e30,0x003829f5,0x02cc0d7d,0x0077adf3,0x0220dd2c,0x0014ea53,0x01c6a0f9,0x01ea7eec}}, + {{0x039d8064,0x01885f80,0x00337e6d,0x01b7a902,0x02628206,0x015eb044,0x01e30473,0x0191f2d9,0x011fadc9,0x01270169},{0x02a8632f,0x0199e2a9,0x00d8b365,0x017a8de2,0x02994279,0x0086f5b5,0x0119e4e3,0x01eb39d6,0x0338add7,0x00d2e7b4},{0x0045af1b,0x013a2fe4,0x0245e0d6,0x014538ce,0x038bfe0f,0x01d4cf16,0x037e14c9,0x0160d55e,0x0021b008,0x01cf05c8}}, + {{0x01864348,0x01d6c092,0x0070262b,0x014bb844,0x00fb5acd,0x008deb95,0x003aaab5,0x00eff474,0x00029d5c,0x0062ad66},{0x02802ade,0x01c02122,0x01c4e5f7,0x00781181,0x039767fb,0x01703406,0x0342388b,0x01f5e227,0x022546d8,0x0109d6ab},{0x016089e9,0x00cb317f,0x00949b05,0x01099417,0x000c7ad2,0x011a8622,0x0088ccda,0x01290886,0x022b53df,0x00f71954}}, + {{0x027fbf93,0x01c04ecc,0x01ed6a0d,0x004cdbbb,0x02bbf3af,0x00ad5968,0x01591955,0x0094f3a2,0x02d17602,0x00099e20},{0x02007f6d,0x003088a8,0x03db77ee,0x00d5ade6,0x02fe12ce,0x0107ba07,0x0107097d,0x00482a6f,0x02ec346f,0x008d3f5f},{0x032ea378,0x0028465c,0x028e2a6c,0x018efc6e,0x0090df9a,0x01a7e533,0x039bfc48,0x010c745d,0x03daa097,0x0125ee9b}}, + {{0x028ccf0b,0x00f36191,0x021ac081,0x012154c8,0x034e0a6e,0x01b25192,0x00180403,0x01d7eea1,0x00218d05,0x010ed735},{0x03cfeaa0,0x01b300c4,0x008da499,0x0068c4e1,0x0219230a,0x01f2d4d0,0x02defd60,0x00e565b7,0x017f12de,0x018788a4},{0x03d0b516,0x009d8be6,0x03ddcbb3,0x0071b9fe,0x03ace2bd,0x01d64270,0x032d3ec9,0x01084065,0x0210ae4d,0x01447584}}, + {{0x0020de87,0x00e19211,0x01b68102,0x00b5ac97,0x022873c0,0x01942d25,0x01271394,0x0102073f,0x02fe2482,0x01c69ff9},{0x010e9d81,0x019dbbe5,0x0089f258,0x006e06b8,0x02951883,0x018f1248,0x019b3237,0x00bc7553,0x024ddb85,0x01b4c964},{0x01c8c854,0x0060ae29,0x01406d8e,0x01cff2f9,0x00cff451,0x01778d0c,0x03ac8c41,0x01552e59,0x036559ee,0x011d1b12}}, + {{0x00741147,0x0151b219,0x01092690,0x00e877e6,0x01f4d6bb,0x0072a332,0x01cd3b03,0x00dadff2,0x0097db5e,0x0086598d},{0x01c69a2b,0x01decf1b,0x02c2fa6e,0x013b7c4f,0x037beac8,0x013a16b5,0x028e7bda,0x01f6e8ac,0x01e34fe9,0x01726947},{0x01f10e67,0x003c73de,0x022b7ea2,0x010f32c2,0x03ff776a,0x00142277,0x01d38b88,0x00776138,0x03c60822,0x01201140}}, + {{0x0236d175,0x0008748e,0x03c6476d,0x013f4cdc,0x02eed02a,0x00838a47,0x032e7210,0x018bcbb3,0x00858de4,0x01dc7826},{0x00a37fc7,0x0127b40b,0x01957884,0x011d30ad,0x02816683,0x016e0e23,0x00b76be4,0x012db115,0x02516506,0x0154ce62},{0x00451edf,0x00bd749e,0x03997342,0x01cc2c4c,0x00eb6975,0x01a59508,0x03a516cf,0x00c228ef,0x0168ff5a,0x01697b47}}, + {{0x00527359,0x01783156,0x03afd75c,0x00ce56dc,0x00e4b970,0x001cabe9,0x029e0f6d,0x0188850c,0x0135fefd,0x00066d80},{0x02150e83,0x01448abf,0x02bb0232,0x012bf259,0x033c8268,0x00711e20,0x03fc148f,0x005e0e70,0x017d8bf9,0x0112b2e2},{0x02134b83,0x001a0517,0x0182c3cc,0x00792182,0x0313d799,0x001a3ed7,0x0344547e,0x01f24a0d,0x03de6ad2,0x00543127}}, + {{0x00dca868,0x00618f27,0x015a1709,0x00ddc38a,0x0320fd13,0x0036168d,0x0371ab06,0x01783fc7,0x0391e05f,0x01e29b5d},{0x01471138,0x00fca542,0x00ca31cf,0x01ca7bad,0x0175bfbc,0x01a708ad,0x03bce212,0x01244215,0x0075bb99,0x01acad68},{0x03a0b976,0x01dc12d1,0x011aab17,0x00aba0ba,0x029806cd,0x0142f590,0x018fd8ea,0x01a01545,0x03c4ad55,0x01c971ff}}, + {{0x00d098c0,0x000afdc7,0x006cd230,0x01276af3,0x03f905b2,0x0102994c,0x002eb8a4,0x015cfbeb,0x025f855f,0x01335518},{0x01cf99b2,0x0099c574,0x01a69c88,0x00881510,0x01cd4b54,0x0112109f,0x008abdc5,0x0074647a,0x0277cb1f,0x01e53324},{0x02ac5053,0x01b109b0,0x024b095e,0x016997b3,0x02f26bb6,0x00311021,0x00197885,0x01d0a55a,0x03b6fcc8,0x01c020d5}}, + {{0x02584a34,0x00e7eee0,0x03257a03,0x011e95a3,0x011ead91,0x00536202,0x00b1ce24,0x008516c6,0x03669d6d,0x004ea4a8},{0x00773f01,0x0019c9ce,0x019f6171,0x01d4afde,0x02e33323,0x01ad29b6,0x02ead1dc,0x01ed51a5,0x01851ad0,0x001bbdfa},{0x00577de5,0x00ddc730,0x038b9952,0x00f281ae,0x01d50390,0x0002e071,0x000780ec,0x010d448d,0x01f8a2af,0x00f0a5b7}}, + {{0x031f2541,0x00d34bae,0x0323ff9d,0x003a056d,0x02e25443,0x00a1ad05,0x00d1bee8,0x002f7f8e,0x03007477,0x002a24b1},{0x0114a713,0x01457e76,0x032255d5,0x01cc647f,0x02a4bdef,0x0153d730,0x00118bcf,0x00f755ff,0x013490c7,0x01ea674e},{0x02bda3e8,0x00bb490d,0x00f291ea,0x000abf40,0x01dea321,0x002f9ce0,0x00b2b193,0x00fa54b5,0x0128302f,0x00a19d8b}}, + {{0x022ef5bd,0x01638af3,0x038c6f8a,0x01a33a3d,0x039261b2,0x01bb89b8,0x010bcf9d,0x00cf42a9,0x023d6f17,0x01da1bca},{0x00e35b25,0x000d824f,0x0152e9cf,0x00ed935d,0x020b8460,0x01c7b83f,0x00c969e5,0x01a74198,0x0046a9d9,0x00cbc768},{0x01597c6a,0x0144a99b,0x00a57551,0x0018269c,0x023c464c,0x0009b022,0x00ee39e1,0x0114c7f2,0x038a9ad2,0x01584c17}}, + {{0x03b0c0d5,0x00b30a39,0x038a6ce4,0x01ded83a,0x01c277a6,0x01010a61,0x0346d3eb,0x018d995e,0x02f2c57c,0x000c286b},{0x0092aed1,0x0125e37b,0x027ca201,0x001a6b6b,0x03290f55,0x0047ba48,0x018d916c,0x01a59062,0x013e35d4,0x0002abb1},{0x003ad2aa,0x007ddcc0,0x00c10f76,0x0001590b,0x002cfca6,0x000ed23e,0x00ee4329,0x00900f04,0x01c24065,0x0082fa70}}, + {{0x02025e60,0x003912b8,0x0327041c,0x017e5ee5,0x02c0ecec,0x015a0d1c,0x02b1ce7c,0x0062220b,0x0145067e,0x01a5d931},{0x009673a6,0x00e1f609,0x00927c2a,0x016faa37,0x01650ef0,0x016f63b5,0x03cd40e1,0x003bc38f,0x0361f0ac,0x01d42acc},{0x02f81037,0x008ca0e8,0x017e23d1,0x011debfe,0x01bcbb68,0x002e2563,0x03e8add6,0x000816e5,0x03fb7075,0x0153e5ac}}, + {{0x02b11ecd,0x016bf185,0x008f22ef,0x00e7d2bb,0x0225d92e,0x00ece785,0x00508873,0x017e16f5,0x01fbe85d,0x01e39a0e},{0x01669279,0x017c810a,0x024941f5,0x0023ebeb,0x00eb7688,0x005760f1,0x02ca4146,0x0073cde7,0x0052bb75,0x00f5ffa7},{0x03b8856b,0x00cb7dcd,0x02f14e06,0x001820d0,0x01d74175,0x00e59e22,0x03fba550,0x00484641,0x03350088,0x01c3c9a3}}, + {{0x00dcf355,0x0104481c,0x0022e464,0x01f73fe7,0x00e03325,0x0152b698,0x02ef769a,0x00973663,0x00039b8c,0x0101395b},{0x01805f47,0x019160ec,0x03832cd0,0x008b06eb,0x03d4d717,0x004cb006,0x03a75b8f,0x013b3d30,0x01cfad88,0x01f034d1},{0x0078338a,0x01c7d2e3,0x02bc2b23,0x018b3f05,0x0280d9aa,0x005f3d44,0x0220a95a,0x00eeeb97,0x0362aaec,0x00835d51}}, + {{0x01b9f543,0x013fac4d,0x02ad93ae,0x018ef464,0x0212cdf7,0x01138ba9,0x011583ab,0x019c3d26,0x028790b4,0x00e2e2b6},{0x033bb758,0x01f0dbf1,0x03734bd1,0x0129b1e5,0x02b3950e,0x003bc922,0x01a53ec8,0x018c5532,0x006f3cee,0x00ae3c79},{0x0351f95d,0x0012a737,0x03d596b8,0x017658fe,0x00ace54a,0x008b66da,0x0036c599,0x012a63a2,0x032ceba1,0x00126bac}}, + {{0x03dcfe7e,0x019f4f18,0x01c81aee,0x0044bc2b,0x00827165,0x014f7c13,0x03b430f0,0x00bf96cc,0x020c8d62,0x01471997},{0x01fc7931,0x001f42dd,0x00ba754a,0x005bd339,0x003fbe49,0x016b3930,0x012a159c,0x009f83b0,0x03530f67,0x01e57b85},{0x02ecbd81,0x0096c294,0x01fce4a9,0x017701a5,0x0175047d,0x00ee4a31,0x012686e5,0x008efcd4,0x0349dc54,0x01b3466f}}, + {{0x02179ca3,0x01d86414,0x03f0afd0,0x00305964,0x015c7428,0x0099711e,0x015d5442,0x00c71014,0x01b40b2e,0x01d483cf},{0x01afc386,0x01984859,0x036203ff,0x0045c6a8,0x0020a8aa,0x00990baa,0x03313f10,0x007ceede,0x027429e4,0x017806ce},{0x039357a1,0x0142f8f4,0x0294a7b6,0x00eaccf4,0x0259edb3,0x01311e6e,0x004d326f,0x0130c346,0x01ccef3c,0x01c424b2}}, + {{0x0364918c,0x00148fc0,0x01638a7b,0x01a1fd5b,0x028ad013,0x0081e5a4,0x01a54f33,0x0174e101,0x003d0257,0x003a856c},{0x00051dcf,0x00f62b1d,0x0143d0ad,0x0042adbd,0x000fda90,0x01743ceb,0x0173e5e4,0x017bc749,0x03b7137a,0x0105ce96},{0x00f9218a,0x015b8c7c,0x00e102f8,0x0158d7e2,0x0169a5b8,0x00b2f176,0x018b347a,0x014cfef2,0x0214a4e3,0x017f1595}}, + {{0x006d7ae5,0x0195c371,0x0391e26d,0x0062a7c6,0x003f42ab,0x010dad86,0x024f8198,0x01542b2a,0x0014c454,0x0189c471},{0x0390988e,0x00b8799d,0x02e44912,0x0078e2e6,0x00075654,0x01923eed,0x0040cd72,0x00a37c76,0x0009d466,0x00c8531d},{0x02651770,0x00609d01,0x0286c265,0x0134513c,0x00ee9281,0x005d223c,0x035c760c,0x00679b36,0x0073ecb8,0x016faa50}}, + {{0x02c89be4,0x016fc244,0x02f38c83,0x018beb72,0x02b3ce2c,0x0097b065,0x034f017b,0x01dd957f,0x00148f61,0x00eab357},{0x0343d2f8,0x003398fc,0x011e368e,0x00782a1f,0x00019eea,0x00117b6f,0x0128d0d1,0x01a5e6bb,0x01944f1b,0x012b41e1},{0x03318301,0x018ecd30,0x0104d0b1,0x0038398b,0x03726701,0x019da88c,0x002d9769,0x00a7a681,0x031d9028,0x00ebfc32}}, + {{0x0220405e,0x0171face,0x02d930f8,0x017f6d6a,0x023b8c47,0x0129d5f9,0x02972456,0x00a3a524,0x006f4cd2,0x004439fa},{0x00c53505,0x0190c2fd,0x00507244,0x009930f9,0x01a39270,0x01d327c6,0x0399bc47,0x01cfe13d,0x0332bd99,0x00b33e7d},{0x0203f5e4,0x003627b5,0x00018af8,0x01478581,0x004a2218,0x002e3bb7,0x039384d0,0x0146ea62,0x020b9693,0x0017155f}}, + {{0x03c97e6f,0x00738c47,0x03b5db1f,0x01808fcf,0x01e8fc98,0x01ed25dd,0x01bf5045,0x00eb5c2b,0x0178fe98,0x01b85530},{0x01c20eb0,0x01aeec22,0x030b9eee,0x01b7d07e,0x0187e16f,0x014421fb,0x009fa731,0x0040b6d7,0x00841861,0x00a27fbc},{0x02d69abf,0x0058cdbf,0x0129f9ec,0x013c19ae,0x026c5b93,0x013a7fe7,0x004bb2ba,0x0063226f,0x002a95ca,0x01abefd9}}, + {{0x02f5d2c1,0x00378318,0x03734fb5,0x01258073,0x0263f0f6,0x01ad70e0,0x01b56d06,0x01188fbd,0x011b9503,0x0036d2e1},{0x0113a8cc,0x01541c3e,0x02ac2bbc,0x01d95867,0x01f47459,0x00ead489,0x00ab5b48,0x01db3b45,0x00edb801,0x004b024f},{0x00b8190f,0x011fe4c2,0x00621f82,0x010508d7,0x001a5a76,0x00c7d7fd,0x03aab96d,0x019cd9dc,0x019c6635,0x00ceaa1e}}, + {{0x01085cf2,0x01fd47af,0x03e3f5e1,0x004b3e99,0x01e3d46a,0x0060033c,0x015ff0a8,0x0150cdd8,0x029e8e21,0x008cf1bc},{0x00156cb1,0x003d623f,0x01a4f069,0x00d8d053,0x01b68aea,0x01ca5ab6,0x0316ae43,0x0134dc44,0x001c8d58,0x0084b343},{0x0318c781,0x0135441f,0x03a51a5e,0x019293f4,0x0048bb37,0x013d3341,0x0143151e,0x019c74e1,0x00911914,0x0076ddde}}, + {{0x006bc26f,0x00d48e5f,0x00227bbe,0x00629ea8,0x01ea5f8b,0x0179a330,0x027a1d5f,0x01bf8f8e,0x02d26e2a,0x00c6b65e},{0x01701ab6,0x0051da77,0x01b4b667,0x00a0ce7c,0x038ae37b,0x012ac852,0x03a0b0fe,0x0097c2bb,0x00a017d2,0x01eb8b2a},{0x0120b962,0x0005fb42,0x0353b6fd,0x0061f8ce,0x007a1463,0x01560a64,0x00e0a792,0x01907c92,0x013a6622,0x007b47f1}} +}; + +// *************** modm-donna-32bit.h *************** // + +const bignum256modm modm_m = { + 0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8, + 0x00000014, 0x00000000, 0x00000000, 0x00000000, + 0x00001000 +}; + +const bignum256modm modm_mu = { + 0x0a2c131b, 0x3673968c, 0x06329a7e, 0x01885742, + 0x3fffeb21, 0x3fffffff, 0x3fffffff, 0x3fffffff, + 0x000fffff +}; + +/* multiples of p */ +const word32 twoP0 = 0x07ffffda; +const word32 twoP13579 = 0x03fffffe; +const word32 twoP2468 = 0x07fffffe; +const word32 fourP0 = 0x0fffffb4; +const word32 fourP13579 = 0x07fffffc; +const word32 fourP2468 = 0x0ffffffc; + +// *************** ed25519-donna-basepoint-table.h *************** // + +/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ +ALIGN(16) const byte ge25519_niels_base_multiples[256][96] = { + {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f}, + {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49}, + {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54}, + {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44}, + {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68}, + {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78}, + {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23}, + {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58}, + {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10}, + {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56}, + {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14}, + {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37}, + {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02}, + {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12}, + {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f}, + {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41}, + {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e}, + {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14}, + {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41}, + {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59}, + {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49}, + {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20}, + {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b}, + {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74}, + {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69}, + {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b}, + {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e}, + {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39}, + {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33}, + {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61}, + {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45}, + {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d}, + {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c}, + {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21}, + {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a}, + {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39}, + {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22}, + {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50}, + {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d}, + {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45}, + {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d}, + {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c}, + {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27}, + {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f}, + {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f}, + {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22}, + {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c}, + {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19}, + {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71}, + {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c}, + {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a}, + {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02}, + {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31}, + {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48}, + {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c}, + {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f}, + {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60}, + {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63}, + {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70}, + {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41}, + {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24}, + {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16}, + {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78}, + {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13}, + {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a}, + {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b}, + {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d}, + {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74}, + {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58}, + {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12}, + {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d}, + {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b}, + {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c}, + {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04}, + {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76}, + {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11}, + {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f}, + {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55}, + {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57}, + {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21}, + {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a}, + {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19}, + {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60}, + {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36}, + {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07}, + {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57}, + {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05}, + {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f}, + {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72}, + {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00}, + {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c}, + {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06}, + {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15}, + {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07}, + {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51}, + {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77}, + {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e}, + {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09}, + {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56}, + {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43}, + {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27}, + {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b}, + {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46}, + {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69}, + {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14}, + {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55}, + {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13}, + {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d}, + {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31}, + {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05}, + {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f}, + {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a}, + {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10}, + {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25}, + {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08}, + {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a}, + {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f}, + {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38}, + {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65}, + {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c}, + {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e}, + {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35}, + {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47}, + {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47}, + {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74}, + {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a}, + {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56}, + {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d}, + {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44}, + {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58}, + {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70}, + {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e}, + {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41}, + {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11}, + {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f}, + {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10}, + {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72}, + {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00}, + {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05}, + {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00}, + {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b}, + {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05}, + {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f}, + {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f}, + {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40}, + {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b}, + {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02}, + {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c}, + {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f}, + {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29}, + {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71}, + {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a}, + {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06}, + {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30}, + {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b}, + {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24}, + {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49}, + {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53}, + {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02}, + {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e}, + {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d}, + {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f}, + {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07}, + {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f}, + {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b}, + {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f}, + {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12}, + {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30}, + {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45}, + {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a}, + {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13}, + {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f}, + {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a}, + {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12}, + {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b}, + {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10}, + {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b}, + {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e}, + {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f}, + {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00}, + {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33}, + {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63}, + {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b}, + {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16}, + {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57}, + {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e}, + {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73}, + {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76}, + {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e}, + {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16}, + {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45}, + {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67}, + {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a}, + {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a}, + {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e}, + {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62}, + {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e}, + {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e}, + {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78}, + {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46}, + {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a}, + {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26}, + {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b}, + {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d}, + {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45}, + {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26}, + {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62}, + {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d}, + {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61}, + {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79}, + {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39}, + {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63}, + {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34}, + {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56}, + {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e}, + {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26}, + {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f}, + {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f}, + {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b}, + {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39}, + {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51}, + {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f}, + {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f}, + {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13}, + {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c}, + {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60}, + {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15}, + {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32}, + {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b}, + {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02}, + {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c}, + {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05}, + {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67}, + {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c}, + {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37}, + {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63}, + {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68}, + {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c}, + {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c}, + {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26}, + {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08}, + {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19}, + {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41}, + {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b}, + {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08}, + {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48}, + {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54}, + {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c}, + {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f}, + {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25}, + {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55}, + {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a}, + {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59}, + {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70}, + {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27}, + {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f} +}; + +NAMESPACE_END // Arch32 +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_DOXYGEN_PROCESSING +#endif // CRYPTOPP_DONNA_32_H diff --git a/third_party/cryptoppwin/include/cryptopp/donna_64.h b/third_party/cryptoppwin/include/cryptopp/donna_64.h new file mode 100644 index 00000000..3180d606 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/donna_64.h @@ -0,0 +1,457 @@ +// donna_64.h - written and placed in public domain by Jeffrey Walton +// Crypto++ specific implementation wrapped around Andrew +// Moon's public domain curve25519-donna and ed25519-donna, +// https://github.com/floodyberry/curve25519-donna and +// https://github.com/floodyberry/ed25519-donna. + +// This source file multiplexes two different repos using namespaces. This +// was a little easier from a project management standpoint. We only need +// two files per architecture at the expense of namespaces and bloat. + +#ifndef CRYPTOPP_DONNA_64_H +#define CRYPTOPP_DONNA_64_H +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + +#include "config.h" + +#if defined(CRYPTOPP_MSC_VERSION) +# include +# pragma intrinsic(_umul128) +# pragma intrinsic(__shiftright128) +#endif + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) +NAMESPACE_BEGIN(Arch64) + +using CryptoPP::byte; +using CryptoPP::word32; +using CryptoPP::word64; + +// ******************** x25519 Agreement ************************* // + +#define ALIGN(n) CRYPTOPP_ALIGN_DATA(n) +typedef word64 bignum25519[5]; + +const byte basePoint[32] = {9}; +const word64 reduce_mask_40 = ((word64)1 << 40) - 1; +const word64 reduce_mask_51 = ((word64)1 << 51) - 1; +const word64 reduce_mask_52 = ((word64)1 << 52) - 1; +const word64 reduce_mask_56 = ((word64)1 << 56) - 1; + +const word64 two54m152 = (((word64)1) << 54) - 152; +const word64 two54m8 = (((word64)1) << 54) - 8; + +#if defined(CRYPTOPP_WORD128_AVAILABLE) +using CryptoPP::word128; +# define lo128(a) ((word64)a) +# define hi128(a) ((word64)(a >> 64)) +# define add128(a,b) a += b; +# define add128_64(a,b) a += (word64)b; +# define mul64x64_128(out,a,b) out = (word128)a * b; +# define shr128(out,in,shift) out = (word64)(in >> (shift)); +# define shl128(out,in,shift) out = (word64)((in << shift) >> 64); + +#elif defined(CRYPTOPP_MSC_VERSION) +struct word128 { word64 lo, hi; }; +# define mul64x64_128(out,a,b) out.lo = _umul128(a,b,&out.hi); +# define shr128_pair(out,hi,lo,shift) out = __shiftright128(lo, hi, shift); +# define shl128_pair(out,hi,lo,shift) out = __shiftleft128(lo, hi, shift); +# define shr128(out,in,shift) shr128_pair(out, in.hi, in.lo, shift) +# define shl128(out,in,shift) shl128_pair(out, in.hi, in.lo, shift) +# define add128(a,b) { word64 p = a.lo; a.lo += b.lo; a.hi += b.hi + (a.lo < p); } +# define add128_64(a,b) { word64 p = a.lo; a.lo += b; a.hi += (a.lo < p); } +# define lo128(a) (a.lo) +# define hi128(a) (a.hi) + +#elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__)) +struct word128 { word64 lo, hi; }; +# define mul64x64_128(out,a,b) __asm__ ("mulq %3" : "=a" (out.lo), "=d" (out.hi) : "a" (a), "rm" (b)); +# define shr128_pair(out,hi,lo,shift) __asm__ ("shrdq %2,%1,%0" : "+r" (lo) : "r" (hi), "J" (shift)); out = lo; +# define shl128_pair(out,hi,lo,shift) __asm__ ("shldq %2,%1,%0" : "+r" (hi) : "r" (lo), "J" (shift)); out = hi; +# define shr128(out,in,shift) shr128_pair(out,in.hi, in.lo, shift) +# define shl128(out,in,shift) shl128_pair(out,in.hi, in.lo, shift) +# define add128(a,b) __asm__ ("addq %4,%2; adcq %5,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b.lo), "rm" (b.hi) : "cc"); +# define add128_64(a,b) __asm__ ("addq %4,%2; adcq $0,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b) : "cc"); +# define lo128(a) (a.lo) +# define hi128(a) (a.hi) + +#else +// https://groups.google.com/forum/#!forum/cryptopp-users +# error "Unsupported platform" +#endif + +// ****************** ed25519 Signatures *********************** // + +typedef byte hash_512bits[64]; + +const int bignum256modm_bits_per_limb = 56; +const int bignum256modm_limb_size = 5; +typedef word64 bignum256modm_element_t; +typedef bignum256modm_element_t bignum256modm[5]; + +/* multiples of p */ +const word64 twoP0 = 0x0fffffffffffda; +const word64 twoP1234 = 0x0ffffffffffffe; +const word64 fourP0 = 0x1fffffffffffb4; +const word64 fourP1234 = 0x1ffffffffffffc; + +struct ge25519 { + bignum25519 x, y, z, t; +}; + +struct ge25519_p1p1 { + bignum25519 x, y, z, t; +}; + +struct ge25519_niels { + bignum25519 ysubx, xaddy, t2d; +}; + +struct ge25519_pniels { + bignum25519 ysubx, xaddy, z, t2d; +}; + +#define S1_SWINDOWSIZE 5 +#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2)) +#define S2_SWINDOWSIZE 7 +#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2)) + +// *************** ed25519-donna-64bit-tables.h *************** // + +const ge25519 ge25519_basepoint = { + {0x00062d608f25d51a,0x000412a4b4f6592a,0x00075b7171a4b31d,0x0001ff60527118fe,0x000216936d3cd6e5}, + {0x0006666666666658,0x0004cccccccccccc,0x0001999999999999,0x0003333333333333,0x0006666666666666}, + {0x0000000000000001,0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000}, + {0x00068ab3a5b7dda3,0x00000eea2a5eadbb,0x0002af8df483c27e,0x000332b375274732,0x00067875f0fd78b7} +}; + +const bignum25519 ge25519_ecd = { + 0x00034dca135978a3,0x0001a8283b156ebd,0x0005e7a26001c029,0x000739c663a03cbb,0x00052036cee2b6ff +}; + +const bignum25519 ge25519_ec2d = { + 0x00069b9426b2f159,0x00035050762add7a,0x0003cf44c0038052,0x0006738cc7407977,0x0002406d9dc56dff +}; + +const bignum25519 ge25519_sqrtneg1 = { + 0x00061b274a0ea0b0,0x0000d5a5fc8f189d,0x0007ef5e9cbd0c60,0x00078595a6804c9e,0x0002b8324804fc1d +}; + +const ge25519_niels ge25519_niels_sliding_multiples[32] = { + {{0x00003905d740913e,0x0000ba2817d673a2,0x00023e2827f4e67c,0x000133d2e0c21a34,0x00044fd2f9298f81},{0x000493c6f58c3b85,0x0000df7181c325f7,0x0000f50b0b3e4cb7,0x0005329385a44c32,0x00007cf9d3a33d4b},{0x00011205877aaa68,0x000479955893d579,0x00050d66309b67a0,0x0002d42d0dbee5ee,0x0006f117b689f0c6}}, + {{0x00011fe8a4fcd265,0x0007bcb8374faacc,0x00052f5af4ef4d4f,0x0005314098f98d10,0x0002ab91587555bd},{0x0005b0a84cee9730,0x00061d10c97155e4,0x0004059cc8096a10,0x00047a608da8014f,0x0007a164e1b9a80f},{0x0006933f0dd0d889,0x00044386bb4c4295,0x0003cb6d3162508c,0x00026368b872a2c6,0x0005a2826af12b9b}}, + {{0x000182c3a447d6ba,0x00022964e536eff2,0x000192821f540053,0x0002f9f19e788e5c,0x000154a7e73eb1b5},{0x0002bc4408a5bb33,0x000078ebdda05442,0x0002ffb112354123,0x000375ee8df5862d,0x0002945ccf146e20},{0x0003dbf1812a8285,0x0000fa17ba3f9797,0x0006f69cb49c3820,0x00034d5a0db3858d,0x00043aabe696b3bb}}, + {{0x00072c9aaa3221b1,0x000267774474f74d,0x000064b0e9b28085,0x0003f04ef53b27c9,0x0001d6edd5d2e531},{0x00025cd0944ea3bf,0x00075673b81a4d63,0x000150b925d1c0d4,0x00013f38d9294114,0x000461bea69283c9},{0x00036dc801b8b3a2,0x0000e0a7d4935e30,0x0001deb7cecc0d7d,0x000053a94e20dd2c,0x0007a9fbb1c6a0f9}}, + {{0x0006217e039d8064,0x0006dea408337e6d,0x00057ac112628206,0x000647cb65e30473,0x00049c05a51fadc9},{0x0006678aa6a8632f,0x0005ea3788d8b365,0x00021bd6d6994279,0x0007ace75919e4e3,0x00034b9ed338add7},{0x0004e8bf9045af1b,0x000514e33a45e0d6,0x0007533c5b8bfe0f,0x000583557b7e14c9,0x00073c172021b008}}, + {{0x00075b0249864348,0x00052ee11070262b,0x000237ae54fb5acd,0x0003bfd1d03aaab5,0x00018ab598029d5c},{0x000700848a802ade,0x0001e04605c4e5f7,0x0005c0d01b9767fb,0x0007d7889f42388b,0x0004275aae2546d8},{0x00032cc5fd6089e9,0x000426505c949b05,0x00046a18880c7ad2,0x0004a4221888ccda,0x0003dc65522b53df}}, + {{0x0007013b327fbf93,0x0001336eeded6a0d,0x0002b565a2bbf3af,0x000253ce89591955,0x0000267882d17602},{0x0000c222a2007f6d,0x000356b79bdb77ee,0x00041ee81efe12ce,0x000120a9bd07097d,0x000234fd7eec346f},{0x0000a119732ea378,0x00063bf1ba8e2a6c,0x00069f94cc90df9a,0x000431d1779bfc48,0x000497ba6fdaa097}}, + {{0x0003cd86468ccf0b,0x00048553221ac081,0x0006c9464b4e0a6e,0x00075fba84180403,0x00043b5cd4218d05},{0x0006cc0313cfeaa0,0x0001a313848da499,0x0007cb534219230a,0x00039596dedefd60,0x00061e22917f12de},{0x0002762f9bd0b516,0x0001c6e7fbddcbb3,0x00075909c3ace2bd,0x00042101972d3ec9,0x000511d61210ae4d}}, + {{0x000386484420de87,0x0002d6b25db68102,0x000650b4962873c0,0x0004081cfd271394,0x00071a7fe6fe2482},{0x000676ef950e9d81,0x0001b81ae089f258,0x00063c4922951883,0x0002f1d54d9b3237,0x0006d325924ddb85},{0x000182b8a5c8c854,0x00073fcbe5406d8e,0x0005de3430cff451,0x000554b967ac8c41,0x0004746c4b6559ee}}, + {{0x000546c864741147,0x0003a1df99092690,0x0001ca8cc9f4d6bb,0x00036b7fc9cd3b03,0x000219663497db5e},{0x00077b3c6dc69a2b,0x0004edf13ec2fa6e,0x0004e85ad77beac8,0x0007dba2b28e7bda,0x0005c9a51de34fe9},{0x0000f1cf79f10e67,0x00043ccb0a2b7ea2,0x00005089dfff776a,0x0001dd84e1d38b88,0x0004804503c60822}}, + {{0x000021d23a36d175,0x0004fd3373c6476d,0x00020e291eeed02a,0x00062f2ecf2e7210,0x000771e098858de4},{0x00049ed02ca37fc7,0x000474c2b5957884,0x0005b8388e816683,0x0004b6c454b76be4,0x000553398a516506},{0x0002f5d278451edf,0x000730b133997342,0x0006965420eb6975,0x000308a3bfa516cf,0x0005a5ed1d68ff5a}}, + {{0x0005e0c558527359,0x0003395b73afd75c,0x000072afa4e4b970,0x00062214329e0f6d,0x000019b60135fefd},{0x0005122afe150e83,0x0004afc966bb0232,0x0001c478833c8268,0x00017839c3fc148f,0x00044acb897d8bf9},{0x000068145e134b83,0x0001e4860982c3cc,0x000068fb5f13d799,0x0007c9283744547e,0x000150c49fde6ad2}}, + {{0x0001863c9cdca868,0x0003770e295a1709,0x0000d85a3720fd13,0x0005e0ff1f71ab06,0x00078a6d7791e05f},{0x0003f29509471138,0x000729eeb4ca31cf,0x00069c22b575bfbc,0x0004910857bce212,0x0006b2b5a075bb99},{0x0007704b47a0b976,0x0002ae82e91aab17,0x00050bd6429806cd,0x00068055158fd8ea,0x000725c7ffc4ad55}}, + {{0x00002bf71cd098c0,0x00049dabcc6cd230,0x00040a6533f905b2,0x000573efac2eb8a4,0x0004cd54625f855f},{0x00026715d1cf99b2,0x0002205441a69c88,0x000448427dcd4b54,0x0001d191e88abdc5,0x000794cc9277cb1f},{0x0006c426c2ac5053,0x0005a65ece4b095e,0x0000c44086f26bb6,0x0007429568197885,0x0007008357b6fcc8}}, + {{0x00039fbb82584a34,0x00047a568f257a03,0x00014d88091ead91,0x0002145b18b1ce24,0x00013a92a3669d6d},{0x0000672738773f01,0x000752bf799f6171,0x0006b4a6dae33323,0x0007b54696ead1dc,0x00006ef7e9851ad0},{0x0003771cc0577de5,0x0003ca06bb8b9952,0x00000b81c5d50390,0x00043512340780ec,0x0003c296ddf8a2af}}, + {{0x00034d2ebb1f2541,0x0000e815b723ff9d,0x000286b416e25443,0x0000bdfe38d1bee8,0x0000a892c7007477},{0x000515f9d914a713,0x00073191ff2255d5,0x00054f5cc2a4bdef,0x0003dd57fc118bcf,0x0007a99d393490c7},{0x0002ed2436bda3e8,0x00002afd00f291ea,0x0000be7381dea321,0x0003e952d4b2b193,0x000286762d28302f}}, + {{0x00058e2bce2ef5bd,0x00068ce8f78c6f8a,0x0006ee26e39261b2,0x00033d0aa50bcf9d,0x0007686f2a3d6f17},{0x000036093ce35b25,0x0003b64d7552e9cf,0x00071ee0fe0b8460,0x00069d0660c969e5,0x00032f1da046a9d9},{0x000512a66d597c6a,0x0000609a70a57551,0x000026c08a3c464c,0x0004531fc8ee39e1,0x000561305f8a9ad2}}, + {{0x0002cc28e7b0c0d5,0x00077b60eb8a6ce4,0x0004042985c277a6,0x000636657b46d3eb,0x000030a1aef2c57c},{0x0004978dec92aed1,0x000069adae7ca201,0x00011ee923290f55,0x00069641898d916c,0x00000aaec53e35d4},{0x0001f773003ad2aa,0x000005642cc10f76,0x00003b48f82cfca6,0x0002403c10ee4329,0x00020be9c1c24065}}, + {{0x0000e44ae2025e60,0x0005f97b9727041c,0x0005683472c0ecec,0x000188882eb1ce7c,0x00069764c545067e},{0x000387d8249673a6,0x0005bea8dc927c2a,0x0005bd8ed5650ef0,0x0000ef0e3fcd40e1,0x000750ab3361f0ac},{0x00023283a2f81037,0x000477aff97e23d1,0x0000b8958dbcbb68,0x0000205b97e8add6,0x00054f96b3fb7075}}, + {{0x0005afc616b11ecd,0x00039f4aec8f22ef,0x0003b39e1625d92e,0x0005f85bd4508873,0x00078e6839fbe85d},{0x0005f20429669279,0x00008fafae4941f5,0x00015d83c4eb7688,0x0001cf379eca4146,0x0003d7fe9c52bb75},{0x00032df737b8856b,0x0000608342f14e06,0x0003967889d74175,0x0001211907fba550,0x00070f268f350088}}, + {{0x0004112070dcf355,0x0007dcff9c22e464,0x00054ada60e03325,0x00025cd98eef769a,0x000404e56c039b8c},{0x00064583b1805f47,0x00022c1baf832cd0,0x000132c01bd4d717,0x0004ecf4c3a75b8f,0x0007c0d345cfad88},{0x00071f4b8c78338a,0x00062cfc16bc2b23,0x00017cf51280d9aa,0x0003bbae5e20a95a,0x00020d754762aaec}}, + {{0x0004feb135b9f543,0x00063bd192ad93ae,0x00044e2ea612cdf7,0x000670f4991583ab,0x00038b8ada8790b4},{0x0007c36fc73bb758,0x0004a6c797734bd1,0x0000ef248ab3950e,0x00063154c9a53ec8,0x0002b8f1e46f3cee},{0x00004a9cdf51f95d,0x0005d963fbd596b8,0x00022d9b68ace54a,0x0004a98e8836c599,0x000049aeb32ceba1}}, + {{0x00067d3c63dcfe7e,0x000112f0adc81aee,0x00053df04c827165,0x0002fe5b33b430f0,0x00051c665e0c8d62},{0x00007d0b75fc7931,0x00016f4ce4ba754a,0x0005ace4c03fbe49,0x00027e0ec12a159c,0x000795ee17530f67},{0x00025b0a52ecbd81,0x0005dc0695fce4a9,0x0003b928c575047d,0x00023bf3512686e5,0x0006cd19bf49dc54}}, + {{0x0007619052179ca3,0x0000c16593f0afd0,0x000265c4795c7428,0x00031c40515d5442,0x0007520f3db40b2e},{0x0006612165afc386,0x0001171aa36203ff,0x0002642ea820a8aa,0x0001f3bb7b313f10,0x0005e01b3a7429e4},{0x00050be3d39357a1,0x0003ab33d294a7b6,0x0004c479ba59edb3,0x0004c30d184d326f,0x00071092c9ccef3c}}, + {{0x0000523f0364918c,0x000687f56d638a7b,0x00020796928ad013,0x0005d38405a54f33,0x0000ea15b03d0257},{0x0003d8ac74051dcf,0x00010ab6f543d0ad,0x0005d0f3ac0fda90,0x0005ef1d2573e5e4,0x0004173a5bb7137a},{0x00056e31f0f9218a,0x0005635f88e102f8,0x0002cbc5d969a5b8,0x000533fbc98b347a,0x0005fc565614a4e3}}, + {{0x0006570dc46d7ae5,0x00018a9f1b91e26d,0x000436b6183f42ab,0x000550acaa4f8198,0x00062711c414c454},{0x0002e1e67790988e,0x0001e38b9ae44912,0x000648fbb4075654,0x00028df1d840cd72,0x0003214c7409d466},{0x0001827406651770,0x0004d144f286c265,0x00017488f0ee9281,0x00019e6cdb5c760c,0x0005bea94073ecb8}}, + {{0x0005bf0912c89be4,0x00062fadcaf38c83,0x00025ec196b3ce2c,0x00077655ff4f017b,0x0003aacd5c148f61},{0x0000ce63f343d2f8,0x0001e0a87d1e368e,0x000045edbc019eea,0x0006979aed28d0d1,0x0004ad0785944f1b},{0x00063b34c3318301,0x0000e0e62d04d0b1,0x000676a233726701,0x00029e9a042d9769,0x0003aff0cb1d9028}}, + {{0x0005c7eb3a20405e,0x0005fdb5aad930f8,0x0004a757e63b8c47,0x00028e9492972456,0x000110e7e86f4cd2},{0x0006430bf4c53505,0x000264c3e4507244,0x00074c9f19a39270,0x00073f84f799bc47,0x0002ccf9f732bd99},{0x0000d89ed603f5e4,0x00051e1604018af8,0x0000b8eedc4a2218,0x00051ba98b9384d0,0x00005c557e0b9693}}, + {{0x0001ce311fc97e6f,0x0006023f3fb5db1f,0x0007b49775e8fc98,0x0003ad70adbf5045,0x0006e154c178fe98},{0x0006bbb089c20eb0,0x0006df41fb0b9eee,0x00051087ed87e16f,0x000102db5c9fa731,0x000289fef0841861},{0x00016336fed69abf,0x0004f066b929f9ec,0x0004e9ff9e6c5b93,0x00018c89bc4bb2ba,0x0006afbf642a95ca}}, + {{0x0000de0c62f5d2c1,0x00049601cf734fb5,0x0006b5c38263f0f6,0x0004623ef5b56d06,0x0000db4b851b9503},{0x00055070f913a8cc,0x000765619eac2bbc,0x0003ab5225f47459,0x00076ced14ab5b48,0x00012c093cedb801},{0x00047f9308b8190f,0x000414235c621f82,0x00031f5ff41a5a76,0x0006736773aab96d,0x00033aa8799c6635}}, + {{0x0007f51ebd085cf2,0x00012cfa67e3f5e1,0x0001800cf1e3d46a,0x00054337615ff0a8,0x000233c6f29e8e21},{0x0000f588fc156cb1,0x000363414da4f069,0x0007296ad9b68aea,0x0004d3711316ae43,0x000212cd0c1c8d58},{0x0004d5107f18c781,0x00064a4fd3a51a5e,0x0004f4cd0448bb37,0x000671d38543151e,0x0001db7778911914}}, + {{0x000352397c6bc26f,0x00018a7aa0227bbe,0x0005e68cc1ea5f8b,0x0006fe3e3a7a1d5f,0x00031ad97ad26e2a},{0x00014769dd701ab6,0x00028339f1b4b667,0x0004ab214b8ae37b,0x00025f0aefa0b0fe,0x0007ae2ca8a017d2},{0x000017ed0920b962,0x000187e33b53b6fd,0x00055829907a1463,0x000641f248e0a792,0x0001ed1fc53a6622}} +}; + +// ****************** modm-donna-64bit.h *********************** // + +const bignum256modm modm_m = { + 0x12631a5cf5d3ed, 0xf9dea2f79cd658, + 0x000000000014de, 0x00000000000000, + 0x00000010000000 +}; + +const bignum256modm modm_mu = { + 0x9ce5a30a2c131b, 0x215d086329a7ed, + 0xffffffffeb2106, 0xffffffffffffff, + 0x00000fffffffff +}; + +// *************** ed25519-donna-basepoint-table.h *************** // + +/* multiples of the base point in packed {ysubx, xaddy, t2d} form */ +ALIGN(16) const byte ge25519_niels_base_multiples[256][96] = { + {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f}, + {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49}, + {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54}, + {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44}, + {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68}, + {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78}, + {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23}, + {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58}, + {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10}, + {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56}, + {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14}, + {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37}, + {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02}, + {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12}, + {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f}, + {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41}, + {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e}, + {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14}, + {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41}, + {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59}, + {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49}, + {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20}, + {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b}, + {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74}, + {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69}, + {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b}, + {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e}, + {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39}, + {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33}, + {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61}, + {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45}, + {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d}, + {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c}, + {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21}, + {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a}, + {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39}, + {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22}, + {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50}, + {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d}, + {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45}, + {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d}, + {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c}, + {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27}, + {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f}, + {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f}, + {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22}, + {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c}, + {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19}, + {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71}, + {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c}, + {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a}, + {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02}, + {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31}, + {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48}, + {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c}, + {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f}, + {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60}, + {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63}, + {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70}, + {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41}, + {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24}, + {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16}, + {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78}, + {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13}, + {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a}, + {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b}, + {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d}, + {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74}, + {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58}, + {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12}, + {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d}, + {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b}, + {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c}, + {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04}, + {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76}, + {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11}, + {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f}, + {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55}, + {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57}, + {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21}, + {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a}, + {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19}, + {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60}, + {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36}, + {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07}, + {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57}, + {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05}, + {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f}, + {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72}, + {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00}, + {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c}, + {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06}, + {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15}, + {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07}, + {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51}, + {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77}, + {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e}, + {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09}, + {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56}, + {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43}, + {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27}, + {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b}, + {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46}, + {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69}, + {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14}, + {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55}, + {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13}, + {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d}, + {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31}, + {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05}, + {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f}, + {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a}, + {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10}, + {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25}, + {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08}, + {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a}, + {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f}, + {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38}, + {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65}, + {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c}, + {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e}, + {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35}, + {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47}, + {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47}, + {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74}, + {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a}, + {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56}, + {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d}, + {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44}, + {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58}, + {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70}, + {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e}, + {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41}, + {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11}, + {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f}, + {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10}, + {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72}, + {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00}, + {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05}, + {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00}, + {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b}, + {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05}, + {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f}, + {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f}, + {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40}, + {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b}, + {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02}, + {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c}, + {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f}, + {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29}, + {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71}, + {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a}, + {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06}, + {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30}, + {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b}, + {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24}, + {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49}, + {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53}, + {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02}, + {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e}, + {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d}, + {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f}, + {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07}, + {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f}, + {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b}, + {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f}, + {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12}, + {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30}, + {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45}, + {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a}, + {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13}, + {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f}, + {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a}, + {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12}, + {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b}, + {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10}, + {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b}, + {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e}, + {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f}, + {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00}, + {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33}, + {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63}, + {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b}, + {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16}, + {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57}, + {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e}, + {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73}, + {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76}, + {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e}, + {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16}, + {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45}, + {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67}, + {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a}, + {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a}, + {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e}, + {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62}, + {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e}, + {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e}, + {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78}, + {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46}, + {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a}, + {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26}, + {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b}, + {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d}, + {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45}, + {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26}, + {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62}, + {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d}, + {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61}, + {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79}, + {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39}, + {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63}, + {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34}, + {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56}, + {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e}, + {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26}, + {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f}, + {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f}, + {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b}, + {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39}, + {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51}, + {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f}, + {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f}, + {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13}, + {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c}, + {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60}, + {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15}, + {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32}, + {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b}, + {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02}, + {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c}, + {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05}, + {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67}, + {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c}, + {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37}, + {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63}, + {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68}, + {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c}, + {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c}, + {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26}, + {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08}, + {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19}, + {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41}, + {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b}, + {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08}, + {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48}, + {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54}, + {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c}, + {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f}, + {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25}, + {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55}, + {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a}, + {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59}, + {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70}, + {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27}, + {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f} +}; + +NAMESPACE_END // Arch64 +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_DOXYGEN_PROCESSING +#endif // CRYPTOPP_DONNA_64_H diff --git a/third_party/cryptoppwin/include/cryptopp/donna_sse.h b/third_party/cryptoppwin/include/cryptopp/donna_sse.h new file mode 100644 index 00000000..581bf607 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/donna_sse.h @@ -0,0 +1,86 @@ +// donna_sse.h - written and placed in public domain by Jeffrey Walton +// Crypto++ specific implementation wrapped around Andrew +// Moon's public domain curve25519-donna and ed25519-donna, +// https://github.com/floodyberry/curve25519-donna and +// https://github.com/floodyberry/ed25519-donna. + +// This source file multiplexes two different repos using namespaces. This +// was a little easier from a project management standpoint. We only need +// two files per architecture at the expense of namespaces and bloat. + +#ifndef CRYPTOPP_DONNA_SSE_H +#define CRYPTOPP_DONNA_SSE_H +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + +#include "config.h" +#include + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Donna) +NAMESPACE_BEGIN(ArchSSE) + +using CryptoPP::byte; +using CryptoPP::word32; + +typedef __m128i xmmi; +#define ALIGN(n) CRYPTOPP_ALIGN_DATA(n) + +typedef union packedelem8_t { + byte u[16]; + xmmi v; +} packedelem8; + +typedef union packedelem32_t { + word32 u[4]; + xmmi v; +} packedelem32; + +typedef union packedelem64_t { + word64 u[2]; + xmmi v; +} packedelem64; + +/* 10 elements + an extra 2 to fit in 3 xmm registers */ +typedef word32 bignum25519[12]; +typedef packedelem32 packed32bignum25519[5]; +typedef packedelem64 packed64bignum25519[10]; + +const word32 reduce_mask_26 = (1 << 26) - 1; +const word32 reduce_mask_25 = (1 << 25) - 1; + +const packedelem32 sse2_bot32bitmask = {{0xffffffff, 0x00000000, 0xffffffff, 0x00000000}}; +const packedelem32 sse2_top32bitmask = {{0x00000000, 0xffffffff, 0x00000000, 0xffffffff}}; +const packedelem32 sse2_top64bitmask = {{0x00000000, 0x00000000, 0xffffffff, 0xffffffff}}; +const packedelem32 sse2_bot64bitmask = {{0xffffffff, 0xffffffff, 0x00000000, 0x00000000}}; + +/* reduction masks */ +const packedelem64 packedmask26 = {{0x03ffffff, 0x03ffffff}}; +const packedelem64 packedmask25 = {{0x01ffffff, 0x01ffffff}}; +const packedelem32 packedmask2625 = {{0x3ffffff,0,0x1ffffff,0}}; +const packedelem32 packedmask26262626 = {{0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff}}; +const packedelem32 packedmask25252525 = {{0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}}; + +/* multipliers */ +const packedelem64 packednineteen = {{19, 19}}; +const packedelem64 packednineteenone = {{19, 1}}; +const packedelem64 packedthirtyeight = {{38, 38}}; +const packedelem64 packed3819 = {{19*2,19}}; +const packedelem64 packed9638 = {{19*4,19*2}}; + +/* 121666,121665 */ +const packedelem64 packed121666121665 = {{121666, 121665}}; + +/* 2*(2^255 - 19) = 0 mod p */ +const packedelem32 packed2p0 = {{0x7ffffda,0x3fffffe,0x7fffffe,0x3fffffe}}; +const packedelem32 packed2p1 = {{0x7fffffe,0x3fffffe,0x7fffffe,0x3fffffe}}; +const packedelem32 packed2p2 = {{0x7fffffe,0x3fffffe,0x0000000,0x0000000}}; + +const packedelem32 packed32zeromodp0 = {{0x7ffffda,0x7ffffda,0x3fffffe,0x3fffffe}}; +const packedelem32 packed32zeromodp1 = {{0x7fffffe,0x7fffffe,0x3fffffe,0x3fffffe}}; + +NAMESPACE_END // ArchSSE +NAMESPACE_END // Donna +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_DOXYGEN_PROCESSING +#endif // CRYPTOPP_DONNA_SSE_H diff --git a/third_party/cryptoppwin/include/cryptopp/drbg.h b/third_party/cryptoppwin/include/cryptopp/drbg.h new file mode 100644 index 00000000..81920774 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/drbg.h @@ -0,0 +1,718 @@ +// drbg.h - written and placed in public domain by Jeffrey Walton. + +/// \file drbg.h +/// \brief Classes for NIST DRBGs from SP 800-90A +/// \sa Recommendation +/// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_NIST_DRBG_H +#define CRYPTOPP_NIST_DRBG_H + +#include "cryptlib.h" +#include "secblock.h" +#include "hmac.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Interface for NIST DRBGs from SP 800-90A +/// \details NIST_DRBG is the base class interface for NIST DRBGs from SP 800-90A Rev 1 (June 2015) +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa Recommendation +/// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) +/// \since Crypto++ 6.0 +class NIST_DRBG : public RandomNumberGenerator +{ +public: + /// \brief Exception thrown when a NIST DRBG encounters an error + class Err : public Exception + { + public: + explicit Err(const std::string &c, const std::string &m) + : Exception(OTHER_ERROR, c + ": " + m) {} + }; + +public: + virtual ~NIST_DRBG() {} + + /// \brief Determines if a generator can accept additional entropy + /// \return true + /// \details All NIST_DRBG return true + virtual bool CanIncorporateEntropy() const {return true;} + + /// \brief Update RNG state with additional unpredictable values + /// \param input the entropy to add to the generator + /// \param length the size of the input buffer + /// \throw NIST_DRBG::Err if the generator is reseeded with insufficient entropy + /// \details NIST instantiation and reseed requirements demand the generator is constructed + /// with at least MINIMUM_ENTROPY entropy. The byte array for input must + /// meet NIST SP 800-90B or + /// SP 800-90C requirements. + virtual void IncorporateEntropy(const byte *input, size_t length)=0; + + /// \brief Update RNG state with additional unpredictable values + /// \param entropy the entropy to add to the generator + /// \param entropyLength the size of the input buffer + /// \param additional additional input to add to the generator + /// \param additionaLength the size of the additional input buffer + /// \throw NIST_DRBG::Err if the generator is reseeded with insufficient entropy + /// \details IncorporateEntropy() is an overload provided to match NIST requirements. NIST + /// instantiation and reseed requirements demand the generator is constructed with at least + /// MINIMUM_ENTROPY entropy. The byte array for entropy must meet + /// NIST SP 800-90B or + ///! SP 800-90C requirements. + virtual void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0; + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \throw NIST_DRBG::Err if a reseed is required + /// \throw NIST_DRBG::Err if the size exceeds MAXIMUM_BYTES_PER_REQUEST + virtual void GenerateBlock(byte *output, size_t size)=0; + + /// \brief Generate random array of bytes + /// \param additional additional input to add to the generator + /// \param additionaLength the size of the additional input buffer + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \throw NIST_DRBG::Err if a reseed is required + /// \throw NIST_DRBG::Err if the size exceeds MAXIMUM_BYTES_PER_REQUEST + /// \details GenerateBlock() is an overload provided to match NIST requirements. The byte + /// array for additional input is optional. If present the additional randomness + /// is mixed before generating the output bytes. + virtual void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size)=0; + + /// \brief Provides the security strength + /// \return The security strength of the generator, in bytes + /// \details The equivalent class constant is SECURITY_STRENGTH + virtual unsigned int SecurityStrength() const=0; + + /// \brief Provides the seed length + /// \return The seed size of the generator, in bytes + /// \details The equivalent class constant is SEED_LENGTH. The size is + /// used to maintain internal state of V and C. + virtual unsigned int SeedLength() const=0; + + /// \brief Provides the minimum entropy size + /// \return The minimum entropy size required by the generator, in bytes + /// \details The equivalent class constant is MINIMUM_ENTROPY. All NIST DRBGs must + /// be instaniated with at least MINIMUM_ENTROPY bytes of entropy. The bytes must + /// meet NIST SP 800-90B or + /// SP 800-90C requirements. + virtual unsigned int MinEntropyLength() const=0; + + /// \brief Provides the maximum entropy size + /// \return The maximum entropy size that can be consumed by the generator, in bytes + /// \details The equivalent class constant is MAXIMUM_ENTROPY. The bytes must + /// meet NIST SP 800-90B or + /// SP 800-90C requirements. MAXIMUM_ENTROPY has been reduced from + /// 235 to INT_MAX to fit the underlying C++ datatype. + virtual unsigned int MaxEntropyLength() const=0; + + /// \brief Provides the minimum nonce size + /// \return The minimum nonce size recommended for the generator, in bytes + /// \details The equivalent class constant is MINIMUM_NONCE. If a nonce is not + /// required then MINIMUM_NONCE is 0. Hash_DRBG does not require a + /// nonce, while HMAC_DRBG and CTR_DRBG require a nonce. + virtual unsigned int MinNonceLength() const=0; + + /// \brief Provides the maximum nonce size + /// \return The maximum nonce that can be consumed by the generator, in bytes + /// \details The equivalent class constant is MAXIMUM_NONCE. MAXIMUM_NONCE + /// has been reduced from 235 to INT_MAX to fit the underlying C++ datatype. + /// If a nonce is not required then MINIMUM_NONCE is 0. Hash_DRBG does not + /// require a nonce, while HMAC_DRBG and CTR_DRBG require a nonce. + virtual unsigned int MaxNonceLength() const=0; + + /// \brief Provides the maximum size of a request to GenerateBlock + /// \return The maximum size of a request to GenerateBlock(), in bytes + /// \details The equivalent class constant is MAXIMUM_BYTES_PER_REQUEST + virtual unsigned int MaxBytesPerRequest() const=0; + + /// \brief Provides the maximum number of requests before a reseed + /// \return The maximum number of requests before a reseed, in bytes + /// \details The equivalent class constant is MAXIMUM_REQUESTS_BEFORE_RESEED. + /// MAXIMUM_REQUESTS_BEFORE_RESEED has been reduced from 248 to INT_MAX + /// to fit the underlying C++ datatype. + virtual unsigned int MaxRequestBeforeReseed() const=0; + +protected: + virtual void DRBG_Instantiate(const byte* entropy, size_t entropyLength, + const byte* nonce, size_t nonceLength, const byte* personalization, size_t personalizationLength)=0; + + virtual void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength)=0; +}; + +// ************************************************************* + +/// \tparam HASH NIST approved hash derived from HashTransformation +/// \tparam STRENGTH security strength, in bytes +/// \tparam SEEDLENGTH seed length, in bytes +/// \brief Hash_DRBG from SP 800-90A Rev 1 (June 2015) +/// \details The NIST Hash DRBG is instantiated with a number of parameters. Two of the parameters, +/// Security Strength and Seed Length, depend on the hash and are specified as template parameters. +/// The remaining parameters are included in the class. The parameters and their values are listed +/// in NIST SP 800-90A Rev. 1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p.38). +/// \details Some parameters have been reduce to fit C++ datatypes. For example, NIST allows upto +/// 248 requests before a reseed. However, Hash_DRBG limits it to INT_MAX due +/// to the limited data range of an int. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa Recommendation +/// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) +/// \since Crypto++ 6.0 +template +class Hash_DRBG : public NIST_DRBG, public NotCopyable +{ +public: + CRYPTOPP_CONSTANT(SECURITY_STRENGTH=STRENGTH); + CRYPTOPP_CONSTANT(SEED_LENGTH=SEEDLENGTH); + CRYPTOPP_CONSTANT(MINIMUM_ENTROPY=STRENGTH); + CRYPTOPP_CONSTANT(MINIMUM_NONCE=0); + CRYPTOPP_CONSTANT(MINIMUM_ADDITIONAL=0); + CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0); + CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_NONCE=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_ADDITIONAL=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_PERSONALIZATION=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_BYTES_PER_REQUEST=65536); + CRYPTOPP_CONSTANT(MAXIMUM_REQUESTS_BEFORE_RESEED=INT_MAX); + + static std::string StaticAlgorithmName() { return std::string("Hash_DRBG(") + HASH::StaticAlgorithmName() + std::string(")"); } + + /// \brief Construct a Hash DRBG + /// \param entropy the entropy to instantiate the generator + /// \param entropyLength the size of the entropy buffer + /// \param nonce additional input to instantiate the generator + /// \param nonceLength the size of the nonce buffer + /// \param personalization additional input to instantiate the generator + /// \param personalizationLength the size of the personalization buffer + /// \throw NIST_DRBG::Err if the generator is instantiated with insufficient entropy + /// \details All NIST DRBGs must be instaniated with at least MINIMUM_ENTROPY bytes of entropy. + /// The byte array for entropy must meet NIST + /// SP 800-90B or SP 800-90C requirements. + /// \details The nonce and personalization are optional byte arrays. If nonce is supplied, + /// then it should be at least MINIMUM_NONCE bytes of entropy. + /// \details An example of instantiating a SHA256 generator is shown below. + /// The example provides more entropy than required for SHA256. The NonblockingRng meets the + /// requirements of NIST SP 800-90B or SP 800-90C. + /// RDRAND() and RDSEED() generators would work as well. + ///
+    ///   SecByteBlock entropy(48), result(128);
+    ///   NonblockingRng prng;
+    ///   RandomNumberSource rns(prng, entropy.size(), new ArraySink(entropy, entropy.size()));
+    ///
+    ///   Hash_DRBG drbg(entropy, 32, entropy+32, 16);
+    ///   drbg.GenerateBlock(result, result.size());
+    /// 
+ Hash_DRBG(const byte* entropy=NULLPTR, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR, + size_t nonceLength=0, const byte* personalization=NULLPTR, size_t personalizationLength=0) + : NIST_DRBG(), m_c(SEEDLENGTH), m_v(SEEDLENGTH), m_reseed(0) + { + if (m_c.data()) // GCC analyzer warning + std::memset(m_c.data(), 0x00, m_c.size()); + if (m_v.data()) // GCC analyzer warning + std::memset(m_v.data(), 0x00, m_v.size()); + + if (entropy != NULLPTR && entropyLength != 0) + DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength); + } + + unsigned int SecurityStrength() const {return SECURITY_STRENGTH;} + unsigned int SeedLength() const {return SEED_LENGTH;} + unsigned int MinEntropyLength() const {return MINIMUM_ENTROPY;} + unsigned int MaxEntropyLength() const {return MAXIMUM_ENTROPY;} + unsigned int MinNonceLength() const {return MINIMUM_NONCE;} + unsigned int MaxNonceLength() const {return MAXIMUM_NONCE;} + unsigned int MaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;} + unsigned int MaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;} + + void IncorporateEntropy(const byte *input, size_t length) + {return DRBG_Reseed(input, length, NULLPTR, 0);} + + void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength) + {return DRBG_Reseed(entropy, entropyLength, additional, additionaLength);} + + void GenerateBlock(byte *output, size_t size) + {return Hash_Generate(NULLPTR, 0, output, size);} + + void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size) + {return Hash_Generate(additional, additionaLength, output, size);} + + std::string AlgorithmProvider() const + {/*Hack*/HASH hash; return hash.AlgorithmProvider();} + +protected: + // 10.1.1.2 Instantiation of Hash_DRBG (p.39) + void DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, + const byte* personalization, size_t personalizationLength); + + // 10.1.1.3 Reseeding a Hash_DRBG Instantiation (p.40) + void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength); + + // 10.1.1.4 Generating Pseudorandom Bits Using Hash_DRBG (p.41) + void Hash_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size); + + // 10.3.1 Derivation Function Using a Hash Function (Hash_df) (p.49) + void Hash_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, + const byte* input3, size_t inlen3, const byte* input4, size_t inlen4, byte* output, size_t outlen); + +private: + HASH m_hash; + SecByteBlock m_c, m_v, m_temp; + word64 m_reseed; +}; + +// typedef Hash_DRBG Hash_SHA1_DRBG; +// typedef Hash_DRBG Hash_SHA256_DRBG; +// typedef Hash_DRBG Hash_SHA384_DRBG; +// typedef Hash_DRBG Hash_SHA512_DRBG; + +// ************************************************************* + +/// \tparam HASH NIST approved hash derived from HashTransformation +/// \tparam STRENGTH security strength, in bytes +/// \tparam SEEDLENGTH seed length, in bytes +/// \brief HMAC_DRBG from SP 800-90A Rev 1 (June 2015) +/// \details The NIST HMAC DRBG is instantiated with a number of parameters. Two of the parameters, +/// Security Strength and Seed Length, depend on the hash and are specified as template parameters. +/// The remaining parameters are included in the class. The parameters and their values are listed +/// in NIST SP 800-90A Rev. 1, Table 2: Definitions for Hash-Based DRBG Mechanisms (p.38). +/// \details Some parameters have been reduce to fit C++ datatypes. For example, NIST allows upto 248 requests +/// before a reseed. However, HMAC_DRBG limits it to INT_MAX due to the limited data range of an int. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa Recommendation +/// for Random Number Generation Using Deterministic Random Bit Generators, Rev 1 (June 2015) +/// \since Crypto++ 6.0 +template +class HMAC_DRBG : public NIST_DRBG, public NotCopyable +{ +public: + CRYPTOPP_CONSTANT(SECURITY_STRENGTH=STRENGTH); + CRYPTOPP_CONSTANT(SEED_LENGTH=SEEDLENGTH); + CRYPTOPP_CONSTANT(MINIMUM_ENTROPY=STRENGTH); + CRYPTOPP_CONSTANT(MINIMUM_NONCE=0); + CRYPTOPP_CONSTANT(MINIMUM_ADDITIONAL=0); + CRYPTOPP_CONSTANT(MINIMUM_PERSONALIZATION=0); + CRYPTOPP_CONSTANT(MAXIMUM_ENTROPY=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_NONCE=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_ADDITIONAL=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_PERSONALIZATION=INT_MAX); + CRYPTOPP_CONSTANT(MAXIMUM_BYTES_PER_REQUEST=65536); + CRYPTOPP_CONSTANT(MAXIMUM_REQUESTS_BEFORE_RESEED=INT_MAX); + + static std::string StaticAlgorithmName() { return std::string("HMAC_DRBG(") + HASH::StaticAlgorithmName() + std::string(")"); } + + /// \brief Construct a HMAC DRBG + /// \param entropy the entropy to instantiate the generator + /// \param entropyLength the size of the entropy buffer + /// \param nonce additional input to instantiate the generator + /// \param nonceLength the size of the nonce buffer + /// \param personalization additional input to instantiate the generator + /// \param personalizationLength the size of the personalization buffer + /// \throw NIST_DRBG::Err if the generator is instantiated with insufficient entropy + /// \details All NIST DRBGs must be instaniated with at least MINIMUM_ENTROPY bytes of entropy. + /// The byte array for entropy must meet NIST + /// SP 800-90B or SP 800-90C requirements. + /// \details The nonce and personalization are optional byte arrays. If nonce is supplied, + /// then it should be at least MINIMUM_NONCE bytes of entropy. + /// \details An example of instantiating a SHA256 generator is shown below. + /// The example provides more entropy than required for SHA256. The NonblockingRng meets the + /// requirements of NIST SP 800-90B or SP 800-90C. + /// RDRAND() and RDSEED() generators would work as well. + ///
+    ///   SecByteBlock entropy(48), result(128);
+    ///   NonblockingRng prng;
+    ///   RandomNumberSource rns(prng, entropy.size(), new ArraySink(entropy, entropy.size()));
+    ///
+    ///   HMAC_DRBG drbg(entropy, 32, entropy+32, 16);
+    ///   drbg.GenerateBlock(result, result.size());
+    /// 
+ HMAC_DRBG(const byte* entropy=NULLPTR, size_t entropyLength=STRENGTH, const byte* nonce=NULLPTR, + size_t nonceLength=0, const byte* personalization=NULLPTR, size_t personalizationLength=0) + : NIST_DRBG(), m_k(HASH::DIGESTSIZE), m_v(HASH::DIGESTSIZE), m_reseed(0) + { + if (m_k.data()) // GCC analyzer warning + std::memset(m_k, 0x00, m_k.size()); + if (m_v.data()) // GCC analyzer warning + std::memset(m_v, 0x00, m_v.size()); + + if (entropy != NULLPTR && entropyLength != 0) + DRBG_Instantiate(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength); + } + + unsigned int SecurityStrength() const {return SECURITY_STRENGTH;} + unsigned int SeedLength() const {return SEED_LENGTH;} + unsigned int MinEntropyLength() const {return MINIMUM_ENTROPY;} + unsigned int MaxEntropyLength() const {return MAXIMUM_ENTROPY;} + unsigned int MinNonceLength() const {return MINIMUM_NONCE;} + unsigned int MaxNonceLength() const {return MAXIMUM_NONCE;} + unsigned int MaxBytesPerRequest() const {return MAXIMUM_BYTES_PER_REQUEST;} + unsigned int MaxRequestBeforeReseed() const {return MAXIMUM_REQUESTS_BEFORE_RESEED;} + + void IncorporateEntropy(const byte *input, size_t length) + {return DRBG_Reseed(input, length, NULLPTR, 0);} + + void IncorporateEntropy(const byte *entropy, size_t entropyLength, const byte* additional, size_t additionaLength) + {return DRBG_Reseed(entropy, entropyLength, additional, additionaLength);} + + void GenerateBlock(byte *output, size_t size) + {return HMAC_Generate(NULLPTR, 0, output, size);} + + void GenerateBlock(const byte* additional, size_t additionaLength, byte *output, size_t size) + {return HMAC_Generate(additional, additionaLength, output, size);} + + std::string AlgorithmProvider() const + {/*Hack*/HASH hash; return hash.AlgorithmProvider();} + +protected: + // 10.1.2.3 Instantiation of HMAC_DRBG (p.45) + void DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, + const byte* personalization, size_t personalizationLength); + + // 10.1.2.4 Reseeding a HMAC_DRBG Instantiation (p.46) + void DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength); + + // 10.1.2.5 Generating Pseudorandom Bits Using HMAC_DRBG (p.46) + void HMAC_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size); + + // 10.1.2.2 Derivation Function Using a HMAC Function (HMAC_Update) (p.44) + void HMAC_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, const byte* input3, size_t inlen3); + +private: + HMAC m_hmac; + SecByteBlock m_k, m_v; + word64 m_reseed; +}; + +// typedef HMAC_DRBG HMAC_SHA1_DRBG; +// typedef HMAC_DRBG HMAC_SHA256_DRBG; +// typedef HMAC_DRBG HMAC_SHA384_DRBG; +// typedef HMAC_DRBG HMAC_SHA512_DRBG; + +// ************************************************************* + +// 10.1.1.2 Instantiation of Hash_DRBG (p.39) +template +void Hash_DRBG::DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, + const byte* personalization, size_t personalizationLength) +{ + // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security + // strength of the instantiation. Additional entropy may be provided in the nonce or the optional + // personalization string during instantiation, or in the additional input during reseeding and generation, + // but this is not required and does not increase the "official" security strength of the DRBG + // instantiation that is recorded in the internal state. + CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY); + if (entropyLength < MINIMUM_ENTROPY) + throw NIST_DRBG::Err("Hash_DRBG", "Insufficient entropy during instantiate"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY); + CRYPTOPP_ASSERT(nonceLength <= MAXIMUM_NONCE); + CRYPTOPP_ASSERT(personalizationLength <= MAXIMUM_PERSONALIZATION); + + const byte zero = 0; + SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH); + Hash_Update(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength, NULLPTR, 0, t1, t1.size()); + Hash_Update(&zero, 1, t1, t1.size(), NULLPTR, 0, NULLPTR, 0, t2, t2.size()); + + m_v.swap(t1); m_c.swap(t2); + m_reseed = 1; +} + +// 10.1.1.3 Reseeding a Hash_DRBG Instantiation (p.40) +template +void Hash_DRBG::DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength) +{ + // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security + // strength of the instantiation. Additional entropy may be provided in the nonce or the optional + // personalization string during instantiation, or in the additional input during reseeding and generation, + // but this is not required and does not increase the "official" security strength of the DRBG + // instantiation that is recorded in the internal state.. + CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY); + if (entropyLength < MINIMUM_ENTROPY) + throw NIST_DRBG::Err("Hash_DRBG", "Insufficient entropy during reseed"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY); + CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL); + + const byte zero = 0, one = 1; + SecByteBlock t1(SEEDLENGTH), t2(SEEDLENGTH); + Hash_Update(&one, 1, m_v, m_v.size(), entropy, entropyLength, additional, additionaLength, t1, t1.size()); + Hash_Update(&zero, 1, t1, t1.size(), NULLPTR, 0, NULLPTR, 0, t2, t2.size()); + + m_v.swap(t1); m_c.swap(t2); + m_reseed = 1; +} + +// 10.1.1.4 Generating Pseudorandom Bits Using Hash_DRBG (p.41) +template +void Hash_DRBG::Hash_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size) +{ + // Step 1 + if (static_cast(m_reseed) >= static_cast(MaxRequestBeforeReseed())) + throw NIST_DRBG::Err("Hash_DRBG", "Reseed required"); + + if (size > MaxBytesPerRequest()) + throw NIST_DRBG::Err("Hash_DRBG", "Request size exceeds limit"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL); + + // Step 2 + if (additional && additionaLength) + { + const byte two = 2; + m_temp.New(HASH::DIGESTSIZE); + + m_hash.Update(&two, 1); + m_hash.Update(m_v, m_v.size()); + m_hash.Update(additional, additionaLength); + m_hash.Final(m_temp); + + CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE); + int carry=0, j=HASH::DIGESTSIZE-1, i=SEEDLENGTH-1; + while (j>=0) + { + carry = m_v[i] + m_temp[j] + carry; + m_v[i] = static_cast(carry); + i--; j--; carry >>= 8; + } + while (i>=0) + { + carry = m_v[i] + carry; + m_v[i] = static_cast(carry); + i--; carry >>= 8; + } + } + + // Step 3 + { + m_temp.Assign(m_v); + while (size) + { + m_hash.Update(m_temp, m_temp.size()); + size_t count = STDMIN(size, (size_t)HASH::DIGESTSIZE); + m_hash.TruncatedFinal(output, count); + + IncrementCounterByOne(m_temp, static_cast(m_temp.size())); + size -= count; output += count; + } + } + + // Steps 4-7 + { + const byte three = 3; + m_temp.New(HASH::DIGESTSIZE); + + m_hash.Update(&three, 1); + m_hash.Update(m_v, m_v.size()); + m_hash.Final(m_temp); + + CRYPTOPP_ASSERT(SEEDLENGTH >= HASH::DIGESTSIZE); + CRYPTOPP_ASSERT(HASH::DIGESTSIZE >= sizeof(m_reseed)); + int carry=0, k=sizeof(m_reseed)-1, j=HASH::DIGESTSIZE-1, i=SEEDLENGTH-1; + + while (k>=0) + { + carry = m_v[i] + m_c[i] + m_temp[j] + GetByte(BIG_ENDIAN_ORDER, m_reseed, k) + carry; + m_v[i] = static_cast(carry); + i--; j--; k--; carry >>= 8; + } + + while (j>=0) + { + carry = m_v[i] + m_c[i] + m_temp[j] + carry; + m_v[i] = static_cast(carry); + i--; j--; carry >>= 8; + } + + while (i>=0) + { + carry = m_v[i] + m_c[i] + carry; + m_v[i] = static_cast(carry); + i--; carry >>= 8; + } + } + + m_reseed++; +} + +// 10.3.1 Derivation Function Using a Hash Function (Hash_df) (p.49) +template +void Hash_DRBG::Hash_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, + const byte* input3, size_t inlen3, const byte* input4, size_t inlen4, byte* output, size_t outlen) +{ + byte counter = 1; + word32 bits = ConditionalByteReverse(BIG_ENDIAN_ORDER, static_cast(outlen*8)); + + while (outlen) + { + m_hash.Update(&counter, 1); + m_hash.Update(reinterpret_cast(&bits), 4); + + if (input1 && inlen1) + m_hash.Update(input1, inlen1); + if (input2 && inlen2) + m_hash.Update(input2, inlen2); + if (input3 && inlen3) + m_hash.Update(input3, inlen3); + if (input4 && inlen4) + m_hash.Update(input4, inlen4); + + size_t count = STDMIN(outlen, (size_t)HASH::DIGESTSIZE); + m_hash.TruncatedFinal(output, count); + + output += count; outlen -= count; + counter++; + } +} + +// ************************************************************* + +// 10.1.2.3 Instantiation of HMAC_DRBG (p.45) +template +void HMAC_DRBG::DRBG_Instantiate(const byte* entropy, size_t entropyLength, const byte* nonce, size_t nonceLength, + const byte* personalization, size_t personalizationLength) +{ + // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security + // strength of the instantiation. Additional entropy may be provided in the nonce or the optional + // personalization string during instantiation, or in the additional input during reseeding and generation, + // but this is not required and does not increase the "official" security strength of the DRBG + // instantiation that is recorded in the internal state. + CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY); + if (entropyLength < MINIMUM_ENTROPY) + throw NIST_DRBG::Err("HMAC_DRBG", "Insufficient entropy during instantiate"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY); + CRYPTOPP_ASSERT(nonceLength <= MAXIMUM_NONCE); + CRYPTOPP_ASSERT(personalizationLength <= MAXIMUM_PERSONALIZATION); + + std::fill(m_k.begin(), m_k.begin()+m_k.size(), byte(0)); + std::fill(m_v.begin(), m_v.begin()+m_v.size(), byte(1)); + + HMAC_Update(entropy, entropyLength, nonce, nonceLength, personalization, personalizationLength); + m_reseed = 1; +} + +// 10.1.2.4 Reseeding a HMAC_DRBG Instantiation (p.46) +template +void HMAC_DRBG::DRBG_Reseed(const byte* entropy, size_t entropyLength, const byte* additional, size_t additionaLength) +{ + // SP 800-90A, 8.6.3: The entropy input shall have entropy that is equal to or greater than the security + // strength of the instantiation. Additional entropy may be provided in the nonce or the optional + // personalization string during instantiation, or in the additional input during reseeding and generation, + // but this is not required and does not increase the "official" security strength of the DRBG + // instantiation that is recorded in the internal state.. + CRYPTOPP_ASSERT(entropyLength >= MINIMUM_ENTROPY); + if (entropyLength < MINIMUM_ENTROPY) + throw NIST_DRBG::Err("HMAC_DRBG", "Insufficient entropy during reseed"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(entropyLength <= MAXIMUM_ENTROPY); + CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL); + + HMAC_Update(entropy, entropyLength, additional, additionaLength, NULLPTR, 0); + m_reseed = 1; +} + +// 10.1.2.5 Generating Pseudorandom Bits Using HMAC_DRBG (p.46) +template +void HMAC_DRBG::HMAC_Generate(const byte* additional, size_t additionaLength, byte *output, size_t size) +{ + // Step 1 + if (static_cast(m_reseed) >= static_cast(MaxRequestBeforeReseed())) + throw NIST_DRBG::Err("HMAC_DRBG", "Reseed required"); + + if (size > MaxBytesPerRequest()) + throw NIST_DRBG::Err("HMAC_DRBG", "Request size exceeds limit"); + + // SP 800-90A, Section 9, says we should throw if we have too much entropy, too large a nonce, + // or too large a persoanlization string. We warn in Debug builds, but do nothing in Release builds. + CRYPTOPP_ASSERT(additionaLength <= MAXIMUM_ADDITIONAL); + + // Step 2 + if (additional && additionaLength) + HMAC_Update(additional, additionaLength, NULLPTR, 0, NULLPTR, 0); + + // Step 3 + m_hmac.SetKey(m_k, m_k.size()); + + while (size) + { + m_hmac.Update(m_v, m_v.size()); + m_hmac.TruncatedFinal(m_v, m_v.size()); + + size_t count = STDMIN(size, (size_t)HASH::DIGESTSIZE); + std::memcpy(output, m_v, count); + size -= count; output += count; + } + + HMAC_Update(additional, additionaLength, NULLPTR, 0, NULLPTR, 0); + m_reseed++; +} + +// 10.1.2.2 Derivation Function Using a HMAC Function (HMAC_Update) (p.44) +template +void HMAC_DRBG::HMAC_Update(const byte* input1, size_t inlen1, const byte* input2, size_t inlen2, const byte* input3, size_t inlen3) +{ + const byte zero = 0, one = 1; + + // Step 1 + m_hmac.SetKey(m_k, m_k.size()); + m_hmac.Update(m_v, m_v.size()); + m_hmac.Update(&zero, 1); + + if (input1 && inlen1) + m_hmac.Update(input1, inlen1); + if (input2 && inlen2) + m_hmac.Update(input2, inlen2); + if (input3 && inlen3) + m_hmac.Update(input3, inlen3); + + m_hmac.TruncatedFinal(m_k, m_k.size()); + + // Step 2 + m_hmac.SetKey(m_k, m_k.size()); + m_hmac.Update(m_v, m_v.size()); + + m_hmac.TruncatedFinal(m_v, m_v.size()); + + // Step 3 + if ((inlen1 | inlen2 | inlen3) == 0) + return; + + // Step 4 + m_hmac.SetKey(m_k, m_k.size()); + m_hmac.Update(m_v, m_v.size()); + m_hmac.Update(&one, 1); + + if (input1 && inlen1) + m_hmac.Update(input1, inlen1); + if (input2 && inlen2) + m_hmac.Update(input2, inlen2); + if (input3 && inlen3) + m_hmac.Update(input3, inlen3); + + m_hmac.TruncatedFinal(m_k, m_k.size()); + + // Step 5 + m_hmac.SetKey(m_k, m_k.size()); + m_hmac.Update(m_v, m_v.size()); + + m_hmac.TruncatedFinal(m_v, m_v.size()); +} + +NAMESPACE_END + +#endif // CRYPTOPP_NIST_DRBG_H diff --git a/third_party/cryptoppwin/include/cryptopp/dsa.h b/third_party/cryptoppwin/include/cryptopp/dsa.h new file mode 100644 index 00000000..f49ed92b --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/dsa.h @@ -0,0 +1,53 @@ +// dsa.h - originally written and placed in the public domain by Wei Dai + +/// \file dsa.h +/// \brief Classes for the DSA signature algorithm + +#ifndef CRYPTOPP_DSA_H +#define CRYPTOPP_DSA_H + +#include "cryptlib.h" +#include "gfpcrypt.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief DSA Signature Format +/// \details The DSA signature format used by Crypto++ is as defined by IEEE P1363. +/// OpenSSL, Java and .Net use the DER format, and OpenPGP uses the OpenPGP format. +/// \sa DSAConvertSignatureFormat +/// on the Crypto++ wiki. +/// \since Crypto++ 1.0 +enum DSASignatureFormat { + /// \brief Crypto++ native signature encoding format + DSA_P1363, + /// \brief signature encoding format used by OpenSSL, Java and .Net + DSA_DER, + /// \brief OpenPGP signature encoding format + DSA_OPENPGP +}; + +/// \brief Converts between signature encoding formats +/// \param buffer byte buffer for the converted signature encoding +/// \param bufferSize the length of the converted signature encoding buffer +/// \param toFormat the source signature format +/// \param signature byte buffer for the existing signature encoding +/// \param signatureLen the length of the existing signature encoding buffer +/// \param fromFormat the source signature format +/// \return the number of bytes written during encoding +/// \details This function converts between these formats, and returns length +/// of signature in the target format. If toFormat == DSA_P1363, then +/// bufferSize must equal publicKey.SignatureLength() or +/// verifier.SignatureLength(). +/// \details If the destination buffer is too small then the output of the +/// encoded r and s will be truncated. Be sure to provide +/// an adequately sized buffer and check the return value for the number of +/// bytes written. +/// \sa DSAConvertSignatureFormat +/// on the Crypto++ wiki. +/// \since Crypto++ 1.0 +size_t DSAConvertSignatureFormat(byte *buffer, size_t bufferSize, DSASignatureFormat toFormat, + const byte *signature, size_t signatureLen, DSASignatureFormat fromFormat); + +NAMESPACE_END + +#endif // CRYPTOPP_DSA_H diff --git a/third_party/cryptoppwin/include/cryptopp/eax.h b/third_party/cryptoppwin/include/cryptopp/eax.h new file mode 100644 index 00000000..6dc1fa6d --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/eax.h @@ -0,0 +1,112 @@ +// eax.h - originally written and placed in the public domain by Wei Dai + +/// \file eax.h +/// \brief EAX block cipher mode of operation + +#ifndef CRYPTOPP_EAX_H +#define CRYPTOPP_EAX_H + +#include "authenc.h" +#include "modes.h" +#include "cmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief EAX block cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 5.6.0 +class CRYPTOPP_NO_VTABLE EAX_Base : public AuthenticatedSymmetricCipherBase +{ +public: + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return GetMAC().GetCipher().AlgorithmName() + std::string("/EAX");} + std::string AlgorithmProvider() const + {return GetMAC().GetCipher().AlgorithmProvider();} + size_t MinKeyLength() const + {return GetMAC().MinKeyLength();} + size_t MaxKeyLength() const + {return GetMAC().MaxKeyLength();} + size_t DefaultKeyLength() const + {return GetMAC().DefaultKeyLength();} + size_t GetValidKeyLength(size_t n) const + {return GetMAC().GetValidKeyLength(n);} + bool IsValidKeyLength(size_t n) const + {return GetMAC().IsValidKeyLength(n);} + unsigned int OptimalDataAlignment() const + {return GetMAC().OptimalDataAlignment();} + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return GetMAC().TagSize();} + unsigned int MinIVLength() const + {return 0;} + unsigned int MaxIVLength() const + {return UINT_MAX;} + unsigned int DigestSize() const + {return GetMAC().TagSize();} + lword MaxHeaderLength() const + {return LWORD_MAX;} + lword MaxMessageLength() const + {return LWORD_MAX;} + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const + {return false;} + unsigned int AuthenticationBlockSize() const + {return 1;} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + SymmetricCipher & AccessSymmetricCipher() {return m_ctr;} + const CMAC_Base & GetMAC() const {return const_cast(this)->AccessMAC();} + virtual CMAC_Base & AccessMAC() =0; + + CTR_Mode_ExternalCipher::Encryption m_ctr; +}; + +/// \brief EAX block cipher final implementation +/// \tparam T_BlockCipher block cipher +/// \tparam T_IsEncryption direction in which to operate the cipher +/// \since Crypto++ 5.6.0 +template +class EAX_Final : public EAX_Base +{ +public: + static std::string StaticAlgorithmName() + {return T_BlockCipher::StaticAlgorithmName() + std::string("/EAX");} + std::string AlgorithmProvider() const + {return m_cmac.AlgorithmProvider();} + bool IsForwardTransformation() const + {return T_IsEncryption;} + +private: + CMAC_Base & AccessMAC() {return m_cmac;} + CMAC m_cmac; +}; + +#ifdef EAX // EAX is defined to 11 on GCC 3.4.3, OpenSolaris 8.11 +#undef EAX +#endif + +/// \brief EAX block cipher mode of operation +/// \tparam T_BlockCipher block cipher +/// \details \p EAX provides the \p Encryption and \p Decryption typedef. See EAX_Base +/// and EAX_Final for the AuthenticatedSymmetricCipher implementation. +/// \sa EAX Mode and +/// Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +template +struct EAX : public AuthenticatedSymmetricCipherDocumentation +{ + typedef EAX_Final Encryption; + typedef EAX_Final Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/ec2n.h b/third_party/cryptoppwin/include/cryptopp/ec2n.h new file mode 100644 index 00000000..529da045 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/ec2n.h @@ -0,0 +1,136 @@ +// ec2n.h - originally written and placed in the public domain by Wei Dai + +/// \file ec2n.h +/// \brief Classes for Elliptic Curves over binary fields + +#ifndef CRYPTOPP_EC2N_H +#define CRYPTOPP_EC2N_H + +#include "cryptlib.h" +#include "gf2n.h" +#include "integer.h" +#include "algebra.h" +#include "ecpoint.h" +#include "eprecomp.h" +#include "smartptr.h" +#include "pubkey.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Elliptic Curve over GF(2^n) +class CRYPTOPP_DLL EC2N : public AbstractGroup, public EncodedPoint +{ +public: + typedef GF2NP Field; + typedef Field::Element FieldElement; + typedef EC2NPoint Point; + + virtual ~EC2N() {} + + /// \brief Construct an EC2N + EC2N() {} + + /// \brief Construct an EC2N + /// \param field Field, GF2NP derived class + /// \param a Field::Element + /// \param b Field::Element + EC2N(const Field &field, const Field::Element &a, const Field::Element &b) + : m_field(field), m_a(a), m_b(b) {} + + /// \brief Construct an EC2N from BER encoded parameters + /// \param bt BufferedTransformation derived object + /// \details This constructor will decode and extract the fields fieldID and curve of the sequence ECParameters + EC2N(BufferedTransformation &bt); + + /// \brief Encode the fields fieldID and curve of the sequence ECParameters + /// \param bt BufferedTransformation derived object + void DEREncode(BufferedTransformation &bt) const; + + bool Equal(const Point &P, const Point &Q) const; + const Point& Identity() const; + const Point& Inverse(const Point &P) const; + bool InversionIsFast() const {return true;} + const Point& Add(const Point &P, const Point &Q) const; + const Point& Double(const Point &P) const; + + Point Multiply(const Integer &k, const Point &P) const + {return ScalarMultiply(P, k);} + Point CascadeMultiply(const Integer &k1, const Point &P, const Integer &k2, const Point &Q) const + {return CascadeScalarMultiply(P, k1, Q, k2);} + + bool ValidateParameters(RandomNumberGenerator &rng, unsigned int level=3) const; + bool VerifyPoint(const Point &P) const; + + unsigned int EncodedPointSize(bool compressed = false) const + {return 1 + (compressed?1:2)*m_field->MaxElementByteLength();} + // returns false if point is compressed and not valid (doesn't check if uncompressed) + bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const; + bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const; + void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const; + void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Point BERDecodePoint(BufferedTransformation &bt) const; + void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Integer FieldSize() const {return Integer::Power2(m_field->MaxElementBitLength());} + const Field & GetField() const {return *m_field;} + const FieldElement & GetA() const {return m_a;} + const FieldElement & GetB() const {return m_b;} + + bool operator==(const EC2N &rhs) const + {return GetField() == rhs.GetField() && m_a == rhs.m_a && m_b == rhs.m_b;} + +private: + clonable_ptr m_field; + FieldElement m_a, m_b; + mutable Point m_R; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_FixedBasePrecomputationImpl; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupPrecomputation; + +/// \brief Elliptic Curve precomputation +/// \tparam EC elliptic curve field +template class EcPrecomputation; + +/// \brief EC2N precomputation specialization +/// \details Implementation of DL_GroupPrecomputation +/// \sa DL_GroupPrecomputation +template<> class EcPrecomputation : public DL_GroupPrecomputation +{ +public: + typedef EC2N EllipticCurve; + + virtual ~EcPrecomputation() {} + + // DL_GroupPrecomputation + const AbstractGroup & GetGroup() const {return m_ec;} + Element BERDecodeElement(BufferedTransformation &bt) const {return m_ec.BERDecodePoint(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {m_ec.DEREncodePoint(bt, v, false);} + + /// \brief Set the elliptic curve + /// \param ec ECP derived class + /// \details SetCurve() is not inherited + void SetCurve(const EC2N &ec) {m_ec = ec;} + + /// \brief Get the elliptic curve + /// \return EC2N curve + /// \details GetCurve() is not inherited + const EC2N & GetCurve() const {return m_ec;} + +private: + EC2N m_ec; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/eccrypto.h b/third_party/cryptoppwin/include/cryptopp/eccrypto.h new file mode 100644 index 00000000..17ccb134 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/eccrypto.h @@ -0,0 +1,686 @@ +// eccrypto.h - originally written and placed in the public domain by Wei Dai +// deterministic signatures added by by Douglas Roark + +/// \file eccrypto.h +/// \brief Classes and functions for Elliptic Curves over prime and binary fields + +#ifndef CRYPTOPP_ECCRYPTO_H +#define CRYPTOPP_ECCRYPTO_H + +#include "config.h" +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" +#include "asn.h" +#include "hmac.h" +#include "sha.h" +#include "gfpcrypt.h" +#include "dh.h" +#include "mqv.h" +#include "hmqv.h" +#include "fhmqv.h" +#include "ecp.h" +#include "ec2n.h" + +#include + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Elliptic Curve Parameters +/// \tparam EC elliptic curve field +/// \details This class corresponds to the ASN.1 sequence of the same name +/// in ANSI X9.62 and SEC 1. EC is currently defined for ECP and EC2N. +template +class DL_GroupParameters_EC : public DL_GroupParametersImpl > +{ + typedef DL_GroupParameters_EC ThisClass; + +public: + typedef EC EllipticCurve; + typedef typename EllipticCurve::Point Point; + typedef Point Element; + typedef IncompatibleCofactorMultiplication DefaultCofactorOption; + + virtual ~DL_GroupParameters_EC() {} + + /// \brief Construct an EC GroupParameters + DL_GroupParameters_EC() : m_compress(false), m_encodeAsOID(true) {} + + /// \brief Construct an EC GroupParameters + /// \param oid the OID of a curve + DL_GroupParameters_EC(const OID &oid) + : m_compress(false), m_encodeAsOID(true) {Initialize(oid);} + + /// \brief Construct an EC GroupParameters + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param k the cofactor + DL_GroupParameters_EC(const EllipticCurve &ec, const Point &G, const Integer &n, const Integer &k = Integer::Zero()) + : m_compress(false), m_encodeAsOID(true) {Initialize(ec, G, n, k);} + + /// \brief Construct an EC GroupParameters + /// \param bt BufferedTransformation with group parameters + DL_GroupParameters_EC(BufferedTransformation &bt) + : m_compress(false), m_encodeAsOID(true) {BERDecode(bt);} + + /// \brief Initialize an EC GroupParameters using {EC,G,n,k} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param k the cofactor + /// \details This Initialize() function overload initializes group parameters from existing parameters. + void Initialize(const EllipticCurve &ec, const Point &G, const Integer &n, const Integer &k = Integer::Zero()) + { + this->m_groupPrecomputation.SetCurve(ec); + this->SetSubgroupGenerator(G); + m_n = n; + m_k = k; + } + + /// \brief Initialize a DL_GroupParameters_EC {EC,G,n,k} + /// \param oid the OID of a curve + /// \details This Initialize() function overload initializes group parameters from existing parameters. + void Initialize(const OID &oid); + + // NameValuePairs + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // GeneratibleCryptoMaterial interface + /// this implementation doesn't actually generate a curve, it just initializes the parameters with existing values + /*! parameters: (Curve, SubgroupGenerator, SubgroupOrder, Cofactor (optional)), or (GroupOID) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + // DL_GroupParameters + const DL_FixedBasePrecomputation & GetBasePrecomputation() const {return this->m_gpc;} + DL_FixedBasePrecomputation & AccessBasePrecomputation() {return this->m_gpc;} + const Integer & GetSubgroupOrder() const {return m_n;} + Integer GetCofactor() const; + bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const; + bool ValidateElement(unsigned int level, const Element &element, const DL_FixedBasePrecomputation *precomp) const; + bool FastSubgroupCheckAvailable() const {return false;} + void EncodeElement(bool reversible, const Element &element, byte *encoded) const + { + if (reversible) + GetCurve().EncodePoint(encoded, element, m_compress); + else + element.x.Encode(encoded, GetEncodedElementSize(false)); + } + virtual unsigned int GetEncodedElementSize(bool reversible) const + { + if (reversible) + return GetCurve().EncodedPointSize(m_compress); + else + return GetCurve().GetField().MaxElementByteLength(); + } + Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const + { + Point result; + if (!GetCurve().DecodePoint(result, encoded, GetEncodedElementSize(true))) + throw DL_BadElement(); + if (checkForGroupMembership && !ValidateElement(1, result, NULLPTR)) + throw DL_BadElement(); + return result; + } + Integer ConvertElementToInteger(const Element &element) const; + Integer GetMaxExponent() const {return GetSubgroupOrder()-1;} + bool IsIdentity(const Element &element) const {return element.identity;} + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + static std::string CRYPTOPP_API StaticAlgorithmNamePrefix() {return "EC";} + + // ASN1Key + OID GetAlgorithmID() const; + + // used by MQV + Element MultiplyElements(const Element &a, const Element &b) const; + Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const; + + // non-inherited + + // enumerate OIDs for recommended parameters, use OID() to get first one + static OID CRYPTOPP_API GetNextRecommendedParametersOID(const OID &oid); + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + void SetPointCompression(bool compress) {m_compress = compress;} + bool GetPointCompression() const {return m_compress;} + + void SetEncodeAsOID(bool encodeAsOID) {m_encodeAsOID = encodeAsOID;} + bool GetEncodeAsOID() const {return m_encodeAsOID;} + + const EllipticCurve& GetCurve() const {return this->m_groupPrecomputation.GetCurve();} + + bool operator==(const ThisClass &rhs) const + {return this->m_groupPrecomputation.GetCurve() == rhs.m_groupPrecomputation.GetCurve() && this->m_gpc.GetBase(this->m_groupPrecomputation) == rhs.m_gpc.GetBase(rhs.m_groupPrecomputation);} + +protected: + unsigned int FieldElementLength() const {return GetCurve().GetField().MaxElementByteLength();} + unsigned int ExponentLength() const {return m_n.ByteCount();} + + OID m_oid; // set if parameters loaded from a recommended curve + Integer m_n; // order of base point + mutable Integer m_k; // cofactor + mutable bool m_compress, m_encodeAsOID; // presentation details +}; + +inline std::ostream& operator<<(std::ostream& os, const DL_GroupParameters_EC::Element& obj); + +/// \brief Elliptic Curve Discrete Log (DL) public key +/// \tparam EC elliptic curve field +template +class DL_PublicKey_EC : public DL_PublicKeyImpl > +{ +public: + typedef typename EC::Point Element; + + virtual ~DL_PublicKey_EC() {} + + /// \brief Initialize an EC Public Key using {GP,Q} + /// \param params group parameters + /// \param Q the public point + /// \details This Initialize() function overload initializes a public key from existing parameters. + void Initialize(const DL_GroupParameters_EC ¶ms, const Element &Q) + {this->AccessGroupParameters() = params; this->SetPublicElement(Q);} + + /// \brief Initialize an EC Public Key using {EC,G,n,Q} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param Q the public point + /// \details This Initialize() function overload initializes a public key from existing parameters. + void Initialize(const EC &ec, const Element &G, const Integer &n, const Element &Q) + {this->AccessGroupParameters().Initialize(ec, G, n); this->SetPublicElement(Q);} + + // X509PublicKey + void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePublicKey(BufferedTransformation &bt) const; +}; + +/// \brief Elliptic Curve Discrete Log (DL) private key +/// \tparam EC elliptic curve field +template +class DL_PrivateKey_EC : public DL_PrivateKeyImpl > +{ +public: + typedef typename EC::Point Element; + + virtual ~DL_PrivateKey_EC(); + + /// \brief Initialize an EC Private Key using {GP,x} + /// \param params group parameters + /// \param x the private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const DL_GroupParameters_EC ¶ms, const Integer &x) + {this->AccessGroupParameters() = params; this->SetPrivateExponent(x);} + + /// \brief Initialize an EC Private Key using {EC,G,n,x} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param x the private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const EC &ec, const Element &G, const Integer &n, const Integer &x) + {this->AccessGroupParameters().Initialize(ec, G, n); this->SetPrivateExponent(x);} + + /// \brief Create an EC private key + /// \param rng a RandomNumberGenerator derived class + /// \param params the EC group parameters + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const DL_GroupParameters_EC ¶ms) + {this->GenerateRandom(rng, params);} + + /// \brief Create an EC private key + /// \param rng a RandomNumberGenerator derived class + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const EC &ec, const Element &G, const Integer &n) + {this->GenerateRandom(rng, DL_GroupParameters_EC(ec, G, n));} + + // PKCS8PrivateKey + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PrivateKey_EC::~DL_PrivateKey_EC() {} + +/// \brief Elliptic Curve Diffie-Hellman +/// \tparam EC elliptic curve field +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \sa CofactorMultiplicationOption, Elliptic Curve Diffie-Hellman, AKA ECDH +/// \since Crypto++ 3.0 +template ::DefaultCofactorOption> +struct ECDH +{ + typedef DH_Domain, COFACTOR_OPTION> Domain; +}; + +/// \brief Elliptic Curve Menezes-Qu-Vanstone +/// \tparam EC elliptic curve field +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \sa CofactorMultiplicationOption, Elliptic Curve Menezes-Qu-Vanstone, AKA ECMQV +template ::DefaultCofactorOption> +struct ECMQV +{ + typedef MQV_Domain, COFACTOR_OPTION> Domain; +}; + +/// \brief Hashed Elliptic Curve Menezes-Qu-Vanstone +/// \tparam EC elliptic curve field +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \details This implementation follows Hugo Krawczyk's HMQV: A High-Performance +/// Secure Diffie-Hellman Protocol. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided. +/// \sa CofactorMultiplicationOption +template ::DefaultCofactorOption, class HASH = SHA256> +struct ECHMQV +{ + typedef HMQV_Domain, COFACTOR_OPTION, HASH> Domain; +}; + +typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA1 >::Domain ECHMQV160; +typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA256 >::Domain ECHMQV256; +typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA384 >::Domain ECHMQV384; +typedef ECHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA512 >::Domain ECHMQV512; + +/// \brief Fully Hashed Elliptic Curve Menezes-Qu-Vanstone +/// \tparam EC elliptic curve field +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's +/// A Secure and Efficient Authenticated Diffie-Hellman Protocol. +/// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C. +/// \sa CofactorMultiplicationOption +template ::DefaultCofactorOption, class HASH = SHA256> +struct ECFHMQV +{ + typedef FHMQV_Domain, COFACTOR_OPTION, HASH> Domain; +}; + +typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA1 >::Domain ECFHMQV160; +typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA256 >::Domain ECFHMQV256; +typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA384 >::Domain ECFHMQV384; +typedef ECFHMQV< ECP, DL_GroupParameters_EC< ECP >::DefaultCofactorOption, SHA512 >::Domain ECFHMQV512; + +/// \brief Elliptic Curve Discrete Log (DL) keys +/// \tparam EC elliptic curve field +template +struct DL_Keys_EC +{ + typedef DL_PublicKey_EC PublicKey; + typedef DL_PrivateKey_EC PrivateKey; +}; + +// Forward declaration; documented below +template +struct ECDSA; + +/// \brief Elliptic Curve DSA keys +/// \tparam EC elliptic curve field +/// \since Crypto++ 3.2 +template +struct DL_Keys_ECDSA +{ + typedef DL_PublicKey_EC PublicKey; + typedef DL_PrivateKey_WithSignaturePairwiseConsistencyTest, ECDSA > PrivateKey; +}; + +/// \brief Elliptic Curve DSA (ECDSA) signature algorithm +/// \tparam EC elliptic curve field +/// \since Crypto++ 3.2 +template +class DL_Algorithm_ECDSA : public DL_Algorithm_GDSA +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECDSA";} +}; + +/// \brief Elliptic Curve DSA (ECDSA) signature algorithm based on RFC 6979 +/// \tparam EC elliptic curve field +/// \sa RFC 6979, Deterministic Usage of the +/// Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) +/// \since Crypto++ 6.0 +template +class DL_Algorithm_ECDSA_RFC6979 : public DL_Algorithm_DSA_RFC6979 +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECDSA-RFC6979";} +}; + +/// \brief Elliptic Curve NR (ECNR) signature algorithm +/// \tparam EC elliptic curve field +template +class DL_Algorithm_ECNR : public DL_Algorithm_NR +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECNR";} +}; + +/// \brief Elliptic Curve DSA (ECDSA) signature scheme +/// \tparam EC elliptic curve field +/// \tparam H HashTransformation derived class +/// \sa ECDSA +/// \since Crypto++ 3.2 +template +struct ECDSA : public DL_SS, DL_Algorithm_ECDSA, DL_SignatureMessageEncodingMethod_DSA, H> +{ +}; + +/// \brief Elliptic Curve DSA (ECDSA) deterministic signature scheme +/// \tparam EC elliptic curve field +/// \tparam H HashTransformation derived class +/// \sa Deterministic Usage of the +/// Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) +/// \since Crypto++ 6.0 +template +struct ECDSA_RFC6979 : public DL_SS< + DL_Keys_ECDSA, + DL_Algorithm_ECDSA_RFC6979, + DL_SignatureMessageEncodingMethod_DSA, + H, + ECDSA_RFC6979 > +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("ECDSA-RFC6979/") + H::StaticAlgorithmName();} +}; + +/// \brief Elliptic Curve NR (ECNR) signature scheme +/// \tparam EC elliptic curve field +/// \tparam H HashTransformation derived class +template +struct ECNR : public DL_SS, DL_Algorithm_ECNR, DL_SignatureMessageEncodingMethod_NR, H> +{ +}; + +// ****************************************** + +template +class DL_PublicKey_ECGDSA; +template +class DL_PrivateKey_ECGDSA; + +/// \brief Elliptic Curve German DSA key for ISO/IEC 15946 +/// \tparam EC elliptic curve field +/// \sa ECGDSA +/// \since Crypto++ 6.0 +template +class DL_PrivateKey_ECGDSA : public DL_PrivateKeyImpl > +{ +public: + typedef typename EC::Point Element; + + virtual ~DL_PrivateKey_ECGDSA() {} + + /// \brief Initialize an EC Private Key using {GP,x} + /// \param params group parameters + /// \param x the private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const DL_GroupParameters_EC ¶ms, const Integer &x) + { + this->AccessGroupParameters() = params; + this->SetPrivateExponent(x); + CRYPTOPP_ASSERT(x>=1 && x<=params.GetSubgroupOrder()-1); + } + + /// \brief Initialize an EC Private Key using {EC,G,n,x} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param x the private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const EC &ec, const Element &G, const Integer &n, const Integer &x) + { + this->AccessGroupParameters().Initialize(ec, G, n); + this->SetPrivateExponent(x); + CRYPTOPP_ASSERT(x>=1 && x<=this->AccessGroupParameters().GetSubgroupOrder()-1); + } + + /// \brief Create an EC private key + /// \param rng a RandomNumberGenerator derived class + /// \param params the EC group parameters + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const DL_GroupParameters_EC ¶ms) + {this->GenerateRandom(rng, params);} + + /// \brief Create an EC private key + /// \param rng a RandomNumberGenerator derived class + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, const EC &ec, const Element &G, const Integer &n) + {this->GenerateRandom(rng, DL_GroupParameters_EC(ec, G, n));} + + virtual void MakePublicKey(DL_PublicKey_ECGDSA &pub) const + { + const DL_GroupParameters& params = this->GetAbstractGroupParameters(); + pub.AccessAbstractGroupParameters().AssignFrom(params); + const Integer &xInv = this->GetPrivateExponent().InverseMod(params.GetSubgroupOrder()); + pub.SetPublicElement(params.ExponentiateBase(xInv)); + CRYPTOPP_ASSERT(xInv.NotZero()); + } + + virtual bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper, + DL_PrivateKey_ECGDSA >(this, name, valueType, pValue).Assignable(); + } + + virtual void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper, + DL_PrivateKey_ECGDSA >(this, source); + } + + // PKCS8PrivateKey + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; +}; + +/// \brief Elliptic Curve German DSA key for ISO/IEC 15946 +/// \tparam EC elliptic curve field +/// \sa ECGDSA +/// \since Crypto++ 6.0 +template +class DL_PublicKey_ECGDSA : public DL_PublicKeyImpl > +{ + typedef DL_PublicKey_ECGDSA ThisClass; + +public: + typedef typename EC::Point Element; + + virtual ~DL_PublicKey_ECGDSA() {} + + /// \brief Initialize an EC Public Key using {GP,Q} + /// \param params group parameters + /// \param Q the public point + /// \details This Initialize() function overload initializes a public key from existing parameters. + void Initialize(const DL_GroupParameters_EC ¶ms, const Element &Q) + {this->AccessGroupParameters() = params; this->SetPublicElement(Q);} + + /// \brief Initialize an EC Public Key using {EC,G,n,Q} + /// \param ec the elliptic curve + /// \param G the base point + /// \param n the order of the base point + /// \param Q the public point + /// \details This Initialize() function overload initializes a public key from existing parameters. + void Initialize(const EC &ec, const Element &G, const Integer &n, const Element &Q) + {this->AccessGroupParameters().Initialize(ec, G, n); this->SetPublicElement(Q);} + + virtual void AssignFrom(const NameValuePairs &source) + { + DL_PrivateKey_ECGDSA *pPrivateKey = NULLPTR; + if (source.GetThisPointer(pPrivateKey)) + pPrivateKey->MakePublicKey(*this); + else + { + this->AccessAbstractGroupParameters().AssignFrom(source); + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicElement); + } + } + + // DL_PublicKey + virtual void SetPublicElement(const Element &y) + {this->AccessPublicPrecomputation().SetBase(this->GetAbstractGroupParameters().GetGroupPrecomputation(), y);} + + // X509PublicKey + void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePublicKey(BufferedTransformation &bt) const; +}; + +/// \brief Elliptic Curve German DSA keys for ISO/IEC 15946 +/// \tparam EC elliptic curve field +/// \sa ECGDSA +/// \since Crypto++ 6.0 +template +struct DL_Keys_ECGDSA +{ + typedef DL_PublicKey_ECGDSA PublicKey; + typedef DL_PrivateKey_ECGDSA PrivateKey; +}; + +/// \brief Elliptic Curve German DSA signature algorithm +/// \tparam EC elliptic curve field +/// \sa ECGDSA +/// \since Crypto++ 6.0 +template +class DL_Algorithm_ECGDSA : public DL_Algorithm_GDSA_ISO15946 +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECGDSA";} +}; + +/// \brief Elliptic Curve German Digital Signature Algorithm signature scheme +/// \tparam EC elliptic curve field +/// \tparam H HashTransformation derived class +/// \sa Erwin Hess, Marcus Schafheutle, and Pascale Serf The Digital Signature Scheme +/// ECGDSA (October 24, 2006) +/// \since Crypto++ 6.0 +template +struct ECGDSA : public DL_SS< + DL_Keys_ECGDSA, + DL_Algorithm_ECGDSA, + DL_SignatureMessageEncodingMethod_DSA, + H> +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("ECGDSA-ISO15946/") + H::StaticAlgorithmName();} +}; + +// ****************************************** + +/// \brief Elliptic Curve Integrated Encryption Scheme +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \tparam HASH HashTransformation derived class used for key derivation and MAC computation +/// \tparam DHAES_MODE flag indicating if the MAC includes additional context parameters such as u·V, v·U and label +/// \tparam LABEL_OCTETS flag indicating if the label size is specified in octets or bits +/// \details ECIES is an Elliptic Curve based Integrated Encryption Scheme (IES). The scheme combines a Key Encapsulation +/// Method (KEM) with a Data Encapsulation Method (DEM) and a MAC tag. The scheme is +/// IND-CCA2, which is a strong notion of security. +/// You should prefer an Integrated Encryption Scheme over homegrown schemes. +/// \details If you desire an Integrated Encryption Scheme with Crypto++ 4.2 compatibility, then use the ECIES_P1363. +/// If you desire an Integrated Encryption Scheme compatible with Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the ECIES +/// template class with NoCofactorMultiplication, DHAES_MODE=true and LABEL_OCTETS=false. +/// \details The default template parameters ensure compatibility with Bouncy Castle 1.54 and Botan 1.11. The combination of +/// IncompatibleCofactorMultiplication and DHAES_MODE=true is recommended for best efficiency and security. +/// SHA1 is used for compatibility reasons, but it can be changed if desired. +/// \sa DLIES, ECIES_P1363, Elliptic Curve Integrated Encryption Scheme (ECIES), +/// Martínez, Encinas, and Ávila's A Survey of the Elliptic +/// Curve Integrated Encryption Schemes +/// \since Crypto++ 4.0, Crypto++ 5.7 for Bouncy Castle and Botan compatibility +template +struct ECIES + : public DL_ES< + DL_Keys_EC, + DL_KeyAgreementAlgorithm_DH, + DL_KeyDerivationAlgorithm_P1363 >, + DL_EncryptionAlgorithm_Xor, DHAES_MODE, LABEL_OCTETS>, + ECIES > +{ + // TODO: fix this after name is standardized + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECIES";} +}; + +/// \brief Elliptic Curve Integrated Encryption Scheme for P1363 +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \tparam HASH HashTransformation derived class used for key derivation and MAC computation +/// \details ECIES_P1363 is an Elliptic Curve based Integrated Encryption Scheme (IES) for P1363. The scheme combines a Key Encapsulation +/// Method (KEM) with a Data Encapsulation Method (DEM) and a MAC tag. The scheme is +/// IND-CCA2, which is a strong notion of security. +/// You should prefer an Integrated Encryption Scheme over homegrown schemes. +/// \details The library's original implementation is based on an early P1363 draft, which itself appears to be based on an early Certicom +/// SEC-1 draft (or an early SEC-1 draft was based on a P1363 draft). Crypto++ 4.2 used the early draft in its Integrated Enryption +/// Schemes with NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you desire an Integrated Encryption Scheme with Crypto++ 4.2 compatibility, then use the ECIES_P1363. +/// If you desire an Integrated Encryption Scheme compatible with Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the ECIES +/// template class with NoCofactorMultiplication, DHAES_MODE=true and LABEL_OCTETS=false. +/// \details The default template parameters ensure compatibility with P1363. The combination of +/// IncompatibleCofactorMultiplication and DHAES_MODE=true is recommended for best efficiency and security. +/// SHA1 is used for compatibility reasons, but it can be changed if desired. +/// \sa DLIES, ECIES, Elliptic Curve Integrated Encryption Scheme (ECIES), +/// Martínez, Encinas, and Ávila's A Survey of the Elliptic +/// Curve Integrated Encryption Schemes +/// \since Crypto++ 4.0 +template +struct ECIES_P1363 + : public DL_ES< + DL_Keys_EC, + DL_KeyAgreementAlgorithm_DH, + DL_KeyDerivationAlgorithm_P1363 >, + DL_EncryptionAlgorithm_Xor, false, true>, + ECIES > +{ + // TODO: fix this after name is standardized + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECIES-P1363";} +}; + +NAMESPACE_END + +#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#include "eccrypto.cpp" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKeyImpl >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_ECGDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_ECGDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_ECGDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_ECGDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest, ECDSA >; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest, ECDSA >; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/ecp.h b/third_party/cryptoppwin/include/cryptopp/ecp.h new file mode 100644 index 00000000..28929d00 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/ecp.h @@ -0,0 +1,167 @@ +// ecp.h - originally written and placed in the public domain by Wei Dai + +/// \file ecp.h +/// \brief Classes for Elliptic Curves over prime fields + +#ifndef CRYPTOPP_ECP_H +#define CRYPTOPP_ECP_H + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "modarith.h" +#include "ecpoint.h" +#include "eprecomp.h" +#include "smartptr.h" +#include "pubkey.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Elliptic Curve over GF(p), where p is prime +class CRYPTOPP_DLL ECP : public AbstractGroup, public EncodedPoint +{ +public: + typedef ModularArithmetic Field; + typedef Integer FieldElement; + typedef ECPPoint Point; + + virtual ~ECP() {} + + /// \brief Construct an ECP + ECP() {} + + /// \brief Construct an ECP + /// \param ecp the other ECP object + /// \param convertToMontgomeryRepresentation flag indicating if the curve + /// should be converted to a MontgomeryRepresentation. + /// \details Prior to Crypto++ 8.3 the default value for + /// convertToMontgomeryRepresentation was false. it was changed due to + /// two audit tools finding, "Signature-compatible with a copy constructor". + /// \sa ModularArithmetic, MontgomeryRepresentation + ECP(const ECP &ecp, bool convertToMontgomeryRepresentation); + + /// \brief Construct an ECP + /// \param modulus the prime modulus + /// \param a Field::Element + /// \param b Field::Element + ECP(const Integer &modulus, const FieldElement &a, const FieldElement &b) + : m_fieldPtr(new Field(modulus)), m_a(a.IsNegative() ? modulus+a : a), m_b(b) {} + + /// \brief Construct an ECP from BER encoded parameters + /// \param bt BufferedTransformation derived object + /// \details This constructor will decode and extract the fields + /// fieldID and curve of the sequence ECParameters + ECP(BufferedTransformation &bt); + + /// \brief DER Encode + /// \param bt BufferedTransformation derived object + /// \details DEREncode encode the fields fieldID and curve of the sequence + /// ECParameters + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Compare two points + /// \param P the first point + /// \param Q the second point + /// \return true if equal, false otherwise + bool Equal(const Point &P, const Point &Q) const; + + const Point& Identity() const; + const Point& Inverse(const Point &P) const; + bool InversionIsFast() const {return true;} + const Point& Add(const Point &P, const Point &Q) const; + const Point& Double(const Point &P) const; + Point ScalarMultiply(const Point &P, const Integer &k) const; + Point CascadeScalarMultiply(const Point &P, const Integer &k1, const Point &Q, const Integer &k2) const; + void SimultaneousMultiply(Point *results, const Point &base, const Integer *exponents, unsigned int exponentsCount) const; + + Point Multiply(const Integer &k, const Point &P) const + {return ScalarMultiply(P, k);} + Point CascadeMultiply(const Integer &k1, const Point &P, const Integer &k2, const Point &Q) const + {return CascadeScalarMultiply(P, k1, Q, k2);} + + bool ValidateParameters(RandomNumberGenerator &rng, unsigned int level=3) const; + bool VerifyPoint(const Point &P) const; + + unsigned int EncodedPointSize(bool compressed = false) const + {return 1 + (compressed?1:2)*GetField().MaxElementByteLength();} + // returns false if point is compressed and not valid (doesn't check if uncompressed) + bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const; + bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const; + void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const; + void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Point BERDecodePoint(BufferedTransformation &bt) const; + void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const; + + Integer FieldSize() const {return GetField().GetModulus();} + const Field & GetField() const {return *m_fieldPtr;} + const FieldElement & GetA() const {return m_a;} + const FieldElement & GetB() const {return m_b;} + + bool operator==(const ECP &rhs) const + {return GetField() == rhs.GetField() && m_a == rhs.m_a && m_b == rhs.m_b;} + +private: + clonable_ptr m_fieldPtr; + FieldElement m_a, m_b; + mutable Point m_R; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_FixedBasePrecomputationImpl; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupPrecomputation; + +/// \brief Elliptic Curve precomputation +/// \tparam EC elliptic curve field +template class EcPrecomputation; + +/// \brief ECP precomputation specialization +/// \details Implementation of DL_GroupPrecomputation with input and output +/// conversions for Montgomery modular multiplication. +/// \sa DL_GroupPrecomputation, ModularArithmetic, MontgomeryRepresentation +template<> class EcPrecomputation : public DL_GroupPrecomputation +{ +public: + typedef ECP EllipticCurve; + + virtual ~EcPrecomputation() {} + + // DL_GroupPrecomputation + bool NeedConversions() const {return true;} + Element ConvertIn(const Element &P) const + {return P.identity ? P : ECP::Point(m_ec->GetField().ConvertIn(P.x), m_ec->GetField().ConvertIn(P.y));}; + Element ConvertOut(const Element &P) const + {return P.identity ? P : ECP::Point(m_ec->GetField().ConvertOut(P.x), m_ec->GetField().ConvertOut(P.y));} + const AbstractGroup & GetGroup() const {return *m_ec;} + Element BERDecodeElement(BufferedTransformation &bt) const {return m_ec->BERDecodePoint(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {m_ec->DEREncodePoint(bt, v, false);} + + /// \brief Set the elliptic curve + /// \param ec ECP derived class + /// \details SetCurve() is not inherited + void SetCurve(const ECP &ec) + { + m_ec.reset(new ECP(ec, true)); + m_ecOriginal = ec; + } + + /// \brief Get the elliptic curve + /// \return ECP curve + /// \details GetCurve() is not inherited + const ECP & GetCurve() const {return *m_ecOriginal;} + +private: + value_ptr m_ec, m_ecOriginal; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/ecpoint.h b/third_party/cryptoppwin/include/cryptopp/ecpoint.h new file mode 100644 index 00000000..2be93bc7 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/ecpoint.h @@ -0,0 +1,146 @@ +// ecpoint.h - written and placed in the public domain by Jeffrey Walton +// Data structures moved from ecp.h and ec2n.h. Added EncodedPoint interface + +/// \file ecpoint.h +/// \brief Classes for Elliptic Curve points +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_ECPOINT_H +#define CRYPTOPP_ECPOINT_H + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "gf2n.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Elliptical Curve Point over GF(p), where p is prime +/// \since Crypto++ 2.0 +struct CRYPTOPP_DLL ECPPoint +{ + virtual ~ECPPoint() {} + + /// \brief Construct an ECPPoint + /// \details identity is set to true + ECPPoint() : identity(true) {} + + /// \brief Construct an ECPPoint from coordinates + /// \details identity is set to false + ECPPoint(const Integer &x, const Integer &y) + : x(x), y(y), identity(false) {} + + /// \brief Tests points for equality + /// \param t the other point + /// \return true if the points are equal, false otherwise + bool operator==(const ECPPoint &t) const + {return (identity && t.identity) || (!identity && !t.identity && x==t.x && y==t.y);} + + /// \brief Tests points for ordering + /// \param t the other point + /// \return true if this point is less than other, false otherwise + bool operator< (const ECPPoint &t) const + {return identity ? !t.identity : (!t.identity && (x; + +/// \brief Elliptical Curve Point over GF(2^n) +/// \since Crypto++ 2.0 +struct CRYPTOPP_DLL EC2NPoint +{ + virtual ~EC2NPoint() {} + + /// \brief Construct an EC2NPoint + /// \details identity is set to true + EC2NPoint() : identity(true) {} + + /// \brief Construct an EC2NPoint from coordinates + /// \details identity is set to false + EC2NPoint(const PolynomialMod2 &x, const PolynomialMod2 &y) + : x(x), y(y), identity(false) {} + + /// \brief Tests points for equality + /// \param t the other point + /// \return true if the points are equal, false otherwise + bool operator==(const EC2NPoint &t) const + {return (identity && t.identity) || (!identity && !t.identity && x==t.x && y==t.y);} + + /// \brief Tests points for ordering + /// \param t the other point + /// \return true if this point is less than other, false otherwise + bool operator< (const EC2NPoint &t) const + {return identity ? !t.identity : (!t.identity && (x; + +/// \brief Abstract class for encoding and decoding ellicptic curve points +/// \tparam Point ellicptic curve point +/// \details EncodedPoint is an interface for encoding and decoding elliptic curve points. +/// The template parameter Point should be a class like ECP or EC2N. +/// \since Crypto++ 6.0 +template +class EncodedPoint +{ +public: + virtual ~EncodedPoint() {} + + /// \brief Decodes an elliptic curve point + /// \param P point which is decoded + /// \param bt source BufferedTransformation + /// \param len number of bytes to read from the BufferedTransformation + /// \return true if a point was decoded, false otherwise + virtual bool DecodePoint(Point &P, BufferedTransformation &bt, size_t len) const =0; + + /// \brief Decodes an elliptic curve point + /// \param P point which is decoded + /// \param encodedPoint byte array with the encoded point + /// \param len the size of the array + /// \return true if a point was decoded, false otherwise + virtual bool DecodePoint(Point &P, const byte *encodedPoint, size_t len) const =0; + + /// \brief Verifies points on elliptic curve + /// \param P point to verify + /// \return true if the point is valid, false otherwise + virtual bool VerifyPoint(const Point &P) const =0; + + /// \brief Determines encoded point size + /// \param compressed flag indicating if the point is compressed + /// \return the minimum number of bytes required to encode the point + virtual unsigned int EncodedPointSize(bool compressed = false) const =0; + + /// \brief Encodes an elliptic curve point + /// \param P point which is decoded + /// \param encodedPoint byte array for the encoded point + /// \param compressed flag indicating if the point is compressed + /// \details encodedPoint must be at least EncodedPointSize() in length + virtual void EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const =0; + + /// \brief Encodes an elliptic curve point + /// \param bt target BufferedTransformation + /// \param P point which is encoded + /// \param compressed flag indicating if the point is compressed + virtual void EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const =0; + + /// \brief BER Decodes an elliptic curve point + /// \param bt source BufferedTransformation + /// \return the decoded elliptic curve point + virtual Point BERDecodePoint(BufferedTransformation &bt) const =0; + + /// \brief DER Encodes an elliptic curve point + /// \param bt target BufferedTransformation + /// \param P point which is encoded + /// \param compressed flag indicating if the point is compressed + virtual void DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const =0; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_ECPOINT_H diff --git a/third_party/cryptoppwin/include/cryptopp/elgamal.h b/third_party/cryptoppwin/include/cryptopp/elgamal.h new file mode 100644 index 00000000..f979f0a8 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/elgamal.h @@ -0,0 +1,308 @@ +// elgamal.h - originally written and placed in the public domain by Wei Dai + +/// \file elgamal.h +/// \brief Classes and functions for ElGamal key agreement and encryption schemes + +#ifndef CRYPTOPP_ELGAMAL_H +#define CRYPTOPP_ELGAMAL_H + +#include "cryptlib.h" +#include "modexppc.h" +#include "integer.h" +#include "gfpcrypt.h" +#include "pubkey.h" +#include "misc.h" +#include "oids.h" +#include "dsa.h" +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ElGamal key agreement and encryption schemes base class +/// \since Crypto++ 1.0 +class CRYPTOPP_NO_VTABLE ElGamalBase : + public DL_KeyAgreementAlgorithm_DH, + public DL_KeyDerivationAlgorithm, + public DL_SymmetricEncryptionAlgorithm +{ +public: + virtual ~ElGamalBase() {} + + void Derive(const DL_GroupParameters &groupParams, byte *derivedKey, size_t derivedLength, const Integer &agreedElement, const Integer &ephemeralPublicKey, const NameValuePairs &derivationParams) const + { + CRYPTOPP_UNUSED(groupParams); CRYPTOPP_UNUSED(ephemeralPublicKey); + CRYPTOPP_UNUSED(derivationParams); + agreedElement.Encode(derivedKey, derivedLength); + } + + size_t GetSymmetricKeyLength(size_t plainTextLength) const + { + CRYPTOPP_UNUSED(plainTextLength); + return GetGroupParameters().GetModulus().ByteCount(); + } + + size_t GetSymmetricCiphertextLength(size_t plainTextLength) const + { + unsigned int len = GetGroupParameters().GetModulus().ByteCount(); + if (plainTextLength <= GetMaxSymmetricPlaintextLength(len)) + return len; + else + return 0; + } + + size_t GetMaxSymmetricPlaintextLength(size_t cipherTextLength) const + { + unsigned int len = GetGroupParameters().GetModulus().ByteCount(); + CRYPTOPP_ASSERT(len >= 3); + + if (cipherTextLength == len) + return STDMIN(255U, len-3); + else + return 0; + } + + void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plainText, size_t plainTextLength, byte *cipherText, const NameValuePairs ¶meters) const + { + CRYPTOPP_UNUSED(parameters); + const Integer &p = GetGroupParameters().GetModulus(); + unsigned int modulusLen = p.ByteCount(); + + SecByteBlock block(modulusLen-1); + rng.GenerateBlock(block, modulusLen-2-plainTextLength); + std::memcpy(block+modulusLen-2-plainTextLength, plainText, plainTextLength); + block[modulusLen-2] = (byte)plainTextLength; + + a_times_b_mod_c(Integer(key, modulusLen), Integer(block, modulusLen-1), p).Encode(cipherText, modulusLen); + } + + DecodingResult SymmetricDecrypt(const byte *key, const byte *cipherText, size_t cipherTextLength, byte *plainText, const NameValuePairs ¶meters) const + { + CRYPTOPP_UNUSED(parameters); + const Integer &p = GetGroupParameters().GetModulus(); + unsigned int modulusLen = p.ByteCount(); + + if (cipherTextLength != modulusLen) + return DecodingResult(); + + Integer m = a_times_b_mod_c(Integer(cipherText, modulusLen), Integer(key, modulusLen).InverseMod(p), p); + + m.Encode(plainText, 1); + unsigned int plainTextLength = plainText[0]; + if (plainTextLength > GetMaxSymmetricPlaintextLength(modulusLen)) + return DecodingResult(); + m >>= 8; + m.Encode(plainText, plainTextLength); + return DecodingResult(plainTextLength); + } + + virtual const DL_GroupParameters_GFP & GetGroupParameters() const =0; +}; + +/// \brief ElGamal key agreement and encryption schemes default implementation +/// \tparam BASE Base class implementation +/// \tparam SCHEME_OPTIONS Scheme options +/// \tparam KEY ElGamal key classes +/// \since Crypto++ 1.0 +template +class ElGamalObjectImpl : + public DL_ObjectImplBase, + public ElGamalBase +{ +public: + virtual ~ElGamalObjectImpl() {} + + size_t FixedMaxPlaintextLength() const {return this->MaxPlaintextLength(FixedCiphertextLength());} + size_t FixedCiphertextLength() const {return this->CiphertextLength(0);} + + const DL_GroupParameters_GFP & GetGroupParameters() const {return this->GetKey().GetGroupParameters();} + + DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *cipherText, byte *plainText) const + {return Decrypt(rng, cipherText, FixedCiphertextLength(), plainText);} + +protected: + const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const {return *this;} + const DL_KeyDerivationAlgorithm & GetKeyDerivationAlgorithm() const {return *this;} + const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const {return *this;} +}; + +/// \brief ElGamal Public Key adapter +/// \tparam BASE PublicKey derived class +/// \details DL_PublicKey_ElGamal provides an override for GetAlgorithmID() +/// to utilize 1.3.14.7.2.1.1. Prior to DL_PublicKey_ElGamal, the ElGamal +/// keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP(). +/// If you need to Load an ElGamal key with the wrong OID then +/// see ElGamal on +/// the Crypto++ wiki. +/// \sa Issue 876, +/// Issue 567 +/// \since Crypto++ 8.3 +template +struct DL_PublicKey_ElGamal : public BASE +{ + virtual ~DL_PublicKey_ElGamal() {} + + /// \brief Retrieves the OID of the algorithm + /// \return OID of the algorithm + /// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID() + /// to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal + /// keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP(). + /// If you need to Load an ElGamal key with the wrong OID then + /// see ElGamal on + /// the Crypto++ wiki. + /// \sa Issue 876, + /// Issue 567 + virtual OID GetAlgorithmID() const { + return ASN1::elGamal(); + } +}; + +/// \brief ElGamal Private Key adapter +/// \tparam BASE PrivateKey derived class +/// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID() +/// to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal +/// keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP(). +/// If you need to Load an ElGamal key with the wrong OID then +/// see ElGamal on +/// the Crypto++ wiki. +/// \sa Issue 876, +/// Issue 567 +/// \since Crypto++ 8.3 +template +struct DL_PrivateKey_ElGamal : public BASE +{ + virtual ~DL_PrivateKey_ElGamal() {} + + /// \brief Retrieves the OID of the algorithm + /// \return OID of the algorithm + /// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID() + /// to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal + /// keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP(). + /// If you need to Load an ElGamal key with the wrong OID then + /// see ElGamal on + /// the Crypto++ wiki. + /// \sa Issue 876, + /// Issue 567 + virtual OID GetAlgorithmID() const { + return ASN1::elGamal(); + } + + /// \brief Check the key for errors + /// \param rng RandomNumberGenerator for objects which use randomized testing + /// \param level level of thoroughness + /// \return true if the tests succeed, false otherwise + /// \details There are four levels of thoroughness: + ///
    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other + /// operations correctly + ///
  • 2 - ensure this object will function correctly, and perform + /// reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may + /// take a long time + ///
+ /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can + /// be used for level 0. Level 1 may not check for weak keys and such. + /// Levels 2 and 3 are recommended. + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + // Validate() formerly used DL_PrivateKey_GFP implementation through + // inheritance. However, it would reject keys from other libraries + // like BouncyCastle. The failure was x < q. According to ElGamal's + // paper and the HAC, the private key is selected in over [1,p-1], + // Later Tsiounis and Yung showed the lower limit as [1,q-1] in + // "On the Security of EIGamal Based Encryption". As such, Crypto++ + // will generate a key in the range [1,q-1], but accept a key + // in [1,p-1]. Thanks to JPM for finding the reference. Also see + // https://github.com/weidai11/cryptopp/commit/a5a684d92986. + + CRYPTOPP_ASSERT(this->GetAbstractGroupParameters().Validate(rng, level)); + bool pass = this->GetAbstractGroupParameters().Validate(rng, level); + + const Integer &p = this->GetGroupParameters().GetModulus(); + const Integer &q = this->GetAbstractGroupParameters().GetSubgroupOrder(); + const Integer &x = this->GetPrivateExponent(); + + // Changed to x < p-1 based on ElGamal's paper and the HAC. + CRYPTOPP_ASSERT(x.IsPositive()); + CRYPTOPP_ASSERT(x < p-1); + pass = pass && x.IsPositive() && x < p-1; + + if (level >= 1) + { + // Minimum security level due to Tsiounis and Yung. + CRYPTOPP_ASSERT(Integer::Gcd(x, q) == Integer::One()); + pass = pass && Integer::Gcd(x, q) == Integer::One(); + } + return pass; + } +}; + +/// \brief ElGamal key agreement and encryption schemes keys +/// \details ElGamalKeys provide the algorithm implementation ElGamal key +/// agreement and encryption schemes. +/// \details The ElGamalKeys class used DL_PrivateKey_GFP_OldFormat +/// and DL_PublicKey_GFP_OldFormat for the PrivateKey and +/// PublicKey from about Crypto++ 1.0 through Crypto++ 5.6.5. At +/// Crypto++ 6.0 the serialization format was cutover to standard PKCS8 and +/// X509 encodings. +/// \details The ElGamalKeys class [mistakenly] used the OID for DSA from +/// about Crypto++ 1.0 through Crypto++ 8.2. At Crypto++ 8.3 the OID was +/// fixed and now uses ElGamal encryption, which is 1.3.14.7.2.1.1. +/// If you need to Load an ElGamal key with the wrong OID then +/// see ElGamal on +/// the Crypto++ wiki. +/// \details At Crypto++ 8.6 ElGamalKeys were changed to use DL_CryptoKeys_ElGamal +/// due to Issue 1069 and CVE-2021-40530. DL_CryptoKeys_ElGamal group parameters +/// use the subgroup order, and not an estimated work factor. +/// \sa Issue 876, +/// Issue 567, +/// Issue 1059 +/// \since Crypto++ 1.0 +struct ElGamalKeys +{ + /// \brief Implements DL_GroupParameters interface + typedef DL_CryptoKeys_ElGamal::GroupParameters GroupParameters; + /// \brief Implements DL_PrivateKey interface + typedef DL_PrivateKey_ElGamal PrivateKey; + /// \brief Implements DL_PublicKey interface + typedef DL_PublicKey_ElGamal PublicKey; +}; + +/// \brief ElGamal encryption scheme with non-standard padding +/// \details ElGamal provide the algorithm implementation ElGamal key +/// agreement and encryption schemes. +/// \details The ElGamal class [mistakenly] used the OID for DSA from about +/// Crypto++ 1.0 through Crypto++ 8.2. At Crypto++ 8.3 the OID was fixed +/// and now uses ElGamal encryption, which is 1.3.14.7.2.1.1. +/// If you need to Load an ElGamal key with the wrong OID then +/// see ElGamal on +/// the Crypto++ wiki. +/// \sa Issue 876, +/// Issue 567 +/// \since Crypto++ 1.0 +struct ElGamal +{ + typedef DL_CryptoSchemeOptions SchemeOptions; + typedef SchemeOptions::PrivateKey PrivateKey; + typedef SchemeOptions::PublicKey PublicKey; + + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ElgamalEnc/Crypto++Padding";} + + /// \brief Implements DL_GroupParameters interface + typedef SchemeOptions::GroupParameters GroupParameters; + /// \brief Implements PK_Encryptor interface + typedef PK_FinalTemplate, SchemeOptions, SchemeOptions::PublicKey> > Encryptor; + /// \brief Implements PK_Encryptor interface + typedef PK_FinalTemplate, SchemeOptions, SchemeOptions::PrivateKey> > Decryptor; +}; + +typedef ElGamal::Encryptor ElGamalEncryptor; +typedef ElGamal::Decryptor ElGamalDecryptor; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/emsa2.h b/third_party/cryptoppwin/include/cryptopp/emsa2.h new file mode 100644 index 00000000..d39e73db --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/emsa2.h @@ -0,0 +1,101 @@ +// emsa2.h - originally written and placed in the public domain by Wei Dai + +/// \file emsa2.h +/// \brief Classes and functions for various padding schemes used in public key algorithms + +#ifndef CRYPTOPP_EMSA2_H +#define CRYPTOPP_EMSA2_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "hashfwd.h" +#include "misc.h" + +#ifdef CRYPTOPP_IS_DLL +# include "sha.h" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief EMSA2 hash identifier +/// \tparam H HashTransformation derived class +/// \since Crypto++ 5.0 +template class EMSA2HashId +{ +public: + static const byte id; +}; + +/// \brief EMSA2 padding method +/// \tparam BASE Message encoding method +/// \since Crypto++ 5.0 +template +class EMSA2HashIdLookup : public BASE +{ +public: + struct HashIdentifierLookup + { + template struct HashIdentifierLookup2 + { + static HashIdentifier Lookup() + { + return HashIdentifier(&EMSA2HashId::id, 1); + } + }; + }; +}; + +// EMSA2HashId can be instantiated with the following classes. +// SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD128, RIPEMD160, Whirlpool + +#ifdef CRYPTOPP_IS_DLL +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +CRYPTOPP_DLL_TEMPLATE_CLASS EMSA2HashId; +#endif + +// https://github.com/weidai11/cryptopp/issues/300 and +// https://github.com/weidai11/cryptopp/issues/533 +#if defined(__clang__) +template<> const byte EMSA2HashId::id; +template<> const byte EMSA2HashId::id; +template<> const byte EMSA2HashId::id; +template<> const byte EMSA2HashId::id; +template<> const byte EMSA2HashId::id; +#endif + +/// \brief EMSA2 padding method +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL EMSA2Pad : public EMSA2HashIdLookup +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "EMSA2";} + + size_t MinRepresentativeBitLength(size_t hashIdentifierLength, size_t digestLength) const + {CRYPTOPP_UNUSED(hashIdentifierLength); return 8*digestLength + 31;} + + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +// EMSA2, for use with RWSS and RSA_ISO +// Only the following hash functions are supported by this signature standard: +// \dontinclude emsa2.h +// \skip EMSA2HashId can be instantiated +// \until end of list + +/// \brief EMSA2/P1363 padding method +/// \details Use with RWSS and RSA_ISO +/// \since Crypto++ 5.0 +struct P1363_EMSA2 : public SignatureStandard +{ + typedef EMSA2Pad SignatureMessageEncodingMethod; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/eprecomp.h b/third_party/cryptoppwin/include/cryptopp/eprecomp.h new file mode 100644 index 00000000..7049d4bd --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/eprecomp.h @@ -0,0 +1,162 @@ +// eprecomp.h - originally written and placed in the public domain by Wei Dai + +/// \file eprecomp.h +/// \brief Classes for precomputation in a group + +#ifndef CRYPTOPP_EPRECOMP_H +#define CRYPTOPP_EPRECOMP_H + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief DL_GroupPrecomputation interface +/// \tparam T Field element +template +class DL_GroupPrecomputation +{ +public: + typedef T Element; + + virtual ~DL_GroupPrecomputation() {} + + /// \brief Determines if elements needs conversion + /// \return true if the element needs conversion, false otherwise + /// \details NeedConversions determines if an element must convert between representations. + virtual bool NeedConversions() const {return false;} + + /// \brief Converts an element between representations + /// \param v element to convert + /// \return an element converted to an alternate representation for internal use + /// \details ConvertIn is used when an element must convert between representations. + virtual Element ConvertIn(const Element &v) const {return v;} + + /// \brief Converts an element between representations + /// \param v element to convert + /// \return an element converted from an alternate representation + virtual Element ConvertOut(const Element &v) const {return v;} + + /// \brief Retrieves AbstractGroup interface + /// \return GetGroup() returns the AbstractGroup interface + virtual const AbstractGroup & GetGroup() const =0; + + /// \brief Decodes element in DER format + /// \param bt BufferedTransformation object + /// \return element in the group + virtual Element BERDecodeElement(BufferedTransformation &bt) const =0; + + /// \brief Encodes element in DER format + /// \param bt BufferedTransformation object + /// \param P Element to encode + virtual void DEREncodeElement(BufferedTransformation &bt, const Element &P) const =0; +}; + +/// \brief DL_FixedBasePrecomputation interface +/// \tparam T Field element +template +class DL_FixedBasePrecomputation +{ +public: + typedef T Element; + + virtual ~DL_FixedBasePrecomputation() {} + + /// \brief Determines whether this object is initialized + /// \return true if this object is initialized, false otherwise + virtual bool IsInitialized() const =0; + + /// \brief Set the base element + /// \param group the group + /// \param base element in the group + virtual void SetBase(const DL_GroupPrecomputation &group, const Element &base) =0; + + /// \brief Get the base element + /// \param group the group + /// \return base element in the group + virtual const Element & GetBase(const DL_GroupPrecomputation &group) const =0; + + /// \brief Perform precomputation + /// \param group the group + /// \param maxExpBits used to calculate the exponent base + /// \param storage the suggested number of objects for the precompute table + /// \details The exact semantics of Precompute() varies, but it typically means calculate + /// a table of n objects that can be used later to speed up computation. + /// \details If a derived class does not override Precompute(), then the base class throws + /// NotImplemented. + /// \sa SupportsPrecomputation(), LoadPrecomputation(), SavePrecomputation() + virtual void Precompute(const DL_GroupPrecomputation &group, unsigned int maxExpBits, unsigned int storage) =0; + + /// \brief Retrieve previously saved precomputation + /// \param group the group + /// \param storedPrecomputation BufferedTransformation with the saved precomputation + /// \throw NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + virtual void Load(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) =0; + + /// \brief Save precomputation for later use + /// \param group the group + /// \param storedPrecomputation BufferedTransformation to write the precomputation + /// \throw NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + virtual void Save(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) const =0; + + /// \brief Exponentiates an element + /// \param group the group + /// \param exponent the exponent + /// \return the result of the exponentiation + virtual Element Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const =0; + + /// \brief Exponentiates an element + /// \param pc1 the first the group precomputation + /// \param exponent1 the first exponent + /// \param pc2 the second the group precomputation + /// \param exponent2 the first exponent2 + /// \return the public element raised to the exponent + /// \details CascadeExponentiateBaseAndPublicElement raises the public element to + /// the base element and precomputation. + virtual Element CascadeExponentiate(const DL_GroupPrecomputation &pc1, const Integer &exponent1, const DL_FixedBasePrecomputation &pc2, const Integer &exponent2) const =0; +}; + +/// \brief DL_FixedBasePrecomputation adapter class +/// \tparam T Field element +template +class DL_FixedBasePrecomputationImpl : public DL_FixedBasePrecomputation +{ +public: + typedef T Element; + + virtual ~DL_FixedBasePrecomputationImpl() {} + + DL_FixedBasePrecomputationImpl() : m_windowSize(0) {} + + // DL_FixedBasePrecomputation + bool IsInitialized() const + {return !m_bases.empty();} + void SetBase(const DL_GroupPrecomputation &group, const Element &base); + const Element & GetBase(const DL_GroupPrecomputation &group) const + {return group.NeedConversions() ? m_base : m_bases[0];} + void Precompute(const DL_GroupPrecomputation &group, unsigned int maxExpBits, unsigned int storage); + void Load(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation); + void Save(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) const; + Element Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const; + Element CascadeExponentiate(const DL_GroupPrecomputation &pc1, const Integer &exponent1, const DL_FixedBasePrecomputation &pc2, const Integer &exponent2) const; + +private: + void PrepareCascade(const DL_GroupPrecomputation &group, std::vector > &eb, const Integer &exponent) const; + + Element m_base; + unsigned int m_windowSize; + Integer m_exponentBase; // what base to represent the exponent in + std::vector m_bases; // precalculated bases +}; + +NAMESPACE_END + +#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +#include "eprecomp.cpp" +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/esign.h b/third_party/cryptoppwin/include/cryptopp/esign.h new file mode 100644 index 00000000..2c597c25 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/esign.h @@ -0,0 +1,169 @@ +// esign.h - originally written and placed in the public domain by Wei Dai + +/// \file esign.h +/// \brief Classes providing ESIGN signature schemes as defined in IEEE P1363a +/// \since Crypto++ 5.0 + +#ifndef CRYPTOPP_ESIGN_H +#define CRYPTOPP_ESIGN_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" +#include "asn.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief ESIGN trapdoor function using the public key +/// \since Crypto++ 5.0 +class ESIGNFunction : public TrapdoorFunction, public ASN1CryptoMaterial +{ + typedef ESIGNFunction ThisClass; + +public: + + /// \brief Initialize a ESIGN public key with {n,e} + /// \param n the modulus + /// \param e the public exponent + void Initialize(const Integer &n, const Integer &e) + {m_n = n; m_e = e;} + + // PublicKey + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // TrapdoorFunction + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return Integer::Power2(GetK());} + + // non-derived + const Integer & GetModulus() const {return m_n;} + const Integer & GetPublicExponent() const {return m_e;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetPublicExponent(const Integer &e) {m_e = e;} + +protected: + // Covertiy finding on overflow. The library allows small values for research purposes. + unsigned int GetK() const {return SaturatingSubtract(m_n.BitCount()/3, 1U);} + + Integer m_n, m_e; +}; + +/// \brief ESIGN trapdoor function using the private key +/// \since Crypto++ 5.0 +class InvertibleESIGNFunction : public ESIGNFunction, public RandomizedTrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleESIGNFunction ThisClass; + +public: + + /// \brief Initialize a ESIGN private key with {n,e,p,q} + /// \param n modulus + /// \param e public exponent + /// \param p first prime factor + /// \param q second prime factor + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &e, const Integer &p, const Integer &q) + {m_n = n; m_e = e; m_p = p; m_q = q;} + + /// \brief Create a ESIGN private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulud, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {GenerateRandomWithKeySize(rng, modulusBits);} + + // Squash Visual Studio C4250 warning + void Save(BufferedTransformation &bt) const + {BEREncode(bt);} + + // Squash Visual Studio C4250 warning + void Load(BufferedTransformation &bt) + {BERDecode(bt);} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const; + + // GeneratibleCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + +protected: + Integer m_p, m_q; +}; + +/// \brief EMSA5 padding method +/// \tparam T Mask Generation Function +/// \since Crypto++ 5.0 +template +class EMSA5Pad : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "EMSA5";} + + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const + { + CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(recoverableMessageLength); + CRYPTOPP_UNUSED(messageEmpty), CRYPTOPP_UNUSED(hashIdentifier); + SecByteBlock digest(hash.DigestSize()); + hash.Final(digest); + size_t representativeByteLength = BitsToBytes(representativeBitLength); + T mgf; + mgf.GenerateAndMask(hash, representative, representativeByteLength, digest, digest.size(), false); + if (representativeBitLength % 8 != 0) + representative[0] = (byte)Crop(representative[0], representativeBitLength % 8); + } +}; + +/// \brief EMSA5 padding method, for use with ESIGN +/// \since Crypto++ 5.0 +struct P1363_EMSA5 : public SignatureStandard +{ + typedef EMSA5Pad SignatureMessageEncodingMethod; +}; + +/// \brief ESIGN keys +/// \since Crypto++ 5.0 +struct ESIGN_Keys +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ESIGN";} + typedef ESIGNFunction PublicKey; + typedef InvertibleESIGNFunction PrivateKey; +}; + +/// \brief ESIGN signature scheme, IEEE P1363a +/// \tparam H HashTransformation derived class +/// \tparam STANDARD Signature encoding method +/// \since Crypto++ 5.0 +template +struct ESIGN : public TF_SS +{ +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/factory.h b/third_party/cryptoppwin/include/cryptopp/factory.h new file mode 100644 index 00000000..82dc5f58 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/factory.h @@ -0,0 +1,179 @@ +// factory.h - originally written and placed in the public domain by Wei Dai + +/// \file factory.h +/// \brief Classes and functions for registering and locating library objects + +#ifndef CRYPTOPP_OBJFACT_H +#define CRYPTOPP_OBJFACT_H + +#include "cryptlib.h" +#include "misc.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Object factory interface for registering objects +/// \tparam AbstractClass Base class interface of the object +template +class ObjectFactory +{ +public: + virtual ~ObjectFactory () {} + virtual AbstractClass * CreateObject() const =0; +}; + +/// \brief Object factory for registering objects +/// \tparam AbstractClass Base class interface of the object +/// \tparam ConcreteClass Class object +template +class DefaultObjectFactory : public ObjectFactory +{ +public: + AbstractClass * CreateObject() const + { + return new ConcreteClass; + } +}; + +/// \brief Object factory registry +/// \tparam AbstractClass Base class interface of the object +/// \tparam instance unique identifier +template +class ObjectFactoryRegistry +{ +public: + class FactoryNotFound : public Exception + { + public: + FactoryNotFound(const char *name) : Exception(OTHER_ERROR, std::string("ObjectFactoryRegistry: could not find factory for algorithm ") + name) {} + }; + + ~ObjectFactoryRegistry() + { + for (typename Map::iterator i = m_map.begin(); i != m_map.end(); ++i) + { + delete (ObjectFactory *)i->second; + i->second = NULLPTR; + } + } + + void RegisterFactory(const std::string &name, ObjectFactory *factory) + { + m_map[name] = factory; + } + + const ObjectFactory * GetFactory(const char *name) const + { + typename Map::const_iterator i = m_map.find(name); + return i == m_map.end() ? NULLPTR : (ObjectFactory *)i->second; + } + + AbstractClass *CreateObject(const char *name) const + { + const ObjectFactory *factory = GetFactory(name); + if (!factory) + throw FactoryNotFound(name); + return factory->CreateObject(); + } + + // Return a vector containing the factory names. This is easier than returning an iterator. + // from Andrew Pitonyak + std::vector GetFactoryNames() const + { + std::vector names; + typename Map::const_iterator iter; + for (iter = m_map.begin(); iter != m_map.end(); ++iter) + names.push_back(iter->first); + return names; + } + + CRYPTOPP_NOINLINE static ObjectFactoryRegistry & Registry(CRYPTOPP_NOINLINE_DOTDOTDOT); + +private: + // use void * instead of ObjectFactory * to save code size + typedef std::map Map; + Map m_map; +}; + +template +ObjectFactoryRegistry & ObjectFactoryRegistry::Registry(CRYPTOPP_NOINLINE_DOTDOTDOT) +{ + static ObjectFactoryRegistry s_registry; + return s_registry; +} + +/// \brief Object factory registry helper +/// \tparam AbstractClass Base class interface of the object +/// \tparam ConcreteClass Class object +/// \tparam instance unique identifier +template +struct RegisterDefaultFactoryFor +{ + RegisterDefaultFactoryFor(const char *name=NULLPTR) + { + // BCB2006 workaround + std::string n = name ? std::string(name) : std::string(ConcreteClass::StaticAlgorithmName()); + ObjectFactoryRegistry::Registry(). + RegisterFactory(n, new DefaultObjectFactory); + } +}; + +/// \fn RegisterAsymmetricCipherDefaultFactories +/// \brief Register asymmetric ciphers +/// \tparam SchemeClass interface of the object under a scheme +/// \details Schemes include asymmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// signature schemes (registers SchemeClass::Signer and SchemeClass::Verifier), +/// symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// authenticated symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), etc. +template +void RegisterAsymmetricCipherDefaultFactories(const char *name=NULLPTR) +{ + RegisterDefaultFactoryFor((const char *)name); + RegisterDefaultFactoryFor((const char *)name); +} + +/// \fn RegisterSignatureSchemeDefaultFactories +/// \brief Register signature schemes +/// \tparam SchemeClass interface of the object under a scheme +/// \details Schemes include asymmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// signature schemes (registers SchemeClass::Signer and SchemeClass::Verifier), +/// symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// authenticated symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), etc. +template +void RegisterSignatureSchemeDefaultFactories(const char *name=NULLPTR) +{ + RegisterDefaultFactoryFor((const char *)name); + RegisterDefaultFactoryFor((const char *)name); +} + +/// \fn RegisterSymmetricCipherDefaultFactories +/// \brief Register symmetric ciphers +/// \tparam SchemeClass interface of the object under a scheme +/// \details Schemes include asymmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// signature schemes (registers SchemeClass::Signer and SchemeClass::Verifier), +/// symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// authenticated symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), etc. +template +void RegisterSymmetricCipherDefaultFactories(const char *name=NULLPTR) +{ + RegisterDefaultFactoryFor((const char *)name); + RegisterDefaultFactoryFor((const char *)name); +} + +/// \fn RegisterAuthenticatedSymmetricCipherDefaultFactories +/// \brief Register authenticated symmetric ciphers +/// \tparam SchemeClass interface of the object under a scheme +/// \details Schemes include asymmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// signature schemes (registers SchemeClass::Signer and SchemeClass::Verifier), +/// symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), +/// authenticated symmetric ciphers (registers SchemeClass::Encryptor and SchemeClass::Decryptor), etc. +template +void RegisterAuthenticatedSymmetricCipherDefaultFactories(const char *name=NULLPTR) +{ + RegisterDefaultFactoryFor((const char *)name); + RegisterDefaultFactoryFor((const char *)name); +} + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/fhmqv.h b/third_party/cryptoppwin/include/cryptopp/fhmqv.h new file mode 100644 index 00000000..505d2861 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/fhmqv.h @@ -0,0 +1,408 @@ +// fhmqv.h - written and placed in the public domain by Jeffrey Walton, Ray Clayton and Uri Blumenthal +// Shamelessly based upon Wei Dai's MQV source files + +#ifndef CRYPTOPP_FHMQV_H +#define CRYPTOPP_FHMQV_H + +/// \file fhmqv.h +/// \brief Classes for Fully Hashed Menezes-Qu-Vanstone key agreement in GF(p) +/// \since Crypto++ 5.6.4 + +#include "gfpcrypt.h" +#include "algebra.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p) +/// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's +/// A Secure and Efficient Authenticated Diffie-Hellman Protocol. +/// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C. +/// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain +/// \since Crypto++ 5.6.4 +template +class FHMQV_Domain : public AuthenticatedKeyAgreementDomain +{ +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef FHMQV_Domain Domain; + + virtual ~FHMQV_Domain() {} + + /// \brief Construct a FHMQV domain + /// \param clientRole flag indicating initiator or recipient + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + FHMQV_Domain(bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) {} + + /// \brief Construct a FHMQV domain + /// \param params group parameters and options + /// \param clientRole flag indicating initiator or recipient + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + FHMQV_Domain(const GroupParameters ¶ms, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {} + + /// \brief Construct a FHMQV domain + /// \param bt BufferedTransformation with group parameters and options + /// \param clientRole flag indicating initiator or recipient + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + FHMQV_Domain(BufferedTransformation &bt, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.BERDecode(bt);} + + /// \brief Construct a FHMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1 is passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + FHMQV_Domain(T1 v1, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1);} + + /// \brief Construct a FHMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + FHMQV_Domain(T1 v1, T2 v2, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Construct a FHMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + FHMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Construct a FHMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 third parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + FHMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + +public: + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a const reference + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a non-const reference + GroupParameters & AccessGroupParameters() {return m_groupParameters;} + + /// \brief Retrieves the crypto parameters for this domain + /// \return the crypto parameters for this domain as a non-const reference + CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + /// \details The length is calculated using GetEncodedElementSize(false), + /// which means the element is encoded in a non-reversible format. A + /// non-reversible format means its a raw byte array, and it lacks presentation + /// format like an ASN.1 BIT_STRING or OCTET_STRING. + unsigned int AgreedValueLength() const + {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + + /// \brief Provides the size of the static private key + /// \return size of static private keys in this domain + /// \details The length is calculated using the byte count of the subgroup order. + unsigned int StaticPrivateKeyLength() const + {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + + /// \brief Provides the size of the static public key + /// \return size of static public keys in this domain + /// \details The length is calculated using GetEncodedElementSize(true), + /// which means the element is encoded in a reversible format. A reversible + /// format means it has a presentation format, and its an ANS.1 encoded element + /// or point. + unsigned int StaticPublicKeyLength() const + {return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + /// \brief Generate static private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \details The private key is a random scalar used as an exponent in the range + /// [1,MaxExponent()]. + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + } + + /// \brief Generate a static public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details The public key is an element or point on the curve, and its stored + /// in a revrsible format. A reversible format means it has a presentation + /// format, and its an ANS.1 encoded element or point. + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + /// \brief Provides the size of the ephemeral private key + /// \return size of ephemeral private keys in this domain + /// \details An ephemeral private key is a private key and public key. + /// The serialized size is different than a static private key. + unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();} + + /// \brief Provides the size of the ephemeral public key + /// \return size of ephemeral public keys in this domain + /// \details An ephemeral public key is a public key. + /// The serialized size is the same as a static public key. + unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();} + + /// \brief Generate ephemeral private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == EphemeralPrivateKeyLength() + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(rng, Integer::One(), params.GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength()); + } + + /// \brief Generate ephemeral public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == EphemeralPublicKeyLength() + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + std::memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength()); + } + + /// \brief Derive agreed value or shared secret + /// \param agreedValue the shared secret + /// \param staticPrivateKey your long term private key + /// \param ephemeralPrivateKey your ephemeral private key + /// \param staticOtherPublicKey couterparty's long term public key + /// \param ephemeralOtherPublicKey couterparty's ephemeral public key + /// \param validateStaticOtherPublicKey flag indicating validation + /// \return true upon success, false in case of failure + /// \details Agree() performs the authenticated key agreement. Agree() + /// derives a shared secret from your private keys and couterparty's + /// public keys. Each instance or run of the protocol should use a new + /// ephemeral key pair. + /// \details The other's ephemeral public key will always be validated at + /// Level 1 to ensure it is a point on the curve. + /// validateStaticOtherPublicKey determines how thoroughly other's + /// static public key is validated. If you have previously validated the + /// couterparty's static public key, then use + /// validateStaticOtherPublicKey=false to save time. + /// \pre COUNTOF(agreedValue) == AgreedValueLength() + /// \pre COUNTOF(staticPrivateKey) == StaticPrivateKeyLength() + /// \pre COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength() + /// \pre COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength() + /// \pre COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength() + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const + { + const byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR; + size_t xxs = 0, yys = 0, aas = 0, bbs = 0; + + // Depending on the role, this will hold either A's or B's static + // (long term) public key. AA or BB will then point into tt. + SecByteBlock tt(StaticPublicKeyLength()); + + try + { + this->GetMaterial().DoQuickSanityCheck(); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + + if(m_role == RoleServer) + { + Integer b(staticPrivateKey, StaticPrivateKeyLength()); + Element B = params.ExponentiateBase(b); + params.EncodeElement(true, B, tt); + + XX = ephemeralOtherPublicKey; + xxs = EphemeralPublicKeyLength(); + YY = ephemeralPrivateKey + StaticPrivateKeyLength(); + yys = EphemeralPublicKeyLength(); + AA = staticOtherPublicKey; + aas = StaticPublicKeyLength(); + BB = tt.BytePtr(); + bbs = tt.SizeInBytes(); + } + else + { + Integer a(staticPrivateKey, StaticPrivateKeyLength()); + Element A = params.ExponentiateBase(a); + params.EncodeElement(true, A, tt); + + XX = ephemeralPrivateKey + StaticPrivateKeyLength(); + xxs = EphemeralPublicKeyLength(); + YY = ephemeralOtherPublicKey; + yys = EphemeralPublicKeyLength(); + AA = tt.BytePtr(); + aas = tt.SizeInBytes(); + BB = staticOtherPublicKey; + bbs = StaticPublicKeyLength(); + } + + Element VV1 = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey); + Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, true); + + const Integer& q = params.GetSubgroupOrder(); + const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8); + SecByteBlock dd(len), ee(len); + + Hash(NULLPTR, XX, xxs, YY, yys, AA, aas, BB, bbs, dd.BytePtr(), dd.SizeInBytes()); + Integer d(dd.BytePtr(), dd.SizeInBytes()); + + Hash(NULLPTR, YY, yys, XX, xxs, AA, aas, BB, bbs, ee.BytePtr(), ee.SizeInBytes()); + Integer e(ee.BytePtr(), ee.SizeInBytes()); + + Element sigma; + if(m_role == RoleServer) + { + Integer y(ephemeralPrivateKey, StaticPrivateKeyLength()); + Integer b(staticPrivateKey, StaticPrivateKeyLength()); + Integer s_B = (y + e * b) % q; + + Element A = params.DecodeElement(AA, false); + Element X = params.DecodeElement(XX, false); + + Element t1 = params.ExponentiateElement(A, d); + Element t2 = m_groupParameters.MultiplyElements(X, t1); + + sigma = params.ExponentiateElement(t2, s_B); + } + else + { + Integer x(ephemeralPrivateKey, StaticPrivateKeyLength()); + Integer a(staticPrivateKey, StaticPrivateKeyLength()); + Integer s_A = (x + d * a) % q; + + Element B = params.DecodeElement(BB, false); + Element Y = params.DecodeElement(YY, false); + + Element t1 = params.ExponentiateElement(B, e); + Element t2 = m_groupParameters.MultiplyElements(Y, t1); + + sigma = params.ExponentiateElement(t2, s_A); + } + + Hash(&sigma, XX, xxs, YY, yys, AA, aas, BB, bbs, agreedValue, AgreedValueLength()); + } + catch (DL_BadElement &) + { + CRYPTOPP_ASSERT(0); + return false; + } + return true; + } + +protected: + + inline void Hash(const Element* sigma, + const byte* e1, size_t e1len, const byte* e2, size_t e2len, + const byte* s1, size_t s1len, const byte* s2, size_t s2len, + byte* digest, size_t dlen) const + { + HASH hash; + size_t idx = 0, req = dlen; + size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE); + + if(sigma) + { + //Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma); + //SecByteBlock sbb(x.MinEncodedSize()); + //x.Encode(sbb.BytePtr(), sbb.SizeInBytes()); + SecByteBlock sbb(GetAbstractGroupParameters().GetEncodedElementSize(false)); + GetAbstractGroupParameters().EncodeElement(false, *sigma, sbb); + hash.Update(sbb.BytePtr(), sbb.SizeInBytes()); + } + + hash.Update(e1, e1len); + hash.Update(e2, e2len); + hash.Update(s1, s1len); + hash.Update(s2, s2len); + + hash.TruncatedFinal(digest, blk); + req -= blk; + + // All this to catch tail bytes for large curves and small hashes + while(req != 0) + { + hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE); + + idx += (size_t)HASH::DIGESTSIZE; + blk = STDMIN(req, (size_t)HASH::DIGESTSIZE); + hash.TruncatedFinal(&digest[idx], blk); + + req -= blk; + } + } + +private: + + // The paper uses Initiator and Recipient - make it classical. + enum KeyAgreementRole { RoleServer = 1, RoleClient }; + + DL_GroupParameters & AccessAbstractGroupParameters() {return m_groupParameters;} + const DL_GroupParameters & GetAbstractGroupParameters() const{return m_groupParameters;} + + GroupParameters m_groupParameters; + KeyAgreementRole m_role; +}; + +/// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p) +/// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's +/// A Secure and Efficient Authenticated Diffie-Hellman Protocol. +/// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C. +/// \sa FHMQV, MQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain +/// \since Crypto++ 5.6.4 +typedef FHMQV_Domain FHMQV; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/files.h b/third_party/cryptoppwin/include/cryptopp/files.h new file mode 100644 index 00000000..c09da5a5 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/files.h @@ -0,0 +1,181 @@ +// files.h - originally written and placed in the public domain by Wei Dai + +/// \file files.h +/// \brief Classes providing file-based library services +/// \since Crypto++ 1.0 + +#ifndef CRYPTOPP_FILES_H +#define CRYPTOPP_FILES_H + +#include "cryptlib.h" +#include "filters.h" +#include "argnames.h" +#include "smartptr.h" + +#include +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Implementation of Store interface +/// \details file-based implementation of Store interface +class CRYPTOPP_DLL FileStore : public Store, private FilterPutSpaceHelper, public NotCopyable +{ +public: + /// \brief Exception thrown when file-based error is encountered + class Err : public Exception + { + public: + Err(const std::string &s) : Exception(IO_ERROR, s) {} + }; + /// \brief Exception thrown when file-based open error is encountered + class OpenErr : public Err {public: OpenErr(const std::string &filename) : Err("FileStore: error opening file for reading: " + filename) {}}; + /// \brief Exception thrown when file-based read error is encountered + class ReadErr : public Err {public: ReadErr() : Err("FileStore: error reading file") {}}; + + /// \brief Construct a FileStore + FileStore() : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0) {} + + /// \brief Construct a FileStore + /// \param in an existing stream + FileStore(std::istream &in) : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0) + {StoreInitialize(MakeParameters(Name::InputStreamPointer(), &in));} + + /// \brief Construct a FileStore + /// \param filename the narrow name of the file to open + FileStore(const char *filename) : m_stream(NULLPTR), m_space(NULLPTR), m_len(0), m_waiting(0) + {StoreInitialize(MakeParameters(Name::InputFileName(), filename ? filename : ""));} + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) || (CRYPTOPP_MSC_VERSION >= 1400) + /// \brief Construct a FileStore + /// \param filename the Unicode name of the file to open + /// \details On non-Windows OS, this function assumes that setlocale() has been called. + FileStore(const wchar_t *filename) + {StoreInitialize(MakeParameters(Name::InputFileNameWide(), filename));} +#endif + + /// \brief Retrieves the internal stream + /// \return the internal stream pointer + std::istream* GetStream() {return m_stream;} + + /// \brief Retrieves the internal stream + /// \return the internal stream pointer + const std::istream* GetStream() const {return m_stream;} + + /// \brief Provides the number of bytes ready for retrieval + /// \return the number of bytes ready for retrieval + /// \details All retrieval functions return the actual number of bytes retrieved, which is + /// the lesser of the request number and MaxRetrievable() + lword MaxRetrievable() const; + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + lword Skip(lword skipMax=ULONG_MAX); + +private: + void StoreInitialize(const NameValuePairs ¶meters); + + member_ptr m_file; + std::istream *m_stream; + byte *m_space; + size_t m_len; + bool m_waiting; +}; + +/// \brief Implementation of Store interface +/// \details file-based implementation of Store interface +class CRYPTOPP_DLL FileSource : public SourceTemplate +{ +public: + typedef FileStore::Err Err; + typedef FileStore::OpenErr OpenErr; + typedef FileStore::ReadErr ReadErr; + + /// \brief Construct a FileSource + FileSource(BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {} + + /// \brief Construct a FileSource + /// \param in an existing stream + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + FileSource(std::istream &in, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputStreamPointer(), &in));} + + /// \brief Construct a FileSource + /// \param filename the narrow name of the file to open + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + /// \param binary flag indicating if the file is binary + FileSource(const char *filename, bool pumpAll, BufferedTransformation *attachment = NULLPTR, bool binary=true) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputFileName(), filename)(Name::InputBinaryMode(), binary));} + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) || (CRYPTOPP_MSC_VERSION >= 1400) + /// \brief Construct a FileSource + /// \param filename the Unicode name of the file to open + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + /// \param binary flag indicating if the file is binary + /// \details On non-Windows OS, this function assumes that setlocale() has been called. + FileSource(const wchar_t *filename, bool pumpAll, BufferedTransformation *attachment = NULLPTR, bool binary=true) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters(Name::InputFileNameWide(), filename)(Name::InputBinaryMode(), binary));} +#endif + + /// \brief Retrieves the internal stream + /// \return the internal stream pointer + std::istream* GetStream() {return m_store.GetStream();} +}; + +/// \brief Implementation of Store interface +/// \details file-based implementation of Sink interface +class CRYPTOPP_DLL FileSink : public Sink, public NotCopyable +{ +public: + /// \brief Exception thrown when file-based error is encountered + class Err : public Exception + { + public: + Err(const std::string &s) : Exception(IO_ERROR, s) {} + }; + /// \brief Exception thrown when file-based open error is encountered + class OpenErr : public Err {public: OpenErr(const std::string &filename) : Err("FileSink: error opening file for writing: " + filename) {}}; + /// \brief Exception thrown when file-based write error is encountered + class WriteErr : public Err {public: WriteErr() : Err("FileSink: error writing file") {}}; + + /// \brief Construct a FileSink + FileSink() : m_stream(NULLPTR) {} + + /// \brief Construct a FileSink + /// \param out an existing stream + FileSink(std::ostream &out) + {IsolatedInitialize(MakeParameters(Name::OutputStreamPointer(), &out));} + + /// \brief Construct a FileSink + /// \param filename the narrow name of the file to open + /// \param binary flag indicating if the file is binary + FileSink(const char *filename, bool binary=true) + {IsolatedInitialize(MakeParameters(Name::OutputFileName(), filename)(Name::OutputBinaryMode(), binary));} + +#if defined(CRYPTOPP_UNIX_AVAILABLE) || (CRYPTOPP_MSC_VERSION >= 1400) + /// \brief Construct a FileSink + /// \param filename the Unicode name of the file to open + /// \details On non-Windows OS, this function assumes that setlocale() has been called. + FileSink(const wchar_t *filename, bool binary=true) + {IsolatedInitialize(MakeParameters(Name::OutputFileNameWide(), filename)(Name::OutputBinaryMode(), binary));} +#endif + + /// \brief Retrieves the internal stream + /// \return the internal stream pointer + std::ostream* GetStream() {return m_stream;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + bool IsolatedFlush(bool hardFlush, bool blocking); + +private: + member_ptr m_file; + std::ostream *m_stream; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/filters.h b/third_party/cryptoppwin/include/cryptopp/filters.h new file mode 100644 index 00000000..0de46c41 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/filters.h @@ -0,0 +1,1529 @@ +// filters.h - originally written and placed in the public domain by Wei Dai + +/// \file filters.h +/// \brief Implementation of BufferedTransformation's attachment interface. + +#ifndef CRYPTOPP_FILTERS_H +#define CRYPTOPP_FILTERS_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189 4231 4275 4514) +#endif + +#include "cryptlib.h" +#include "simple.h" +#include "secblock.h" +#include "misc.h" +#include "smartptr.h" +#include "queue.h" +#include "algparam.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Implementation of BufferedTransformation's attachment interface +/// \details Filter is a cornerstone of the Pipeline trinity. Data flows from +/// Sources, through Filters, and then terminates in Sinks. The difference +/// between a Source and Filter is a Source \a pumps data, while a Filter does +/// not. The difference between a Filter and a Sink is a Filter allows an +/// attached transformation, while a Sink does not. +/// \details See the discussion of BufferedTransformation in cryptlib.h for +/// more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Filter : public BufferedTransformation, public NotCopyable +{ +public: + virtual ~Filter() {} + + /// \name ATTACHMENT + //@{ + + /// \brief Construct a Filter + /// \param attachment an optional attached transformation + /// \details attachment can be NULL. + Filter(BufferedTransformation *attachment = NULLPTR); + + /// \brief Determine if attachable + /// \return true if the object allows attached transformations, false otherwise. + /// \note Source and Filter offer attached transformations; while Sink does not. + bool Attachable() {return true;} + + /// \brief Retrieve attached transformation + /// \return pointer to a BufferedTransformation if there is an attached transformation, NULL otherwise. + BufferedTransformation *AttachedTransformation(); + + /// \brief Retrieve attached transformation + /// \return pointer to a BufferedTransformation if there is an attached transformation, NULL otherwise. + const BufferedTransformation *AttachedTransformation() const; + + /// \brief Replace an attached transformation + /// \param newAttachment an optional attached transformation + /// \details newAttachment can be a single filter, a chain of filters or NULL. + /// Pass NULL to remove an existing BufferedTransformation or chain of filters + void Detach(BufferedTransformation *newAttachment = NULLPTR); + + //@} + + /// \name RETRIEVAL OF ONE MESSAGE + //@{ + + // BufferedTransformation in cryptlib.h + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + //@} + + /// \name SIGNALS + //@{ + + // BufferedTransformation in cryptlib.h + void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1); + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true); + bool MessageSeriesEnd(int propagation=-1, bool blocking=true); + + //@} + +protected: + virtual BufferedTransformation * NewDefaultAttachment() const; + void Insert(Filter *nextFilter); // insert filter after this one + + virtual bool ShouldPropagateMessageEnd() const {return true;} + virtual bool ShouldPropagateMessageSeriesEnd() const {return true;} + + void PropagateInitialize(const NameValuePairs ¶meters, int propagation); + + /// \brief Forward processed data on to attached transformation + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + size_t Output(int outputSite, const byte *inString, size_t length, int messageEnd, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + + /// \brief Output multiple bytes that may be modified by callee. + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + size_t OutputModifiable(int outputSite, byte *inString, size_t length, int messageEnd, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + + /// \brief Signals the end of messages to the object + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param propagation the number of attached transformations the MessageEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \return true is the MessageEnd signal was successful, false otherwise. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + bool OutputMessageEnd(int outputSite, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + + /// \brief Flush buffered input and/or output, with signal propagation + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the Flush() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \return true is the Flush signal was successful, false otherwise. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note Hard flushes must be used with care. It means try to process and output everything, even if + /// there may not be enough data to complete the action. For example, hard flushing a HexDecoder + /// would cause an error if you do it after inputing an odd number of hex encoded characters. + /// \note For some types of filters, like ZlibDecompressor, hard flushes can only + /// be done at "synchronization points". These synchronization points are positions in the data + /// stream that are created by hard flushes on the corresponding reverse filters, in this + /// example ZlibCompressor. This is useful when zlib compressed data is moved across a + /// network in packets and compression state is preserved across packets, as in the SSH2 protocol. + bool OutputFlush(int outputSite, bool hardFlush, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + + /// \brief Marks the end of a series of messages, with signal propagation + /// \param outputSite unknown, system crash between keyboard and chair... + /// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \param channel the channel to process the data + /// \return true is the MessageEnd signal was successful, false otherwise. + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + bool OutputMessageSeriesEnd(int outputSite, int propagation, bool blocking, const std::string &channel=DEFAULT_CHANNEL); + +private: + member_ptr m_attachment; + +protected: + size_t m_inputPosition; + int m_continueAt; +}; + +/// \brief Create a working space in a BufferedTransformation +struct CRYPTOPP_DLL FilterPutSpaceHelper +{ + virtual ~FilterPutSpaceHelper() {} + + /// \brief Create a working space in a BufferedTransformation + /// \param target BufferedTransformation for the working space + /// \param channel channel for the working space + /// \param minSize minimum size of the allocation, in bytes + /// \param desiredSize preferred size of the allocation, in bytes + /// \param bufferSize actual size of the allocation, in bytes + /// \pre desiredSize >= minSize and bufferSize >= minSize. + /// \details bufferSize is an IN and OUT parameter. If HelpCreatePutSpace() returns a non-NULL value, then + /// bufferSize is valid and provides the size of the working space created for the caller. + /// \details Internally, HelpCreatePutSpace() calls \ref BufferedTransformation::ChannelCreatePutSpace + /// "ChannelCreatePutSpace()" using desiredSize. If the target returns desiredSize with a size less + /// than minSize (i.e., the request could not be fulfilled), then an internal SecByteBlock + /// called m_tempSpace is resized and used for the caller. + byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t desiredSize, size_t &bufferSize) + { + CRYPTOPP_ASSERT(desiredSize >= minSize && bufferSize >= minSize); + if (m_tempSpace.size() < minSize) + { + byte *result = target.ChannelCreatePutSpace(channel, desiredSize); + if (desiredSize >= minSize) + { + bufferSize = desiredSize; + return result; + } + m_tempSpace.New(bufferSize); + } + + bufferSize = m_tempSpace.size(); + return m_tempSpace.begin(); + } + + /// \brief Create a working space in a BufferedTransformation + /// \param target the BufferedTransformation for the working space + /// \param channel channel for the working space + /// \param minSize minimum size of the allocation, in bytes + /// \return pointer to the created space + /// \details Internally, the overload calls HelpCreatePutSpace() using minSize for missing arguments. + /// \details The filter will delete the space. The caller does not need to delete the space. + byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize) + {return HelpCreatePutSpace(target, channel, minSize, minSize, minSize);} + + /// \brief Create a working space in a BufferedTransformation + /// \param target the BufferedTransformation for the working space + /// \param channel channel for the working space + /// \param minSize minimum size of the allocation, in bytes + /// \param bufferSize the actual size of the allocation, in bytes + /// \details Internally, the overload calls HelpCreatePutSpace() using minSize for missing arguments. + /// \details The filter will delete the space. The caller does not need to delete the space. + byte *HelpCreatePutSpace(BufferedTransformation &target, const std::string &channel, size_t minSize, size_t bufferSize) + {return HelpCreatePutSpace(target, channel, minSize, minSize, bufferSize);} + + /// \brief Temporary working space + SecByteBlock m_tempSpace; +}; + +/// \brief Measure how many bytes and messages pass through the filter +/// \details measure how many bytes and messages pass through the filter. The filter also serves as valve by +/// maintaining a list of ranges to skip during processing. +class CRYPTOPP_DLL MeterFilter : public Bufferless +{ +public: + virtual ~MeterFilter() {} + + /// \brief Construct a MeterFilter + /// \param attachment an optional attached transformation + /// \param transparent flag indicating if the filter should function transparently + /// \details attachment can be NULL. The filter is transparent by default. If the filter is + /// transparent, then PutMaybeModifiable() does not process a request and always returns 0. + MeterFilter(BufferedTransformation *attachment=NULLPTR, bool transparent=true) + : m_transparent(transparent), m_currentMessageBytes(0), m_totalBytes(0) + , m_currentSeriesMessages(0), m_totalMessages(0), m_totalMessageSeries(0) + , m_begin(NULLPTR), m_length(0) {Detach(attachment); ResetMeter();} + + /// \brief Set or change the transparent mode of this object + /// \param transparent the new transparent mode + void SetTransparent(bool transparent) {m_transparent = transparent;} + + /// \brief Adds a range to skip during processing + /// \param message the message to apply the range + /// \param position the 0-based index in the current stream + /// \param size the length of the range + /// \param sortNow flag indicating whether the range should be sorted + /// \details Internally, MeterFilter maitains a deque of ranges to skip. As messages are processed, + /// ranges of bytes are skipped according to the list of ranges. + void AddRangeToSkip(unsigned int message, lword position, lword size, bool sortNow = true); + + /// \brief Resets the meter + /// \details ResetMeter() reinitializes the meter by setting counters to 0 and removing previous + /// skip ranges. + void ResetMeter(); + + // BufferedTransformation in cryptlib.h + void IsolatedInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); ResetMeter();} + + /// \brief Number of bytes in the current message + /// \return the number of bytes in the current message + lword GetCurrentMessageBytes() const {return m_currentMessageBytes;} + + /// \brief Number of bytes processed by the filter + /// \return the number of bytes processed by the filter + lword GetTotalBytes() const {return m_totalBytes;} + + /// \brief Message number in the series + /// \return the message number in the series + unsigned int GetCurrentSeriesMessages() const {return m_currentSeriesMessages;} + + /// \brief Number of messages in the message series + /// \return the number of messages in the message series + unsigned int GetTotalMessages() const {return m_totalMessages;} + + /// \brief Number of messages processed by the filter + /// \return the number of messages processed by the filter + unsigned int GetTotalMessageSeries() const {return m_totalMessageSeries;} + + // BufferedTransformation in cryptlib.h + byte * CreatePutSpace(size_t &size) {return AttachedTransformation()->CreatePutSpace(size);} + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking); + bool IsolatedMessageSeriesEnd(bool blocking); + +private: + size_t PutMaybeModifiable(byte *inString, size_t length, int messageEnd, bool blocking, bool modifiable); + bool ShouldPropagateMessageEnd() const {return m_transparent;} + bool ShouldPropagateMessageSeriesEnd() const {return m_transparent;} + + struct MessageRange + { + inline bool operator<(const MessageRange &b) const // BCB2006 workaround: this has to be a member function + {return message < b.message || (message == b.message && position < b.position);} + unsigned int message; lword position; lword size; + }; + + bool m_transparent; + lword m_currentMessageBytes, m_totalBytes; + unsigned int m_currentSeriesMessages, m_totalMessages, m_totalMessageSeries; + std::deque m_rangesToSkip; + byte *m_begin; + size_t m_length; +}; + +/// \brief A transparent MeterFilter +/// \sa MeterFilter, OpaqueFilter +class CRYPTOPP_DLL TransparentFilter : public MeterFilter +{ +public: + /// \brief Construct a TransparentFilter + /// \param attachment an optional attached transformation + TransparentFilter(BufferedTransformation *attachment=NULLPTR) : MeterFilter(attachment, true) {} +}; + +/// \brief A non-transparent MeterFilter +/// \sa MeterFilter, TransparentFilter +class CRYPTOPP_DLL OpaqueFilter : public MeterFilter +{ +public: + /// \brief Construct an OpaqueFilter + /// \param attachment an optional attached transformation + OpaqueFilter(BufferedTransformation *attachment=NULLPTR) : MeterFilter(attachment, false) {} +}; + +/// \brief Divides an input stream into discrete blocks +/// \details FilterWithBufferedInput divides the input stream into a first block, a number of +/// middle blocks, and a last block. First and last blocks are optional, and middle blocks may +/// be a stream instead (i.e. blockSize == 1). +/// \sa AuthenticatedEncryptionFilter, AuthenticatedDecryptionFilter, HashVerificationFilter, +/// SignatureVerificationFilter, StreamTransformationFilter +class CRYPTOPP_DLL FilterWithBufferedInput : public Filter +{ +public: + virtual ~FilterWithBufferedInput() {} + + /// \brief Construct a FilterWithBufferedInput with an attached transformation + /// \param attachment an attached transformation + FilterWithBufferedInput(BufferedTransformation *attachment); + + /// \brief Construct a FilterWithBufferedInput with an attached transformation + /// \param firstSize the size of the first block + /// \param blockSize the size of middle blocks + /// \param lastSize the size of the last block + /// \param attachment an attached transformation + /// \details firstSize and lastSize may be 0. blockSize must be at least 1. + FilterWithBufferedInput(size_t firstSize, size_t blockSize, size_t lastSize, BufferedTransformation *attachment); + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + { + return PutMaybeModifiable(const_cast(inString), length, messageEnd, blocking, false); + } + + size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking) + { + return PutMaybeModifiable(inString, length, messageEnd, blocking, true); + } + + /// \brief Flushes data buffered by this object, without signal propagation + /// \param hardFlush indicates whether all data should be flushed + /// \param blocking specifies whether the object should block when processing input + /// \return true if the Flush was successful, false otherwise + /// \details IsolatedFlush() calls ForceNextPut() if hardFlush is true + /// \note hardFlush must be used with care + bool IsolatedFlush(bool hardFlush, bool blocking); + + /// \brief Flushes data buffered by this object + /// \details The input buffer may contain more than blockSize bytes if lastSize != 0. + /// ForceNextPut() forces a call to NextPut() if this is the case. + void ForceNextPut(); + +protected: + virtual bool DidFirstPut() const {return m_firstInputDone;} + virtual size_t GetFirstPutSize() const {return m_firstSize;} + virtual size_t GetBlockPutSize() const {return m_blockSize;} + virtual size_t GetLastPutSize() const {return m_lastSize;} + + virtual void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize) + {CRYPTOPP_UNUSED(parameters); CRYPTOPP_UNUSED(firstSize); CRYPTOPP_UNUSED(blockSize); CRYPTOPP_UNUSED(lastSize); InitializeDerived(parameters);} + virtual void InitializeDerived(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters);} + // FirstPut() is called if (firstSize != 0 and totalLength >= firstSize) + // or (firstSize == 0 and (totalLength > 0 or a MessageEnd() is received)). + // inString is m_firstSize in length. + virtual void FirstPut(const byte *inString) =0; + // NextPut() is called if totalLength >= firstSize+blockSize+lastSize + virtual void NextPutSingle(const byte *inString) + {CRYPTOPP_UNUSED(inString); CRYPTOPP_ASSERT(false);} + // Same as NextPut() except length can be a multiple of blockSize + // Either NextPut() or NextPutMultiple() must be overridden + virtual void NextPutMultiple(const byte *inString, size_t length); + // Same as NextPutMultiple(), but inString can be modified + virtual void NextPutModifiable(byte *inString, size_t length) + {NextPutMultiple(inString, length);} + /// \brief Input the last block of data + /// \param inString the input byte buffer + /// \param length the size of the input buffer, in bytes + /// \details LastPut() processes the last block of data and signals attached filters to do the same. + /// LastPut() is always called. The pseudo algorithm for the logic is: + ///
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// 
+ virtual void LastPut(const byte *inString, size_t length) =0; + virtual void FlushDerived() {} + +protected: + size_t PutMaybeModifiable(byte *begin, size_t length, int messageEnd, bool blocking, bool modifiable); + void NextPutMaybeModifiable(byte *inString, size_t length, bool modifiable) + { + if (modifiable) NextPutModifiable(inString, length); + else NextPutMultiple(inString, length); + } + + // This function should no longer be used, put this here to cause a compiler error + // if someone tries to override NextPut(). + virtual int NextPut(const byte *inString, size_t length) + {CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_ASSERT(false); return 0;} + + class BlockQueue + { + public: + void ResetQueue(size_t blockSize, size_t maxBlocks); + byte *GetBlock(); + byte *GetContigousBlocks(size_t &numberOfBytes); + size_t GetAll(byte *outString); + void Put(const byte *inString, size_t length); + size_t CurrentSize() const {return m_size;} + size_t MaxSize() const {return m_buffer.size();} + + private: + SecByteBlock m_buffer; + size_t m_blockSize, m_maxBlocks, m_size; + byte *m_begin; + }; + + size_t m_firstSize, m_blockSize, m_lastSize; + bool m_firstInputDone; + BlockQueue m_queue; +}; + +/// \brief A filter that buffers input using a ByteQueue +/// \details FilterWithInputQueue will buffer input using a ByteQueue. When the filter receives +/// a \ref BufferedTransformation::MessageEnd() "MessageEnd()" signal it will pass the data +/// on to its attached transformation. +class CRYPTOPP_DLL FilterWithInputQueue : public Filter +{ +public: + virtual ~FilterWithInputQueue() {} + + /// \brief Construct a FilterWithInputQueue + /// \param attachment an optional attached transformation + FilterWithInputQueue(BufferedTransformation *attachment=NULLPTR) : Filter(attachment) {} + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + { + if (!blocking) + throw BlockingInputOnly("FilterWithInputQueue"); + + m_inQueue.Put(inString, length); + if (messageEnd) + { + IsolatedMessageEnd(blocking); + Output(0, NULLPTR, 0, messageEnd, blocking); + } + return 0; + } + +protected: + virtual bool IsolatedMessageEnd(bool blocking) =0; + void IsolatedInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); m_inQueue.Clear();} + + ByteQueue m_inQueue; +}; + +/// \struct BlockPaddingSchemeDef +/// \brief Padding schemes used for block ciphers +/// \since Crypto++ 5.0 +struct BlockPaddingSchemeDef +{ + /// \enum BlockPaddingScheme + /// \brief Padding schemes used for block ciphers. + /// \details DEFAULT_PADDING means PKCS_PADDING if cipher.MandatoryBlockSize() > 1 && + /// cipher.MinLastBlockSize() == 0, which holds for ECB or CBC mode. Otherwise, + /// NO_PADDING for modes like OFB, CFB, CTR, CBC-CTS. + /// \sa Block Cipher Padding for + /// additional details. + /// \since Crypto++ 5.0 + enum BlockPaddingScheme { + /// \brief No padding added to a block + /// \since Crypto++ 5.0 + NO_PADDING, + /// \brief 0's padding added to a block + /// \since Crypto++ 5.0 + ZEROS_PADDING, + /// \brief PKCS padding added to a block + /// \since Crypto++ 5.0 + PKCS_PADDING, + /// \brief 1 and 0's padding added to a block + /// \since Crypto++ 5.0 + ONE_AND_ZEROS_PADDING, + /// \brief W3C padding added to a block + /// \sa XML + /// Encryption Syntax and Processing + /// \since Crypto++ 6.0 + W3C_PADDING, + /// \brief Default padding scheme + /// \since Crypto++ 5.0 + DEFAULT_PADDING + }; +}; + +/// \brief Filter wrapper for StreamTransformation +/// \details StreamTransformationFilter() is a filter wrapper for StreamTransformation(). It is used when +/// pipelining data for stream ciphers and confidentiality-only block ciphers. The filter will optionally +/// handle padding and unpadding when needed. If you are using an authenticated encryption mode of operation, +/// then use AuthenticatedEncryptionFilter() and AuthenticatedDecryptionFilter() +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL StreamTransformationFilter : public FilterWithBufferedInput, public BlockPaddingSchemeDef, private FilterPutSpaceHelper +{ +public: + virtual ~StreamTransformationFilter() {} + + /// \brief Construct a StreamTransformationFilter + /// \param c reference to a StreamTransformation + /// \param attachment an optional attached transformation + /// \param padding the \ref BlockPaddingSchemeDef "padding scheme" + /// \details This constructor creates a StreamTransformationFilter() for stream ciphers and + /// confidentiality-only block cipher modes of operation. If you are using an authenticated + /// encryption mode of operation, then use either AuthenticatedEncryptionFilter() or + /// AuthenticatedDecryptionFilter(). + /// \sa AuthenticatedEncryptionFilter() and AuthenticatedDecryptionFilter() + StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment = NULLPTR, BlockPaddingScheme padding = DEFAULT_PADDING); + + std::string AlgorithmName() const {return m_cipher.AlgorithmName();} + +protected: + + friend class AuthenticatedEncryptionFilter; + friend class AuthenticatedDecryptionFilter; + + /// \brief Construct a StreamTransformationFilter + /// \param c reference to a StreamTransformation + /// \param attachment an optional attached transformation + /// \param padding the \ref BlockPaddingSchemeDef "padding scheme" + /// \param authenticated flag indicating whether the filter should allow authenticated encryption schemes + /// \details This constructor is used for authenticated encryption mode of operation and by + /// AuthenticatedEncryptionFilter() and AuthenticatedDecryptionFilter(). + StreamTransformationFilter(StreamTransformation &c, BufferedTransformation *attachment, BlockPaddingScheme padding, bool authenticated); + + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, size_t length); + void NextPutModifiable(byte *inString, size_t length); + void LastPut(const byte *inString, size_t length); + + static size_t LastBlockSize(StreamTransformation &c, BlockPaddingScheme padding); + + StreamTransformation &m_cipher; + BlockPaddingScheme m_padding; + unsigned int m_mandatoryBlockSize; + unsigned int m_optimalBufferSize; + unsigned int m_reservedBufferSize; + bool m_isSpecial; +}; + +/// \brief Filter wrapper for HashTransformation +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL HashFilter : public Bufferless, private FilterPutSpaceHelper +{ +public: + virtual ~HashFilter() {} + + /// \brief Construct a HashFilter + /// \param hm reference to a HashTransformation + /// \param attachment an optional attached transformation + /// \param putMessage flag indicating whether the original message should be passed to an attached transformation + /// \param truncatedDigestSize the size of the digest + /// \param messagePutChannel the channel on which the message should be output + /// \param hashPutChannel the channel on which the digest should be output + HashFilter(HashTransformation &hm, BufferedTransformation *attachment = NULLPTR, bool putMessage=false, int truncatedDigestSize=-1, const std::string &messagePutChannel=DEFAULT_CHANNEL, const std::string &hashPutChannel=DEFAULT_CHANNEL); + + std::string AlgorithmName() const {return m_hashModule.AlgorithmName();} + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + byte * CreatePutSpace(size_t &size) {return m_hashModule.CreateUpdateSpace(size);} + +private: + HashTransformation &m_hashModule; + bool m_putMessage; + unsigned int m_digestSize; + byte *m_space; + std::string m_messagePutChannel, m_hashPutChannel; +}; + +/// \brief Filter wrapper for HashTransformation +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL HashVerificationFilter : public FilterWithBufferedInput +{ +public: + virtual ~HashVerificationFilter() {} + + /// \brief Exception thrown when a data integrity check failure is encountered + class HashVerificationFailed : public Exception + { + public: + HashVerificationFailed() + : Exception(DATA_INTEGRITY_CHECK_FAILED, "HashVerificationFilter: message hash or MAC not valid") {} + }; + + /// \enum Flags + /// \brief Flags controlling filter behavior. + /// \details The flags are a bitmask and can be OR'd together. + enum Flags { + /// \brief The hash is at the end of the message (i.e., concatenation of message+hash) + HASH_AT_END=0, + /// \brief The hash is at the beginning of the message (i.e., concatenation of hash+message) + HASH_AT_BEGIN=1, + /// \brief The message should be passed to an attached transformation + PUT_MESSAGE=2, + /// \brief The hash should be passed to an attached transformation + PUT_HASH=4, + /// \brief The result of the verification should be passed to an attached transformation + PUT_RESULT=8, + /// \brief The filter should throw a HashVerificationFailed if a failure is encountered + THROW_EXCEPTION=16, + /// \brief Default flags using HASH_AT_BEGIN and PUT_RESULT + DEFAULT_FLAGS = HASH_AT_BEGIN | PUT_RESULT + }; + + /// \brief Construct a HashVerificationFilter + /// \param hm reference to a HashTransformation + /// \param attachment an optional attached transformation + /// \param flags flags indicating behaviors for the filter + /// \param truncatedDigestSize the size of the digest + /// \details truncatedDigestSize = -1 indicates \ref HashTransformation::DigestSize() "DigestSize" should be used. + HashVerificationFilter(HashTransformation &hm, BufferedTransformation *attachment = NULLPTR, word32 flags = DEFAULT_FLAGS, int truncatedDigestSize=-1); + + std::string AlgorithmName() const {return m_hashModule.AlgorithmName();} + bool GetLastResult() const {return m_verified;} + +protected: + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, size_t length); + void LastPut(const byte *inString, size_t length); + +private: + friend class AuthenticatedDecryptionFilter; + + HashTransformation &m_hashModule; + word32 m_flags; + unsigned int m_digestSize; + bool m_verified; + SecByteBlock m_expectedHash; +}; + +/// \brief Filter wrapper for encrypting with AuthenticatedSymmetricCipher +/// \details AuthenticatedEncryptionFilter() is a wrapper for encrypting with +/// AuthenticatedSymmetricCipher(), optionally handling padding/unpadding when needed. +/// \details AuthenticatedDecryptionFilter() for Crypto++ 8.2 and earlier +/// had a bug where a FileSource() would cause an exception, but a StringSource() +/// was OK. Also see Issue 817 and Commit ff110c6e183e. +/// \sa AuthenticatedSymmetricCipher, AuthenticatedDecryptionFilter, EAX, CCM, GCM, +/// and AadSource on the +/// Crypto++ wiki. +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL AuthenticatedEncryptionFilter : public StreamTransformationFilter +{ +public: + virtual ~AuthenticatedEncryptionFilter() {} + + /// \brief Construct a AuthenticatedEncryptionFilter + /// \param c reference to a AuthenticatedSymmetricCipher + /// \param attachment an optional attached transformation + /// \param putAAD flag indicating whether the AAD should be passed to an attached transformation + /// \param truncatedDigestSize the size of the digest + /// \param macChannel the channel on which the MAC should be output + /// \param padding the \ref BlockPaddingSchemeDef "padding scheme" + /// \details truncatedDigestSize = -1 indicates \ref HashTransformation::DigestSize() "DigestSize" should be used. + /// \since Crypto++ 5.6.0 + AuthenticatedEncryptionFilter(AuthenticatedSymmetricCipher &c, BufferedTransformation *attachment = NULLPTR, bool putAAD=false, int truncatedDigestSize=-1, const std::string &macChannel=DEFAULT_CHANNEL, BlockPaddingScheme padding = DEFAULT_PADDING); + + void IsolatedInitialize(const NameValuePairs ¶meters); + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size); + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking); + + /// \brief Input the last block of data + /// \param inString the input byte buffer + /// \param length the size of the input buffer, in bytes + /// \details LastPut() processes the last block of data and signals attached filters to do the same. + /// LastPut() is always called. The pseudo algorithm for the logic is: + ///
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// 
+ void LastPut(const byte *inString, size_t length); + +protected: + HashFilter m_hf; +}; + +/// \brief Filter wrapper for decrypting with AuthenticatedSymmetricCipher +/// \details AuthenticatedDecryptionFilter() is a wrapper for decrypting with +/// AuthenticatedSymmetricCipher(), optionally handling padding/unpadding when +/// needed. +/// \details AuthenticatedDecryptionFilter() for Crypto++ 8.2 and earlier +/// had a bug where a FileSource() would cause an exception, but a StringSource() +/// was OK. Also see Issue 817 and Commit ff110c6e183e. +/// \sa AuthenticatedSymmetricCipher, AuthenticatedEncryptionFilter, EAX, CCM, GCM, +/// and AadSource on the +/// Crypto++ wiki. +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL AuthenticatedDecryptionFilter : public FilterWithBufferedInput, public BlockPaddingSchemeDef +{ +public: + /// \enum Flags + /// \brief Flags controlling filter behavior. + /// \details The flags are a bitmask and can be OR'd together. + enum Flags { + /// \brief The MAC is at the end of the message (i.e., concatenation of message+mac) + MAC_AT_END=0, + /// \brief The MAC is at the beginning of the message (i.e., concatenation of mac+message) + MAC_AT_BEGIN=1, + /// \brief The filter should throw a HashVerificationFailed if a failure is encountered + THROW_EXCEPTION=16, + /// \brief Default flags using THROW_EXCEPTION + DEFAULT_FLAGS = THROW_EXCEPTION + }; + + virtual ~AuthenticatedDecryptionFilter() {} + + /// \brief Construct a AuthenticatedDecryptionFilter + /// \param c reference to a AuthenticatedSymmetricCipher + /// \param attachment an optional attached transformation + /// \param flags flags indicating behaviors for the filter + /// \param truncatedDigestSize the size of the digest + /// \param padding the \ref BlockPaddingSchemeDef "padding scheme" + /// \details Additional authenticated data should be given in channel "AAD". + /// \details truncatedDigestSize = -1 indicates \ref HashTransformation::DigestSize() "DigestSize" should be used. + /// \since Crypto++ 5.6.0 + AuthenticatedDecryptionFilter(AuthenticatedSymmetricCipher &c, BufferedTransformation *attachment = NULLPTR, word32 flags = DEFAULT_FLAGS, int truncatedDigestSize=-1, BlockPaddingScheme padding = DEFAULT_PADDING); + + std::string AlgorithmName() const {return m_hashVerifier.AlgorithmName();} + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size); + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking); + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking) + { return ChannelPut2(channel, begin, length, messageEnd, blocking); } + /// \brief Get verifier result + /// \return true if the digest on the previosus message was valid, false otherwise + bool GetLastResult() const {return m_hashVerifier.GetLastResult();} + +protected: + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, size_t length); + + /// \brief Input the last block of data + /// \param inString the input byte buffer + /// \param length the size of the input buffer, in bytes + /// \details LastPut() processes the last block of data and signals attached filters to do the same. + /// LastPut() is always called. The pseudo algorithm for the logic is: + ///
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// 
+ void LastPut(const byte *inString, size_t length); + + HashVerificationFilter m_hashVerifier; + StreamTransformationFilter m_streamFilter; +}; + +/// \brief Filter wrapper for PK_Signer +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL SignerFilter : public Unflushable +{ +public: + virtual ~SignerFilter() {} + + /// \brief Construct a SignerFilter + /// \param rng a RandomNumberGenerator derived class + /// \param signer a PK_Signer derived class + /// \param attachment an optional attached transformation + /// \param putMessage flag indicating whether the original message should be passed to an attached transformation + SignerFilter(RandomNumberGenerator &rng, const PK_Signer &signer, BufferedTransformation *attachment = NULLPTR, bool putMessage=false) + : m_rng(rng), m_signer(signer), m_messageAccumulator(signer.NewSignatureAccumulator(rng)), m_putMessage(putMessage) {Detach(attachment);} + + std::string AlgorithmName() const {return m_signer.AlgorithmName();} + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + +private: + RandomNumberGenerator &m_rng; + const PK_Signer &m_signer; + member_ptr m_messageAccumulator; + bool m_putMessage; + SecByteBlock m_buf; +}; + +/// \brief Filter wrapper for PK_Verifier +/// \details This filter was formerly named VerifierFilter. The name changed at Crypto++ 5.0. +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL SignatureVerificationFilter : public FilterWithBufferedInput +{ +public: + /// \brief Exception thrown when an invalid signature is encountered + class SignatureVerificationFailed : public Exception + { + public: + SignatureVerificationFailed() + : Exception(DATA_INTEGRITY_CHECK_FAILED, "VerifierFilter: digital signature not valid") {} + }; + + /// \enum Flags + /// \brief Flags controlling filter behavior. + /// \details The flags are a bitmask and can be OR'd together. + enum Flags { + /// \brief The signature is at the end of the message (i.e., concatenation of message+signature) + SIGNATURE_AT_END=0, + /// \brief The signature is at the beginning of the message (i.e., concatenation of signature+message) + SIGNATURE_AT_BEGIN=1, + /// \brief The message should be passed to an attached transformation + PUT_MESSAGE=2, + /// \brief The signature should be passed to an attached transformation + PUT_SIGNATURE=4, + /// \brief The result of the verification should be passed to an attached transformation + PUT_RESULT=8, + /// \brief The filter should throw a HashVerificationFailed if a failure is encountered + THROW_EXCEPTION=16, + /// \brief Default flags using SIGNATURE_AT_BEGIN and PUT_RESULT + DEFAULT_FLAGS = SIGNATURE_AT_BEGIN | PUT_RESULT + }; + + virtual ~SignatureVerificationFilter() {} + + /// \brief Construct a SignatureVerificationFilter + /// \param verifier a PK_Verifier derived class + /// \param attachment an optional attached transformation + /// \param flags flags indicating behaviors for the filter + SignatureVerificationFilter(const PK_Verifier &verifier, BufferedTransformation *attachment = NULLPTR, word32 flags = DEFAULT_FLAGS); + + std::string AlgorithmName() const {return m_verifier.AlgorithmName();} + + /// \brief Retrieves the result of the last verification + /// \return true if the signature on the previosus message was valid, false otherwise + bool GetLastResult() const {return m_verified;} + +protected: + void InitializeDerivedAndReturnNewSizes(const NameValuePairs ¶meters, size_t &firstSize, size_t &blockSize, size_t &lastSize); + void FirstPut(const byte *inString); + void NextPutMultiple(const byte *inString, size_t length); + void LastPut(const byte *inString, size_t length); + +private: + const PK_Verifier &m_verifier; + member_ptr m_messageAccumulator; + word32 m_flags; + SecByteBlock m_signature; + bool m_verified; +}; + +/// \brief Redirect input to another BufferedTransformation without owning it +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL Redirector : public CustomSignalPropagation +{ +public: + /// \enum Behavior + /// \brief Controls signal propagation behavior + enum Behavior + { + /// \brief Pass data only + DATA_ONLY = 0x00, + /// \brief Pass signals + PASS_SIGNALS = 0x01, + /// \brief Pass wait events + PASS_WAIT_OBJECTS = 0x02, + /// \brief Pass everything + /// \details PASS_EVERYTHING is default + PASS_EVERYTHING = PASS_SIGNALS | PASS_WAIT_OBJECTS + }; + + virtual ~Redirector() {} + + /// \brief Construct a Redirector + Redirector() : m_target(NULLPTR), m_behavior(PASS_EVERYTHING) {} + + /// \brief Construct a Redirector + /// \param target the destination BufferedTransformation + /// \param behavior Behavior "flags" specifying signal propagation + Redirector(BufferedTransformation &target, Behavior behavior=PASS_EVERYTHING) + : m_target(&target), m_behavior(behavior) {} + + /// \brief Redirect input to another BufferedTransformation + /// \param target the destination BufferedTransformation + void Redirect(BufferedTransformation &target) {m_target = ⌖} + /// \brief Stop redirecting input + void StopRedirection() {m_target = NULLPTR;} + + /// \brief Retrieve signal propagation behavior + /// \return the current signal propagation behavior + Behavior GetBehavior() {return static_cast(m_behavior);} + /// \brief Set signal propagation behavior + /// \param behavior the new signal propagation behavior + void SetBehavior(Behavior behavior) {m_behavior=behavior;} + /// \brief Retrieve signal propagation behavior + /// \return true if the Redirector passes signals, false otherwise. + bool GetPassSignals() const {return (m_behavior & PASS_SIGNALS) != 0;} + /// \brief Set signal propagation behavior + /// \param pass flag indicating if the Redirector should pass signals + void SetPassSignals(bool pass) { if (pass) m_behavior |= PASS_SIGNALS; else m_behavior &= ~static_cast(PASS_SIGNALS); } + /// \brief Retrieve signal propagation behavior + /// \return true if the Redirector passes wait objects, false otherwise. + bool GetPassWaitObjects() const {return (m_behavior & PASS_WAIT_OBJECTS) != 0;} + /// \brief Set signal propagation behavior + /// \param pass flag indicating if the Redirector should pass wait objects + void SetPassWaitObjects(bool pass) { if (pass) m_behavior |= PASS_WAIT_OBJECTS; else m_behavior &= ~static_cast(PASS_WAIT_OBJECTS); } + + bool CanModifyInput() const + {return m_target ? m_target->CanModifyInput() : false;} + + void Initialize(const NameValuePairs ¶meters, int propagation); + byte * CreatePutSpace(size_t &size) + { + if (m_target) + return m_target->CreatePutSpace(size); + else + { + size = 0; + return NULLPTR; + } + } + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {return m_target ? m_target->Put2(inString, length, GetPassSignals() ? messageEnd : 0, blocking) : 0;} + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) + {return m_target && GetPassSignals() ? m_target->Flush(hardFlush, propagation, blocking) : false;} + bool MessageSeriesEnd(int propagation=-1, bool blocking=true) + {return m_target && GetPassSignals() ? m_target->MessageSeriesEnd(propagation, blocking) : false;} + + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size) + { + if (m_target) + return m_target->ChannelCreatePutSpace(channel, size); + else + { + size = 0; + return NULLPTR; + } + } + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) + {return m_target ? m_target->ChannelPut2(channel, begin, length, GetPassSignals() ? messageEnd : 0, blocking) : 0;} + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking) + {return m_target ? m_target->ChannelPutModifiable2(channel, begin, length, GetPassSignals() ? messageEnd : 0, blocking) : 0;} + bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true) + {return m_target && GetPassSignals() ? m_target->ChannelFlush(channel, completeFlush, propagation, blocking) : false;} + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true) + {return m_target && GetPassSignals() ? m_target->ChannelMessageSeriesEnd(channel, propagation, blocking) : false;} + + unsigned int GetMaxWaitObjectCount() const + { return m_target && GetPassWaitObjects() ? m_target->GetMaxWaitObjectCount() : 0; } + void GetWaitObjects(WaitObjectContainer &container, CallStack const& callStack) + { if (m_target && GetPassWaitObjects()) m_target->GetWaitObjects(container, callStack); } + +private: + BufferedTransformation *m_target; + word32 m_behavior; +}; + +/// \brief Filter class that is a proxy for a sink +/// \details Used By ProxyFilter +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL OutputProxy : public CustomSignalPropagation +{ +public: + virtual ~OutputProxy() {} + + /// \brief Construct an OutputProxy + /// \param owner the owning transformation + /// \param passSignal flag indicating if signals should be passed + OutputProxy(BufferedTransformation &owner, bool passSignal) : m_owner(owner), m_passSignal(passSignal) {} + + /// \brief Retrieve passSignal flag + /// \return flag indicating if signals should be passed + bool GetPassSignal() const {return m_passSignal;} + /// \brief Set passSignal flag + /// \param passSignal flag indicating if signals should be passed + void SetPassSignal(bool passSignal) {m_passSignal = passSignal;} + + byte * CreatePutSpace(size_t &size) + {return m_owner.AttachedTransformation()->CreatePutSpace(size);} + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->Put2(inString, length, m_passSignal ? messageEnd : 0, blocking);} + size_t PutModifiable2(byte *begin, size_t length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->PutModifiable2(begin, length, m_passSignal ? messageEnd : 0, blocking);} + void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1) + {if (m_passSignal) m_owner.AttachedTransformation()->Initialize(parameters, propagation);} + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->Flush(hardFlush, propagation, blocking) : false;} + bool MessageSeriesEnd(int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->MessageSeriesEnd(propagation, blocking) : false;} + + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size) + {return m_owner.AttachedTransformation()->ChannelCreatePutSpace(channel, size);} + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->ChannelPut2(channel, begin, length, m_passSignal ? messageEnd : 0, blocking);} + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking) + {return m_owner.AttachedTransformation()->ChannelPutModifiable2(channel, begin, length, m_passSignal ? messageEnd : 0, blocking);} + bool ChannelFlush(const std::string &channel, bool completeFlush, int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->ChannelFlush(channel, completeFlush, propagation, blocking) : false;} + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true) + {return m_passSignal ? m_owner.AttachedTransformation()->ChannelMessageSeriesEnd(channel, propagation, blocking) : false;} + +private: + BufferedTransformation &m_owner; + bool m_passSignal; +}; + +/// \brief Base class for Filter classes that are proxies for a chain of other filters +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL ProxyFilter : public FilterWithBufferedInput +{ +public: + virtual ~ProxyFilter() {} + + /// \brief Construct a ProxyFilter + /// \param filter an output filter + /// \param firstSize the first Put size + /// \param lastSize the last Put size + /// \param attachment an attached transformation + ProxyFilter(BufferedTransformation *filter, size_t firstSize, size_t lastSize, BufferedTransformation *attachment); + + bool IsolatedFlush(bool hardFlush, bool blocking); + + /// \brief Sets the OutputProxy filter + /// \param filter an OutputProxy filter + void SetFilter(Filter *filter); + void NextPutMultiple(const byte *s, size_t len); + void NextPutModifiable(byte *inString, size_t length); + +protected: + member_ptr m_filter; +}; + +/// \brief Proxy filter that doesn't modify the underlying filter's input or output +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL SimpleProxyFilter : public ProxyFilter +{ +public: + /// \brief Construct a SimpleProxyFilter + /// \param filter an output filter + /// \param attachment an attached transformation + SimpleProxyFilter(BufferedTransformation *filter, BufferedTransformation *attachment) + : ProxyFilter(filter, 0, 0, attachment) {} + + void FirstPut(const byte * inString) + {CRYPTOPP_UNUSED(inString);} + + /// \brief Input the last block of data + /// \param inString the input byte buffer + /// \param length the size of the input buffer, in bytes + /// \details LastPut() processes the last block of data and signals attached filters to do the same. + /// LastPut() is always called. The pseudo algorithm for the logic is: + ///
+	///     if totalLength < firstSize then length == totalLength
+	///     else if totalLength <= firstSize+lastSize then length == totalLength-firstSize
+	///     else lastSize <= length < lastSize+blockSize
+	/// 
+ void LastPut(const byte *inString, size_t length) + {CRYPTOPP_UNUSED(inString), CRYPTOPP_UNUSED(length); m_filter->MessageEnd();} +}; + +/// \brief Filter wrapper for PK_Encryptor +/// \details PK_DecryptorFilter is a proxy for the filter created by PK_Encryptor::CreateEncryptionFilter. +/// This class provides symmetry with VerifierFilter. +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL PK_EncryptorFilter : public SimpleProxyFilter +{ +public: + /// \brief Construct a PK_EncryptorFilter + /// \param rng a RandomNumberGenerator derived class + /// \param encryptor a PK_Encryptor derived class + /// \param attachment an optional attached transformation + PK_EncryptorFilter(RandomNumberGenerator &rng, const PK_Encryptor &encryptor, BufferedTransformation *attachment = NULLPTR) + : SimpleProxyFilter(encryptor.CreateEncryptionFilter(rng), attachment) {} +}; + +/// \brief Filter wrapper for PK_Decryptor +/// \details PK_DecryptorFilter is a proxy for the filter created by PK_Decryptor::CreateDecryptionFilter. +/// This class provides symmetry with SignerFilter. +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL PK_DecryptorFilter : public SimpleProxyFilter +{ +public: + /// \brief Construct a PK_DecryptorFilter + /// \param rng a RandomNumberGenerator derived class + /// \param decryptor a PK_Decryptor derived class + /// \param attachment an optional attached transformation + PK_DecryptorFilter(RandomNumberGenerator &rng, const PK_Decryptor &decryptor, BufferedTransformation *attachment = NULLPTR) + : SimpleProxyFilter(decryptor.CreateDecryptionFilter(rng), attachment) {} +}; + +/// \brief Append input to a string object +/// \tparam T std::basic_string type +/// \details StringSinkTemplate is a StringSinkTemplate typedef +/// \since Crypto++ 5.0 +template +class StringSinkTemplate : public Bufferless +{ +public: + typedef typename T::value_type value_type; + virtual ~StringSinkTemplate() {} + + /// \brief Construct a StringSinkTemplate + /// \param output std::basic_string or std::vector type + StringSinkTemplate(T &output) + : m_output(&output) {CRYPTOPP_ASSERT(sizeof(value_type)==1);} + + void IsolatedInitialize(const NameValuePairs ¶meters) + {if (!parameters.GetValue("OutputStringPointer", m_output)) throw InvalidArgument("StringSink: OutputStringPointer not specified");} + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + { + CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); + if (length > 0) + { + typename T::size_type size = m_output->size(); + if (length < size && size + length > m_output->capacity()) + m_output->reserve(2*size); + m_output->insert(m_output->end(), (const value_type *)inString, (const value_type *)inString+length); + } + return 0; + } + +private: + T *m_output; +}; + +/// \brief Append input to a string object +/// \details StringSink is a typedef for StringSinkTemplate. +/// \sa ArraySink, ArrayXorSink +/// \since Crypto++ 4.0 +DOCUMENTED_TYPEDEF(StringSinkTemplate, StringSink); +CRYPTOPP_DLL_TEMPLATE_CLASS StringSinkTemplate; + +/// \brief Append input to a std::vector object +/// \details VectorSink is a typedef for StringSinkTemplate >. +/// \since Crypto++ 8.0 +DOCUMENTED_TYPEDEF(StringSinkTemplate >, VectorSink); +CRYPTOPP_DLL_TEMPLATE_CLASS StringSinkTemplate >; + +/// \brief Incorporates input into RNG as additional entropy +/// \since Crypto++ 4.0 +class RandomNumberSink : public Bufferless +{ +public: + virtual ~RandomNumberSink() {} + + /// \brief Construct a RandomNumberSink + RandomNumberSink() + : m_rng(NULLPTR) {} + + /// \brief Construct a RandomNumberSink + /// \param rng a RandomNumberGenerator derived class + RandomNumberSink(RandomNumberGenerator &rng) + : m_rng(&rng) {} + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + +private: + RandomNumberGenerator *m_rng; +}; + +/// \brief Copy input to a memory buffer +/// \details ArraySink wraps a fixed size buffer. The buffer is full once Put returns non-0. +/// When used in a pipeline, ArraySink silently discards input if the buffer is full. +/// AvailableSize() can be used to determine how much space remains in the buffer. +/// TotalPutLength() can be used to determine how many bytes were processed. +/// \sa StringSink, ArrayXorSink +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL ArraySink : public Bufferless +{ +public: + virtual ~ArraySink() {} + + /// \brief Construct an ArraySink + /// \param parameters a set of NameValuePairs to initialize this object + /// \details Name::OutputBuffer() is a mandatory parameter using this constructor. + ArraySink(const NameValuePairs ¶meters = g_nullNameValuePairs) + : m_buf(NULLPTR), m_size(0), m_total(0) {IsolatedInitialize(parameters);} + + /// \brief Construct an ArraySink + /// \param buf pointer to a memory buffer + /// \param size length of the memory buffer + ArraySink(byte *buf, size_t size) + : m_buf(buf), m_size(size), m_total(0) {} + + /// \brief Provides the size remaining in the Sink + /// \return size remaining in the Sink, in bytes + size_t AvailableSize() {return SaturatingSubtract(m_size, m_total);} + + /// \brief Provides the number of bytes written to the Sink + /// \return number of bytes written to the Sink, in bytes + lword TotalPutLength() {return m_total;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + byte * CreatePutSpace(size_t &size); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + +protected: + byte *m_buf; + size_t m_size; + lword m_total; +}; + +/// \brief Xor input to a memory buffer +/// \details ArrayXorSink wraps a fixed size buffer. The buffer is full once Put returns non-0. +/// When used in a pipeline, ArrayXorSink silently discards input if the buffer is full. +/// AvailableSize() can be used to determine how much space remains in the buffer. +/// TotalPutLength() can be used to determine how many bytes were processed. +/// \sa StringSink, ArraySink +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL ArrayXorSink : public ArraySink +{ +public: + virtual ~ArrayXorSink() {} + + /// \brief Construct an ArrayXorSink + /// \param buf pointer to a memory buffer + /// \param size length of the memory buffer + ArrayXorSink(byte *buf, size_t size) + : ArraySink(buf, size) {} + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + byte * CreatePutSpace(size_t &size) {return BufferedTransformation::CreatePutSpace(size);} +}; + +/// \brief String-based implementation of Store interface +/// \since Crypto++ 4.0 +class StringStore : public Store +{ +public: + /// \brief Construct a StringStore + /// \param string pointer to a C-String + StringStore(const char *string = NULLPTR) + {StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + + /// \brief Construct a StringStore + /// \param string pointer to a memory buffer + /// \param length size of the memory buffer + StringStore(const byte *string, size_t length) + {StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string, length)));} + + /// \brief Construct a StringStore + /// \tparam T std::basic_string type + /// \param string reference to a std::basic_string type + template StringStore(const T &string) + {StoreInitialize(MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + + CRYPTOPP_DLL size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + CRYPTOPP_DLL size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + +private: + CRYPTOPP_DLL void StoreInitialize(const NameValuePairs ¶meters); + + const byte *m_store; + size_t m_length, m_count; +}; + +/// \brief RNG-based implementation of Source interface +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL RandomNumberStore : public Store +{ +public: + virtual ~RandomNumberStore() {} + + RandomNumberStore() + : m_rng(NULLPTR), m_length(0), m_count(0) {} + + RandomNumberStore(RandomNumberGenerator &rng, lword length) + : m_rng(&rng), m_length(length), m_count(0) {} + + bool AnyRetrievable() const {return MaxRetrievable() != 0;} + lword MaxRetrievable() const {return m_length-m_count;} + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const + { + CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(begin); CRYPTOPP_UNUSED(end); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); + throw NotImplemented("RandomNumberStore: CopyRangeTo2() is not supported by this store"); + } + +private: + void StoreInitialize(const NameValuePairs ¶meters); + + RandomNumberGenerator *m_rng; + lword m_length, m_count; +}; + +/// \brief Empty store +/// \since Crypto++ 5.0 +class CRYPTOPP_DLL NullStore : public Store +{ +public: + NullStore(lword size = ULONG_MAX) : m_size(size) {} + void StoreInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters);} + lword MaxRetrievable() const {return m_size;} + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + +private: + lword m_size; +}; + +/// \brief Implementation of BufferedTransformation's attachment interface +/// \details Source is a cornerstone of the Pipeline trinitiy. Data flows from +/// Sources, through Filters, and then terminates in Sinks. The difference +/// between a Source and Filter is a Source \a pumps data, while a Filter does +/// not. The difference between a Filter and a Sink is a Filter allows an +/// attached transformation, while a Sink does not. +/// \details See the discussion of BufferedTransformation in cryptlib.h for +/// more details. +/// \sa Store and SourceTemplate +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Source : public InputRejecting +{ +public: + virtual ~Source() {} + + /// \brief Construct a Source + /// \param attachment an optional attached transformation + Source(BufferedTransformation *attachment = NULLPTR) + {Source::Detach(attachment);} + + /// \name PIPELINE + //@{ + + /// \brief Pump data to attached transformation + /// \param pumpMax the maximum number of bytes to pump + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + /// \details Internally, Pump() calls Pump2(). + /// \note pumpMax is a lword, which is a 64-bit value that typically uses + /// LWORD_MAX. The default argument is SIZE_MAX, and it can be + /// 32-bits or 64-bits. + /// \sa Pump2, PumpAll, AnyRetrievable, MaxRetrievable + lword Pump(lword pumpMax=SIZE_MAX) + {Pump2(pumpMax); return pumpMax;} + + /// \brief Pump messages to attached transformation + /// \param count the maximum number of messages to pump + /// \return TODO + /// \details Internally, PumpMessages() calls PumpMessages2(). + unsigned int PumpMessages(unsigned int count=UINT_MAX) + {PumpMessages2(count); return count;} + + /// \brief Pump all data to attached transformation + /// \details Pumps all data to the attached transformation and signal the end of the current + /// message. To avoid the MessageEnd() signal call \ref Pump "Pump(LWORD_MAX)" or \ref Pump2 + /// "Pump2(LWORD_MAX, bool)". + /// \details Internally, PumpAll() calls PumpAll2(), which calls PumpMessages(). + /// \sa Pump, Pump2, AnyRetrievable, MaxRetrievable + void PumpAll() + {PumpAll2();} + + /// \brief Pump data to attached transformation + /// \param byteCount the maximum number of bytes to pump + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + /// \details byteCount is an \a IN and \a OUT parameter. When the call is made, byteCount is the + /// requested size of the pump. When the call returns, byteCount is the number of bytes that + /// were pumped. + /// \sa Pump, PumpAll, AnyRetrievable, MaxRetrievable + virtual size_t Pump2(lword &byteCount, bool blocking=true) =0; + + /// \brief Pump messages to attached transformation + /// \param messageCount the maximum number of messages to pump + /// \param blocking specifies whether the object should block when processing input + /// \details messageCount is an IN and OUT parameter. + virtual size_t PumpMessages2(unsigned int &messageCount, bool blocking=true) =0; + + /// \brief Pump all data to attached transformation + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed). + /// 0 indicates all bytes were processed. + /// \sa Pump, Pump2, AnyRetrievable, MaxRetrievable + virtual size_t PumpAll2(bool blocking=true); + + /// \brief Determines if the Source is exhausted + /// \return true if the source has been exhausted + virtual bool SourceExhausted() const =0; + + //@} + +protected: + void SourceInitialize(bool pumpAll, const NameValuePairs ¶meters) + { + IsolatedInitialize(parameters); + if (pumpAll) + PumpAll(); + } +}; + +/// \brief Transform a Store into a Source +/// \tparam T the class or type +/// \since Crypto++ 5.0 +template +class SourceTemplate : public Source +{ +public: + virtual ~SourceTemplate() {} + + /// \brief Construct a SourceTemplate + /// \param attachment an attached transformation + SourceTemplate(BufferedTransformation *attachment) + : Source(attachment) {} + void IsolatedInitialize(const NameValuePairs ¶meters) + {m_store.IsolatedInitialize(parameters);} + size_t Pump2(lword &byteCount, bool blocking=true) + {return m_store.TransferTo2(*AttachedTransformation(), byteCount, DEFAULT_CHANNEL, blocking);} + size_t PumpMessages2(unsigned int &messageCount, bool blocking=true) + {return m_store.TransferMessagesTo2(*AttachedTransformation(), messageCount, DEFAULT_CHANNEL, blocking);} + size_t PumpAll2(bool blocking=true) + {return m_store.TransferAllTo2(*AttachedTransformation(), DEFAULT_CHANNEL, blocking);} + bool SourceExhausted() const + {return !m_store.AnyRetrievable() && !m_store.AnyMessages();} + void SetAutoSignalPropagation(int propagation) + {m_store.SetAutoSignalPropagation(propagation);} + int GetAutoSignalPropagation() const + {return m_store.GetAutoSignalPropagation();} + +protected: + T m_store; +}; + +/// \brief String-based implementation of the Source interface +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL StringSource : public SourceTemplate +{ +public: + /// \brief Construct a StringSource + /// \param attachment an optional attached transformation + StringSource(BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {} + + /// \brief Construct a StringSource + /// \param string C-String + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + StringSource(const char *string, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} + + /// \brief Construct a StringSource + /// \param string binary byte array + /// \param length size of the byte array + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + StringSource(const byte *string, size_t length, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string, length)));} + + /// \brief Construct a StringSource + /// \param string std::string + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + StringSource(const std::string &string, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(string)));} +}; + +/// \brief Pointer-based implementation of the Source interface +/// \details ArraySource is a typedef for StringSource. Use the third constructor for an array source. +/// The third constructor takes a pointer and length. +/// \since Crypto++ 5.6.0 +DOCUMENTED_TYPEDEF(StringSource, ArraySource); + +/// \brief std::vector-based implementation of the Source interface +/// \since Crypto++ 8.0 +class CRYPTOPP_DLL VectorSource : public SourceTemplate +{ +public: + /// \brief Construct a VectorSource + /// \param attachment an optional attached transformation + VectorSource(BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {} + + /// \brief Construct a VectorSource + /// \param vec vector of bytes + /// \param pumpAll flag indicating if source data should be pumped to its attached transformation + /// \param attachment an optional attached transformation + VectorSource(const std::vector &vec, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) {SourceInitialize(pumpAll, MakeParameters("InputBuffer", ConstByteArrayParameter(vec)));} +}; + +/// \brief RNG-based implementation of Source interface +/// \since Crypto++ 4.0 +class CRYPTOPP_DLL RandomNumberSource : public SourceTemplate +{ +public: + RandomNumberSource(RandomNumberGenerator &rng, int length, bool pumpAll, BufferedTransformation *attachment = NULLPTR) + : SourceTemplate(attachment) + {SourceInitialize(pumpAll, MakeParameters("RandomNumberGeneratorPointer", &rng)("RandomNumberStoreSize", length));} +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/fips140.h b/third_party/cryptoppwin/include/cryptopp/fips140.h new file mode 100644 index 00000000..ebc67edf --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/fips140.h @@ -0,0 +1,112 @@ +// fips140.h - originally written and placed in the public domain by Wei Dai + +/// \file fips140.h +/// \brief Classes and functions for the FIPS 140-2 validated library +/// \details The FIPS validated library is only available on Windows as a DLL. Once compiled, +/// the library is always in FIPS mode contingent upon successful execution of +/// DoPowerUpSelfTest() or DoDllPowerUpSelfTest(). +/// \sa Visual Studio and +/// config.h on the Crypto++ wiki. + +#ifndef CRYPTOPP_FIPS140_H +#define CRYPTOPP_FIPS140_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// Exception thrown when a crypto algorithm is used after a self test fails +/// \details The self tests for an algorithm are performed by Algorithm class +/// when CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined. +class CRYPTOPP_DLL SelfTestFailure : public Exception +{ +public: + explicit SelfTestFailure(const std::string &s) : Exception(OTHER_ERROR, s) {} +}; + +/// \brief Determines whether the library provides FIPS validated cryptography +/// \return true if FIPS 140-2 validated features were enabled at compile time. +/// \details true if FIPS 140-2 validated features were enabled at compile time, +/// false otherwise. +/// \note FIPS mode is enabled at compile time. A program or other module cannot +/// arbitrarily enter or exit the mode. +CRYPTOPP_DLL bool CRYPTOPP_API FIPS_140_2_ComplianceEnabled(); + +/// \brief Status of the power-up self test +enum PowerUpSelfTestStatus { + + /// \brief The self tests have not been performed. + POWER_UP_SELF_TEST_NOT_DONE, + /// \brief The self tests were executed via DoPowerUpSelfTest() or + /// DoDllPowerUpSelfTest(), but the result was failure. + POWER_UP_SELF_TEST_FAILED, + /// \brief The self tests were executed via DoPowerUpSelfTest() or + /// DoDllPowerUpSelfTest(), and the result was success. + POWER_UP_SELF_TEST_PASSED +}; + +/// \brief Performs the power-up self test +/// \param moduleFilename the fully qualified name of the module +/// \param expectedModuleMac the expected MAC of the components protected by the integrity check +/// \details Performs the power-up self test, and sets the self test status to +/// POWER_UP_SELF_TEST_PASSED or POWER_UP_SELF_TEST_FAILED. +/// \details The self tests for an algorithm are performed by the Algorithm class +/// when CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined. +CRYPTOPP_DLL void CRYPTOPP_API DoPowerUpSelfTest(const char *moduleFilename, const byte *expectedModuleMac); + +/// \brief Performs the power-up self test on the DLL +/// \details Performs the power-up self test using the filename of this DLL and the +/// embedded module MAC, and sets the self test status to POWER_UP_SELF_TEST_PASSED or +/// POWER_UP_SELF_TEST_FAILED. +/// \details The self tests for an algorithm are performed by the Algorithm class +/// when CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined. +CRYPTOPP_DLL void CRYPTOPP_API DoDllPowerUpSelfTest(); + +/// \brief Sets the power-up self test status to POWER_UP_SELF_TEST_FAILED +/// \details Sets the power-up self test status to POWER_UP_SELF_TEST_FAILED to simulate failure. +CRYPTOPP_DLL void CRYPTOPP_API SimulatePowerUpSelfTestFailure(); + +/// \brief Provides the current power-up self test status +/// \return the current power-up self test status +CRYPTOPP_DLL PowerUpSelfTestStatus CRYPTOPP_API GetPowerUpSelfTestStatus(); + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +typedef PowerUpSelfTestStatus (CRYPTOPP_API * PGetPowerUpSelfTestStatus)(); +#endif + +/// \brief Class object that calculates the MAC on the module +/// \return the MAC for the module +CRYPTOPP_DLL MessageAuthenticationCode * CRYPTOPP_API NewIntegrityCheckingMAC(); + +/// \brief Verifies the MAC on the module +/// \param moduleFilename the fully qualified name of the module +/// \param expectedModuleMac the expected MAC of the components protected by the integrity check +/// \param pActualMac the actual MAC of the components calculated by the integrity check +/// \param pMacFileLocation the offset of the MAC in the PE/PE+ module +/// \return true if the MAC is valid, false otherwise +CRYPTOPP_DLL bool CRYPTOPP_API IntegrityCheckModule(const char *moduleFilename, const byte *expectedModuleMac, SecByteBlock *pActualMac = NULLPTR, unsigned long *pMacFileLocation = NULLPTR); + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING +// this is used by Algorithm constructor to allow Algorithm objects to be constructed for the self test +bool PowerUpSelfTestInProgressOnThisThread(); + +void SetPowerUpSelfTestInProgressOnThisThread(bool inProgress); + +void SignaturePairwiseConsistencyTest(const PK_Signer &signer, const PK_Verifier &verifier); +void EncryptionPairwiseConsistencyTest(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor); + +void SignaturePairwiseConsistencyTest_FIPS_140_Only(const PK_Signer &signer, const PK_Verifier &verifier); +void EncryptionPairwiseConsistencyTest_FIPS_140_Only(const PK_Encryptor &encryptor, const PK_Decryptor &decryptor); +#endif + +/// \brief The placeholder used prior to embedding the actual MAC in the module. +/// \details After the DLL is built but before it is MAC'd, the string CRYPTOPP_DUMMY_DLL_MAC +/// is used as a placeholder for the actual MAC. A post-build step is performed which calculates +/// the MAC of the DLL and embeds it in the module. The actual MAC is written by the +/// cryptest.exe program using the mac_dll subcommand. +#define CRYPTOPP_DUMMY_DLL_MAC "MAC_51f34b8db820ae8" + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/fltrimpl.h b/third_party/cryptoppwin/include/cryptopp/fltrimpl.h new file mode 100644 index 00000000..399a7292 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/fltrimpl.h @@ -0,0 +1,69 @@ +#ifndef CRYPTOPP_FLTRIMPL_H +#define CRYPTOPP_FLTRIMPL_H + +#define FILTER_BEGIN \ + switch (m_continueAt) \ + { \ + case 0: \ + m_inputPosition = 0; + +#define FILTER_END_NO_MESSAGE_END_NO_RETURN \ + break; \ + default: \ + CRYPTOPP_ASSERT(false); \ + } + +#define FILTER_END_NO_MESSAGE_END \ + FILTER_END_NO_MESSAGE_END_NO_RETURN \ + return 0; + +/* +#define FILTER_END \ + case -1: \ + if (messageEnd && Output(-1, NULLPTR, 0, messageEnd, blocking)) \ + return 1; \ + FILTER_END_NO_MESSAGE_END +*/ + +#define FILTER_OUTPUT3(site, statement, output, length, messageEnd, channel) \ + {\ + case site: \ + (void) statement; \ + if (Output(site, output, length, messageEnd, blocking, channel)) \ + return STDMAX(size_t(1), length-m_inputPosition);\ + } + +#define FILTER_OUTPUT2(site, statement, output, length, messageEnd) \ + FILTER_OUTPUT3(site, statement, output, length, messageEnd, DEFAULT_CHANNEL) + +#define FILTER_OUTPUT(site, output, length, messageEnd) \ + FILTER_OUTPUT2(site, 0, output, length, messageEnd) + +#define FILTER_OUTPUT_BYTE(site, output) \ + FILTER_OUTPUT(site, &(const byte &)(byte)output, 1, 0) + +#define FILTER_OUTPUT2_MODIFIABLE(site, statement, output, length, messageEnd) \ + {\ + /* fall through */ \ + case site: \ + (void) statement; \ + if (OutputModifiable(site, output, length, messageEnd, blocking)) \ + return STDMAX(size_t(1), length-m_inputPosition);\ + } + +#define FILTER_OUTPUT_MODIFIABLE(site, output, length, messageEnd) \ + FILTER_OUTPUT2_MODIFIABLE(site, 0, output, length, messageEnd) + +#define FILTER_OUTPUT2_MAYBE_MODIFIABLE(site, statement, output, length, messageEnd, modifiable) \ + {\ + /* fall through */ \ + case site: \ + (void) statement; \ + if (modifiable ? OutputModifiable(site, output, length, messageEnd, blocking) : Output(site, output, length, messageEnd, blocking)) \ + return STDMAX(size_t(1), length-m_inputPosition);\ + } + +#define FILTER_OUTPUT_MAYBE_MODIFIABLE(site, output, length, messageEnd, modifiable) \ + FILTER_OUTPUT2_MAYBE_MODIFIABLE(site, 0, output, length, messageEnd, modifiable) + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/gcm.h b/third_party/cryptoppwin/include/cryptopp/gcm.h new file mode 100644 index 00000000..0f4d7025 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/gcm.h @@ -0,0 +1,139 @@ +// gcm.h - originally written and placed in the public domain by Wei Dai + +/// \file gcm.h +/// \brief GCM block cipher mode of operation +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_GCM_H +#define CRYPTOPP_GCM_H + +#include "authenc.h" +#include "modes.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_GCM_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \enum GCM_TablesOption +/// \brief GCM table size options +enum GCM_TablesOption { + /// \brief Use a table with 2K entries + GCM_2K_Tables, + /// \brief Use a table with 64K entries + GCM_64K_Tables}; + +/// \brief GCM block cipher base implementation +/// \details Base implementation of the AuthenticatedSymmetricCipher interface +/// \since Crypto++ 5.6.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE GCM_Base : public AuthenticatedSymmetricCipherBase +{ +public: + // AuthenticatedSymmetricCipher + std::string AlgorithmName() const + {return GetBlockCipher().AlgorithmName() + std::string("/GCM");} + std::string AlgorithmProvider() const + {return GetBlockCipher().AlgorithmProvider();} + size_t MinKeyLength() const + {return GetBlockCipher().MinKeyLength();} + size_t MaxKeyLength() const + {return GetBlockCipher().MaxKeyLength();} + size_t DefaultKeyLength() const + {return GetBlockCipher().DefaultKeyLength();} + size_t GetValidKeyLength(size_t n) const + {return GetBlockCipher().GetValidKeyLength(n);} + bool IsValidKeyLength(size_t n) const + {return GetBlockCipher().IsValidKeyLength(n);} + unsigned int OptimalDataAlignment() const; + IV_Requirement IVRequirement() const + {return UNIQUE_IV;} + unsigned int IVSize() const + {return 12;} + unsigned int MinIVLength() const + {return 1;} + unsigned int MaxIVLength() const + {return UINT_MAX;} // (W64LIT(1)<<61)-1 in the standard + unsigned int DigestSize() const + {return 16;} + lword MaxHeaderLength() const + {return (W64LIT(1)<<61)-1;} + lword MaxMessageLength() const + {return ((W64LIT(1)<<39)-256)/8;} + +protected: + // AuthenticatedSymmetricCipherBase + bool AuthenticationIsOnPlaintext() const + {return false;} + unsigned int AuthenticationBlockSize() const + {return HASH_BLOCKSIZE;} + void SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms); + void Resync(const byte *iv, size_t len); + size_t AuthenticateBlocks(const byte *data, size_t len); + void AuthenticateLastHeaderBlock(); + void AuthenticateLastConfidentialBlock(); + void AuthenticateLastFooterBlock(byte *mac, size_t macSize); + SymmetricCipher & AccessSymmetricCipher() {return m_ctr;} + + virtual BlockCipher & AccessBlockCipher() =0; + virtual GCM_TablesOption GetTablesOption() const =0; + + const BlockCipher & GetBlockCipher() const {return const_cast(this)->AccessBlockCipher();} + byte *HashBuffer() {return m_buffer+REQUIRED_BLOCKSIZE;} + byte *HashKey() {return m_buffer+2*REQUIRED_BLOCKSIZE;} + byte *MulTable() {return m_buffer+3*REQUIRED_BLOCKSIZE;} + inline void ReverseHashBufferIfNeeded(); + + class CRYPTOPP_DLL GCTR : public CTR_Mode_ExternalCipher::Encryption + { + protected: + void IncrementCounterBy256(); + }; + + GCTR m_ctr; + static word16 s_reductionTable[256]; + static volatile bool s_reductionTableInitialized; + enum {REQUIRED_BLOCKSIZE = 16, HASH_BLOCKSIZE = 16}; +}; + +/// \brief GCM block cipher final implementation +/// \tparam T_BlockCipher block cipher +/// \tparam T_TablesOption table size, either \p GCM_2K_Tables or \p GCM_64K_Tables +/// \tparam T_IsEncryption direction in which to operate the cipher +/// \since Crypto++ 5.6.0 +template +class GCM_Final : public GCM_Base +{ +public: + static std::string StaticAlgorithmName() + {return T_BlockCipher::StaticAlgorithmName() + std::string("/GCM");} + bool IsForwardTransformation() const + {return T_IsEncryption;} + +private: + GCM_TablesOption GetTablesOption() const {return T_TablesOption;} + BlockCipher & AccessBlockCipher() {return m_cipher;} + typename T_BlockCipher::Encryption m_cipher; +}; + +/// \brief GCM block cipher mode of operation +/// \tparam T_BlockCipher block cipher +/// \tparam T_TablesOption table size, either \p GCM_2K_Tables or \p GCM_64K_Tables +/// \details \p GCM provides the \p Encryption and \p Decryption typedef. See GCM_Base +/// and GCM_Final for the AuthenticatedSymmetricCipher implementation. +/// \sa GCM Mode and +/// Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 5.6.0 +template +struct GCM : public AuthenticatedSymmetricCipherDocumentation +{ + typedef GCM_Final Encryption; + typedef GCM_Final Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/gf256.h b/third_party/cryptoppwin/include/cryptopp/gf256.h new file mode 100644 index 00000000..3c5c3f61 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/gf256.h @@ -0,0 +1,72 @@ +// gf256.h - originally written and placed in the public domain by Wei Dai + +/// \file gf256.h +/// \brief Classes and functions for schemes over GF(256) + +#ifndef CRYPTOPP_GF256_H +#define CRYPTOPP_GF256_H + +#include "cryptlib.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief GF(256) with polynomial basis +class GF256 +{ +public: + typedef byte Element; + typedef int RandomizationParameter; + + GF256(byte modulus) : m_modulus(modulus) {} + + Element RandomElement(RandomNumberGenerator &rng, int ignored = 0) const + {CRYPTOPP_UNUSED(ignored); return rng.GenerateByte();} + + bool Equal(Element a, Element b) const + {return a==b;} + + Element Zero() const + {return 0;} + + Element Add(Element a, Element b) const + {return a^b;} + + Element& Accumulate(Element &a, Element b) const + {return a^=b;} + + Element Inverse(Element a) const + {return a;} + + Element Subtract(Element a, Element b) const + {return a^b;} + + Element& Reduce(Element &a, Element b) const + {return a^=b;} + + Element Double(Element a) const + {CRYPTOPP_UNUSED(a); return 0;} + + Element One() const + {return 1;} + + Element Multiply(Element a, Element b) const; + + Element Square(Element a) const + {return Multiply(a, a);} + + bool IsUnit(Element a) const + {return a != 0;} + + Element MultiplicativeInverse(Element a) const; + + Element Divide(Element a, Element b) const + {return Multiply(a, MultiplicativeInverse(b));} + +private: + word m_modulus; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/gf2_32.h b/third_party/cryptoppwin/include/cryptopp/gf2_32.h new file mode 100644 index 00000000..9e794fe7 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/gf2_32.h @@ -0,0 +1,73 @@ +// gf2_32.h - originally written and placed in the public domain by Wei Dai + +/// \file gf2_32.h +/// \brief Classes and functions for schemes over GF(2^32) + +#ifndef CRYPTOPP_GF2_32_H +#define CRYPTOPP_GF2_32_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief GF(2^32) with polynomial basis +class GF2_32 +{ +public: + typedef word32 Element; + typedef int RandomizationParameter; + + GF2_32(word32 modulus=0x0000008D) : m_modulus(modulus) {} + + Element RandomElement(RandomNumberGenerator &rng, int ignored = 0) const + {CRYPTOPP_UNUSED(ignored); return rng.GenerateWord32();} + + bool Equal(Element a, Element b) const + {return a==b;} + + Element Identity() const + {return 0;} + + Element Add(Element a, Element b) const + {return a^b;} + + Element& Accumulate(Element &a, Element b) const + {return a^=b;} + + Element Inverse(Element a) const + {return a;} + + Element Subtract(Element a, Element b) const + {return a^b;} + + Element& Reduce(Element &a, Element b) const + {return a^=b;} + + Element Double(Element a) const + {CRYPTOPP_UNUSED(a); return 0;} + + Element MultiplicativeIdentity() const + {return 1;} + + Element Multiply(Element a, Element b) const; + + Element Square(Element a) const + {return Multiply(a, a);} + + bool IsUnit(Element a) const + {return a != 0;} + + Element MultiplicativeInverse(Element a) const; + + Element Divide(Element a, Element b) const + {return Multiply(a, MultiplicativeInverse(b));} + +private: + word32 m_modulus; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/gf2n.h b/third_party/cryptoppwin/include/cryptopp/gf2n.h new file mode 100644 index 00000000..4b61fb88 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/gf2n.h @@ -0,0 +1,406 @@ +// gf2n.h - originally written and placed in the public domain by Wei Dai + +/// \file gf2n.h +/// \brief Classes and functions for schemes over GF(2^n) + +#ifndef CRYPTOPP_GF2N_H +#define CRYPTOPP_GF2N_H + +#include "cryptlib.h" +#include "secblock.h" +#include "algebra.h" +#include "misc.h" +#include "asn.h" + +#include + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Polynomial with Coefficients in GF(2) +/*! \nosubgrouping */ +class CRYPTOPP_DLL PolynomialMod2 +{ +public: + /// \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + /// \brief Exception thrown when divide by zero is encountered + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "PolynomialMod2: division by zero") {} + }; + + typedef unsigned int RandomizationParameter; + //@} + + /// \name CREATORS + //@{ + /// \brief Construct the zero polynomial + PolynomialMod2(); + /// Copy construct a PolynomialMod2 + PolynomialMod2(const PolynomialMod2& t); + + /// \brief Construct a PolynomialMod2 from a word + /// \details value should be encoded with the least significant bit as coefficient to x^0 + /// and most significant bit as coefficient to x^(WORD_BITS-1) + /// bitLength denotes how much memory to allocate initially + PolynomialMod2(word value, size_t bitLength=WORD_BITS); + + /// \brief Construct a PolynomialMod2 from big-endian byte array + PolynomialMod2(const byte *encodedPoly, size_t byteCount) + {Decode(encodedPoly, byteCount);} + + /// \brief Construct a PolynomialMod2 from big-endian form stored in a BufferedTransformation + PolynomialMod2(BufferedTransformation &encodedPoly, size_t byteCount) + {Decode(encodedPoly, byteCount);} + + /// \brief Create a uniformly distributed random polynomial + /// \details Create a random polynomial uniformly distributed over all polynomials with degree less than bitcount + PolynomialMod2(RandomNumberGenerator &rng, size_t bitcount) + {Randomize(rng, bitcount);} + + /// \brief Provides x^i + /// \return x^i + static PolynomialMod2 CRYPTOPP_API Monomial(size_t i); + /// \brief Provides x^t0 + x^t1 + x^t2 + /// \return x^t0 + x^t1 + x^t2 + /// \pre The coefficients should be provided in descending order. That is,
t0 > t1 > t2
.
+		static PolynomialMod2 CRYPTOPP_API Trinomial(size_t t0, size_t t1, size_t t2);
+		/// \brief Provides x^t0 + x^t1 + x^t2 + x^t3 + x^t4
+		/// \return x^t0 + x^t1 + x^t2 + x^t3 + x^t4
+		/// \pre The coefficients should be provided in descending order. That is, 
t0 > t1 > t2 > t3 > t4
.
+		static PolynomialMod2 CRYPTOPP_API Pentanomial(size_t t0, size_t t1, size_t t2, size_t t3, size_t t4);
+		/// \brief Provides x^(n-1) + ... + x + 1
+		/// \return x^(n-1) + ... + x + 1
+		static PolynomialMod2 CRYPTOPP_API AllOnes(size_t n);
+
+		/// \brief The Zero polinomial
+		/// \return the zero polynomial
+		static const PolynomialMod2 & CRYPTOPP_API Zero();
+		/// \brief The One polinomial
+		/// \return the one polynomial
+		static const PolynomialMod2 & CRYPTOPP_API One();
+	//@}
+
+	/// \name ENCODE/DECODE
+	//@{
+		/// minimum number of bytes to encode this polynomial
+		/*! MinEncodedSize of 0 is 1 */
+		unsigned int MinEncodedSize() const {return STDMAX(1U, ByteCount());}
+
+		/// encode in big-endian format
+		/// \details if outputLen < MinEncodedSize, the most significant bytes will be dropped
+		///   if outputLen > MinEncodedSize, the most significant bytes will be padded
+		void Encode(byte *output, size_t outputLen) const;
+		///
+		void Encode(BufferedTransformation &bt, size_t outputLen) const;
+
+		///
+		void Decode(const byte *input, size_t inputLen);
+		///
+		//* Precondition: bt.MaxRetrievable() >= inputLen
+		void Decode(BufferedTransformation &bt, size_t inputLen);
+
+		/// encode value as big-endian octet string
+		void DEREncodeAsOctetString(BufferedTransformation &bt, size_t length) const;
+		/// decode value as big-endian octet string
+		void BERDecodeAsOctetString(BufferedTransformation &bt, size_t length);
+	//@}
+
+	/// \name ACCESSORS
+	//@{
+		/// number of significant bits = Degree() + 1
+		unsigned int BitCount() const;
+		/// number of significant bytes = ceiling(BitCount()/8)
+		unsigned int ByteCount() const;
+		/// number of significant words = ceiling(ByteCount()/sizeof(word))
+		unsigned int WordCount() const;
+
+		/// return the n-th bit, n=0 being the least significant bit
+		bool GetBit(size_t n) const {return GetCoefficient(n)!=0;}
+		/// return the n-th byte
+		byte GetByte(size_t n) const;
+
+		/// the zero polynomial will return a degree of -1
+		signed int Degree() const {return (signed int)(BitCount()-1U);}
+		/// degree + 1
+		unsigned int CoefficientCount() const {return BitCount();}
+		/// return coefficient for x^i
+		int GetCoefficient(size_t i) const
+			{return (i/WORD_BITS < reg.size()) ? int(reg[i/WORD_BITS] >> (i % WORD_BITS)) & 1 : 0;}
+		/// return coefficient for x^i
+		int operator[](unsigned int i) const {return GetCoefficient(i);}
+
+		///
+		bool IsZero() const {return !*this;}
+		///
+		bool Equals(const PolynomialMod2 &rhs) const;
+	//@}
+
+	/// \name MANIPULATORS
+	//@{
+		///
+		PolynomialMod2&  operator=(const PolynomialMod2& t);
+		///
+		PolynomialMod2&  operator&=(const PolynomialMod2& t);
+		///
+		PolynomialMod2&  operator^=(const PolynomialMod2& t);
+		///
+		PolynomialMod2&  operator+=(const PolynomialMod2& t) {return *this ^= t;}
+		///
+		PolynomialMod2&  operator-=(const PolynomialMod2& t) {return *this ^= t;}
+		///
+		PolynomialMod2&  operator*=(const PolynomialMod2& t);
+		///
+		PolynomialMod2&  operator/=(const PolynomialMod2& t);
+		///
+		PolynomialMod2&  operator%=(const PolynomialMod2& t);
+		///
+		PolynomialMod2&  operator<<=(unsigned int);
+		///
+		PolynomialMod2&  operator>>=(unsigned int);
+
+		///
+		void Randomize(RandomNumberGenerator &rng, size_t bitcount);
+
+		///
+		void SetBit(size_t i, int value = 1);
+		/// set the n-th byte to value
+		void SetByte(size_t n, byte value);
+
+		///
+		void SetCoefficient(size_t i, int value) {SetBit(i, value);}
+
+		///
+		void swap(PolynomialMod2 &a) {reg.swap(a.reg);}
+	//@}
+
+	/// \name UNARY OPERATORS
+	//@{
+		///
+		bool			operator!() const;
+		///
+		PolynomialMod2	operator+() const {return *this;}
+		///
+		PolynomialMod2	operator-() const {return *this;}
+	//@}
+
+	/// \name BINARY OPERATORS
+	//@{
+		///
+		PolynomialMod2 And(const PolynomialMod2 &b) const;
+		///
+		PolynomialMod2 Xor(const PolynomialMod2 &b) const;
+		///
+		PolynomialMod2 Plus(const PolynomialMod2 &b) const {return Xor(b);}
+		///
+		PolynomialMod2 Minus(const PolynomialMod2 &b) const {return Xor(b);}
+		///
+		PolynomialMod2 Times(const PolynomialMod2 &b) const;
+		///
+		PolynomialMod2 DividedBy(const PolynomialMod2 &b) const;
+		///
+		PolynomialMod2 Modulo(const PolynomialMod2 &b) const;
+
+		///
+		PolynomialMod2 operator>>(unsigned int n) const;
+		///
+		PolynomialMod2 operator<<(unsigned int n) const;
+	//@}
+
+	/// \name OTHER ARITHMETIC FUNCTIONS
+	//@{
+		/// sum modulo 2 of all coefficients
+		unsigned int Parity() const;
+
+		/// check for irreducibility
+		bool IsIrreducible() const;
+
+		/// is always zero since we're working modulo 2
+		PolynomialMod2 Doubled() const {return Zero();}
+		///
+		PolynomialMod2 Squared() const;
+
+		/// only 1 is a unit
+		bool IsUnit() const {return Equals(One());}
+		/// return inverse if *this is a unit, otherwise return 0
+		PolynomialMod2 MultiplicativeInverse() const {return IsUnit() ? One() : Zero();}
+
+		/// greatest common divisor
+		static PolynomialMod2 CRYPTOPP_API Gcd(const PolynomialMod2 &a, const PolynomialMod2 &n);
+		/// calculate multiplicative inverse of *this mod n
+		PolynomialMod2 InverseMod(const PolynomialMod2 &) const;
+
+		/// calculate r and q such that (a == d*q + r) && (deg(r) < deg(d))
+		static void CRYPTOPP_API Divide(PolynomialMod2 &r, PolynomialMod2 &q, const PolynomialMod2 &a, const PolynomialMod2 &d);
+	//@}
+
+	/// \name INPUT/OUTPUT
+	//@{
+		///
+		friend std::ostream& operator<<(std::ostream& out, const PolynomialMod2 &a);
+	//@}
+
+private:
+	friend class GF2NT;
+	friend class GF2NT233;
+
+	SecWordBlock reg;
+};
+
+///
+inline bool operator==(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b)
+{return a.Equals(b);}
+///
+inline bool operator!=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b)
+{return !(a==b);}
+/// compares degree
+inline bool operator> (const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b)
+{return a.Degree() > b.Degree();}
+/// compares degree
+inline bool operator>=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b)
+{return a.Degree() >= b.Degree();}
+/// compares degree
+inline bool operator< (const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b)
+{return a.Degree() < b.Degree();}
+/// compares degree
+inline bool operator<=(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b)
+{return a.Degree() <= b.Degree();}
+///
+inline CryptoPP::PolynomialMod2 operator&(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.And(b);}
+///
+inline CryptoPP::PolynomialMod2 operator^(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Xor(b);}
+///
+inline CryptoPP::PolynomialMod2 operator+(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Plus(b);}
+///
+inline CryptoPP::PolynomialMod2 operator-(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Minus(b);}
+///
+inline CryptoPP::PolynomialMod2 operator*(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Times(b);}
+///
+inline CryptoPP::PolynomialMod2 operator/(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.DividedBy(b);}
+///
+inline CryptoPP::PolynomialMod2 operator%(const CryptoPP::PolynomialMod2 &a, const CryptoPP::PolynomialMod2 &b) {return a.Modulo(b);}
+
+// CodeWarrior 8 workaround: put these template instantiations after overloaded operator declarations,
+// but before the use of QuotientRing > for VC .NET 2003
+CRYPTOPP_DLL_TEMPLATE_CLASS AbstractGroup;
+CRYPTOPP_DLL_TEMPLATE_CLASS AbstractRing;
+CRYPTOPP_DLL_TEMPLATE_CLASS AbstractEuclideanDomain;
+CRYPTOPP_DLL_TEMPLATE_CLASS EuclideanDomainOf;
+CRYPTOPP_DLL_TEMPLATE_CLASS QuotientRing >;
+
+/// \brief GF(2^n) with Polynomial Basis
+class CRYPTOPP_DLL GF2NP : public QuotientRing >
+{
+public:
+	GF2NP(const PolynomialMod2 &modulus);
+
+	virtual GF2NP * Clone() const {return new GF2NP(*this);}
+	virtual void DEREncode(BufferedTransformation &bt) const
+		{CRYPTOPP_UNUSED(bt); CRYPTOPP_ASSERT(false);}	// no ASN.1 syntax yet for general polynomial basis
+
+	void DEREncodeElement(BufferedTransformation &out, const Element &a) const;
+	void BERDecodeElement(BufferedTransformation &in, Element &a) const;
+
+	bool Equal(const Element &a, const Element &b) const
+		{CRYPTOPP_ASSERT(a.Degree() < m_modulus.Degree() && b.Degree() < m_modulus.Degree()); return a.Equals(b);}
+
+	bool IsUnit(const Element &a) const
+		{CRYPTOPP_ASSERT(a.Degree() < m_modulus.Degree()); return !!a;}
+
+	unsigned int MaxElementBitLength() const
+		{return m;}
+
+	unsigned int MaxElementByteLength() const
+		{return (unsigned int)BitsToBytes(MaxElementBitLength());}
+
+	Element SquareRoot(const Element &a) const;
+
+	Element HalfTrace(const Element &a) const;
+
+	// returns z such that z^2 + z == a
+	Element SolveQuadraticEquation(const Element &a) const;
+
+protected:
+	unsigned int m;
+};
+
+/// \brief GF(2^n) with Trinomial Basis
+class CRYPTOPP_DLL GF2NT : public GF2NP
+{
+public:
+	// polynomial modulus = x^t0 + x^t1 + x^t2, t0 > t1 > t2
+	GF2NT(unsigned int t0, unsigned int t1, unsigned int t2);
+
+	GF2NP * Clone() const {return new GF2NT(*this);}
+	void DEREncode(BufferedTransformation &bt) const;
+
+	const Element& Multiply(const Element &a, const Element &b) const;
+
+	const Element& Square(const Element &a) const
+		{return Reduced(a.Squared());}
+
+	const Element& MultiplicativeInverse(const Element &a) const;
+
+protected:
+	const Element& Reduced(const Element &a) const;
+
+	unsigned int t0, t1;
+	mutable PolynomialMod2 result;
+};
+
+/// \brief GF(2^n) for b233 and k233
+/// \details GF2NT233 is a specialization of GF2NT that provides Multiply()
+///   and Square() operations when carryless multiplies is available.
+class CRYPTOPP_DLL GF2NT233 : public GF2NT
+{
+public:
+	// polynomial modulus = x^t0 + x^t1 + x^t2, t0 > t1 > t2
+	GF2NT233(unsigned int t0, unsigned int t1, unsigned int t2);
+
+	GF2NP * Clone() const {return new GF2NT233(*this);}
+
+	const Element& Multiply(const Element &a, const Element &b) const;
+
+	const Element& Square(const Element &a) const;
+};
+
+/// \brief GF(2^n) with Pentanomial Basis
+class CRYPTOPP_DLL GF2NPP : public GF2NP
+{
+public:
+	// polynomial modulus = x^t0 + x^t1 + x^t2 + x^t3 + x^t4, t0 > t1 > t2 > t3 > t4
+	GF2NPP(unsigned int t0, unsigned int t1, unsigned int t2, unsigned int t3, unsigned int t4)
+		: GF2NP(PolynomialMod2::Pentanomial(t0, t1, t2, t3, t4)), t1(t1), t2(t2), t3(t3) {}
+
+	GF2NP * Clone() const {return new GF2NPP(*this);}
+	void DEREncode(BufferedTransformation &bt) const;
+
+private:
+	unsigned int t1, t2, t3;
+};
+
+// construct new GF2NP from the ASN.1 sequence Characteristic-two
+CRYPTOPP_DLL GF2NP * CRYPTOPP_API BERDecodeGF2NP(BufferedTransformation &bt);
+
+NAMESPACE_END
+
+#ifndef __BORLANDC__
+NAMESPACE_BEGIN(std)
+template<> inline void swap(CryptoPP::PolynomialMod2 &a, CryptoPP::PolynomialMod2 &b)
+{
+	a.swap(b);
+}
+NAMESPACE_END
+#endif
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(pop)
+#endif
+
+#endif
diff --git a/third_party/cryptoppwin/include/cryptopp/gfpcrypt.h b/third_party/cryptoppwin/include/cryptopp/gfpcrypt.h
new file mode 100644
index 00000000..741ee477
--- /dev/null
+++ b/third_party/cryptoppwin/include/cryptopp/gfpcrypt.h
@@ -0,0 +1,1036 @@
+// gfpcrypt.h - originally written and placed in the public domain by Wei Dai
+//              RFC6979 deterministic signatures added by Douglas Roark
+//              ECGDSA added by Jeffrey Walton
+
+/// \file gfpcrypt.h
+/// \brief Classes and functions for schemes based on Discrete Logs (DL) over GF(p)
+
+#ifndef CRYPTOPP_GFPCRYPT_H
+#define CRYPTOPP_GFPCRYPT_H
+
+#include "config.h"
+
+#if CRYPTOPP_MSC_VERSION
+# pragma warning(push)
+# pragma warning(disable: 4189 4231 4275)
+#endif
+
+#include "cryptlib.h"
+#include "pubkey.h"
+#include "integer.h"
+#include "modexppc.h"
+#include "algparam.h"
+#include "smartptr.h"
+#include "sha.h"
+#include "asn.h"
+#include "hmac.h"
+#include "misc.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters;
+
+/// \brief Integer-based GroupParameters specialization
+class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE DL_GroupParameters_IntegerBased : public ASN1CryptoMaterial >
+{
+    typedef DL_GroupParameters_IntegerBased ThisClass;
+
+public:
+    virtual ~DL_GroupParameters_IntegerBased() {}
+
+    /// \brief Initialize a group parameters over integers
+    /// \param params the group parameters
+    void Initialize(const DL_GroupParameters_IntegerBased ¶ms)
+        {Initialize(params.GetModulus(), params.GetSubgroupOrder(), params.GetSubgroupGenerator());}
+
+    /// \brief Create a group parameters over integers
+    /// \param rng a RandomNumberGenerator derived class
+    /// \param pbits the size of p, in bits
+    /// \details This function overload of Initialize() creates a new private key because it
+    ///  takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+    ///  then use one of the other Initialize() overloads.
+    void Initialize(RandomNumberGenerator &rng, unsigned int pbits)
+        {GenerateRandom(rng, MakeParameters("ModulusSize", (int)pbits));}
+
+    /// \brief Initialize a group parameters over integers
+    /// \param p the modulus
+    /// \param g the generator
+    void Initialize(const Integer &p, const Integer &g)
+        {SetModulusAndSubgroupGenerator(p, g); SetSubgroupOrder(ComputeGroupOrder(p)/2);}
+
+    /// \brief Initialize a group parameters over integers
+    /// \param p the modulus
+    /// \param q the subgroup order
+    /// \param g the generator
+    void Initialize(const Integer &p, const Integer &q, const Integer &g)
+        {SetModulusAndSubgroupGenerator(p, g); SetSubgroupOrder(q);}
+
+    // ASN1Object interface
+    void BERDecode(BufferedTransformation &bt);
+    void DEREncode(BufferedTransformation &bt) const;
+
+    /// \brief Generate a random key
+    /// \param rng a RandomNumberGenerator to produce keying material
+    /// \param alg additional initialization parameters
+    /// \details Recognised NameValuePairs are ModulusSize and
+    ///  SubgroupOrderSize (optional)
+    /// \throw KeyingErr if a key can't be generated or algorithm parameters
+    ///  are invalid
+    void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg);
+
+    /// \brief Get a named value
+    /// \param name the name of the object or value to retrieve
+    /// \param valueType reference to a variable that receives the value
+    /// \param pValue void pointer to a variable that receives the value
+    /// \return true if the value was retrieved, false otherwise
+    /// \details GetVoidValue() retrieves the value of name if it exists.
+    /// \note GetVoidValue() is an internal function and should be implemented
+    ///  by derived classes. Users should use one of the other functions instead.
+    /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
+    ///  GetRequiredParameter() and GetRequiredIntParameter()
+    bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
+
+    /// \brief Initialize or reinitialize this key
+    /// \param source NameValuePairs to assign
+    void AssignFrom(const NameValuePairs &source);
+
+    // DL_GroupParameters
+    const Integer & GetSubgroupOrder() const {return m_q;}
+    Integer GetGroupOrder() const {return GetFieldType() == 1 ? GetModulus()-Integer::One() : GetModulus()+Integer::One();}
+    bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const;
+    bool ValidateElement(unsigned int level, const Integer &element, const DL_FixedBasePrecomputation *precomp) const;
+
+    /// \brief Determine if subgroup membership check is fast
+    /// \return true or false
+    bool FastSubgroupCheckAvailable() const {return GetCofactor() == 2;}
+
+    /// \brief Encodes the element
+    /// \param reversible flag indicating the encoding format
+    /// \param element reference to the element to encode
+    /// \param encoded destination byte array for the encoded element
+    /// \details EncodeElement() must be implemented in a derived class.
+    /// \pre COUNTOF(encoded) == GetEncodedElementSize()
+    /// \sa GetEncodedElementSize(), DecodeElement(), Cygwin
+    ///  i386 crash at -O3
+    void EncodeElement(bool reversible, const Element &element, byte *encoded) const;
+
+    /// \brief Retrieve the encoded element's size
+    /// \param reversible flag indicating the encoding format
+    /// \return encoded element's size, in bytes
+    /// \details The format of the encoded element varies by the underlying
+    ///  type of the element and the reversible flag.
+    /// \sa EncodeElement(), DecodeElement()
+    unsigned int GetEncodedElementSize(bool reversible) const;
+
+    /// \brief Decodes the element
+    /// \param encoded byte array with the encoded element
+    /// \param checkForGroupMembership flag indicating if the element should be validated
+    /// \return Element after decoding
+    /// \details DecodeElement() must be implemented in a derived class.
+    /// \pre COUNTOF(encoded) == GetEncodedElementSize()
+    /// \sa GetEncodedElementSize(), EncodeElement()
+    Integer DecodeElement(const byte *encoded, bool checkForGroupMembership) const;
+
+    /// \brief Converts an element to an Integer
+    /// \param element the element to convert to an Integer
+    /// \return Element after converting to an Integer
+    /// \details ConvertElementToInteger() must be implemented in a derived class.
+    Integer ConvertElementToInteger(const Element &element) const
+        {return element;}
+
+    /// \brief Retrieve the maximum exponent for the group
+    /// \return the maximum exponent for the group
+    Integer GetMaxExponent() const;
+
+    /// \brief Retrieve the OID of the algorithm
+    /// \return OID of the algorithm
+    OID GetAlgorithmID() const;
+
+    /// \brief Retrieve the modulus for the group
+    /// \return the modulus for the group
+    virtual const Integer & GetModulus() const =0;
+
+    /// \brief Set group parameters
+    /// \param p the prime modulus
+    /// \param g the group generator
+    virtual void SetModulusAndSubgroupGenerator(const Integer &p, const Integer &g) =0;
+
+    /// \brief Set subgroup order
+    /// \param q the subgroup order
+    void SetSubgroupOrder(const Integer &q)
+        {m_q = q; ParametersChanged();}
+
+    static std::string CRYPTOPP_API StaticAlgorithmNamePrefix() {return "";}
+
+protected:
+    Integer ComputeGroupOrder(const Integer &modulus) const
+        {return modulus-(GetFieldType() == 1 ? 1 : -1);}
+
+    // GF(p) = 1, GF(p^2) = 2
+    virtual int GetFieldType() const =0;
+    virtual unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const;
+
+private:
+    Integer m_q;
+};
+
+/// \brief Integer-based GroupParameters default implementation
+/// \tparam GROUP_PRECOMP group parameters precomputation specialization
+/// \tparam BASE_PRECOMP base class precomputation specialization
+template  >
+class CRYPTOPP_NO_VTABLE DL_GroupParameters_IntegerBasedImpl : public DL_GroupParametersImpl
+{
+    typedef DL_GroupParameters_IntegerBasedImpl ThisClass;
+
+public:
+    typedef typename GROUP_PRECOMP::Element Element;
+
+    virtual ~DL_GroupParameters_IntegerBasedImpl() {}
+
+    // GeneratibleCryptoMaterial interface
+    bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
+        {return GetValueHelper(this, name, valueType, pValue).Assignable();}
+
+    void AssignFrom(const NameValuePairs &source)
+        {AssignFromHelper(this, source);}
+
+    // DL_GroupParameters
+    const DL_FixedBasePrecomputation & GetBasePrecomputation() const {return this->m_gpc;}
+    DL_FixedBasePrecomputation & AccessBasePrecomputation() {return this->m_gpc;}
+
+    // IntegerGroupParameters
+    /// \brief Retrieve the modulus for the group
+    /// \return the modulus for the group
+    const Integer & GetModulus() const {return this->m_groupPrecomputation.GetModulus();}
+
+    /// \brief Retrieves a reference to the group generator
+    /// \return const reference to the group generator
+    const Integer & GetGenerator() const {return this->m_gpc.GetBase(this->GetGroupPrecomputation());}
+
+    void SetModulusAndSubgroupGenerator(const Integer &p, const Integer &g)        // these have to be set together
+        {this->m_groupPrecomputation.SetModulus(p); this->m_gpc.SetBase(this->GetGroupPrecomputation(), g); this->ParametersChanged();}
+
+    // non-inherited
+    bool operator==(const DL_GroupParameters_IntegerBasedImpl &rhs) const
+        {return GetModulus() == rhs.GetModulus() && GetGenerator() == rhs.GetGenerator() && this->GetSubgroupOrder() == rhs.GetSubgroupOrder();}
+    bool operator!=(const DL_GroupParameters_IntegerBasedImpl &rhs) const
+        {return !operator==(rhs);}
+};
+
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_GroupParameters_IntegerBasedImpl;
+
+/// \brief GF(p) group parameters
+class CRYPTOPP_DLL DL_GroupParameters_GFP : public DL_GroupParameters_IntegerBasedImpl
+{
+public:
+    virtual ~DL_GroupParameters_GFP() {}
+
+    /// \brief Determines if an element is an identity
+    /// \param element element to check
+    /// \return true if the element is an identity, false otherwise
+    /// \details The identity element or or neutral element is a special element
+    ///  in a group that leaves other elements unchanged when combined with it.
+    /// \details IsIdentity() must be implemented in a derived class.
+    bool IsIdentity(const Integer &element) const {return element == Integer::One();}
+
+    /// \brief Exponentiates a base to multiple exponents
+    /// \param results an array of Elements
+    /// \param base the base to raise to the exponents
+    /// \param exponents an array of exponents
+    /// \param exponentsCount the number of exponents in the array
+    /// \details SimultaneousExponentiate() raises the base to each exponent in
+    ///  the exponents array and stores the result at the respective position in
+    ///  the results array.
+    /// \details SimultaneousExponentiate() must be implemented in a derived class.
+    /// \pre COUNTOF(results) == exponentsCount
+    /// \pre COUNTOF(exponents) == exponentsCount
+    void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const;
+
+    /// \brief Get a named value
+    /// \param name the name of the object or value to retrieve
+    /// \param valueType reference to a variable that receives the value
+    /// \param pValue void pointer to a variable that receives the value
+    /// \return true if the value was retrieved, false otherwise
+    /// \details GetVoidValue() retrieves the value of name if it exists.
+    /// \note GetVoidValue() is an internal function and should be implemented
+    ///  by derived classes. Users should use one of the other functions instead.
+    /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(),
+    ///  GetRequiredParameter() and GetRequiredIntParameter()
+    bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const
+    {
+        return GetValueHelper(this, name, valueType, pValue).Assignable();
+    }
+
+    // used by MQV
+    Element MultiplyElements(const Element &a, const Element &b) const;
+    Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const;
+
+protected:
+    int GetFieldType() const {return 1;}
+};
+
+/// \brief GF(p) group parameters that default to safe primes
+class CRYPTOPP_DLL DL_GroupParameters_GFP_DefaultSafePrime : public DL_GroupParameters_GFP
+{
+public:
+    typedef NoCofactorMultiplication DefaultCofactorOption;
+
+    virtual ~DL_GroupParameters_GFP_DefaultSafePrime() {}
+
+protected:
+    unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const {return modulusSize-1;}
+};
+
+/// ElGamal encryption for safe interop
+/// \sa On the
+///  (in)security of ElGamal in OpenPGP,
+///  Issue 1059,
+///  CVE-2021-40530
+/// \since Crypto++ 8.6
+class CRYPTOPP_DLL DL_GroupParameters_ElGamal : public DL_GroupParameters_GFP_DefaultSafePrime
+{
+public:
+    typedef NoCofactorMultiplication DefaultCofactorOption;
+
+    virtual ~DL_GroupParameters_ElGamal() {}
+
+	Integer GetMaxExponent() const
+	{
+		return GetSubgroupOrder()-1;
+	}
+};
+
+/// \brief GDSA algorithm
+/// \tparam T FieldElement type or class
+/// \details FieldElement T can be Integer, ECP or EC2N.
+template 
+class DL_Algorithm_GDSA : public DL_ElgamalLikeSignatureAlgorithm
+{
+public:
+    CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "DSA-1363";}
+
+    virtual ~DL_Algorithm_GDSA() {}
+
+    void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const
+    {
+        const Integer &q = params.GetSubgroupOrder();
+        r %= q;
+        Integer kInv = k.InverseMod(q);
+        s = (kInv * (x*r + e)) % q;
+        CRYPTOPP_ASSERT(!!r && !!s);
+    }
+
+    bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const
+    {
+        const Integer &q = params.GetSubgroupOrder();
+        if (r>=q || r<1 || s>=q || s<1)
+            return false;
+
+        Integer w = s.InverseMod(q);
+        Integer u1 = (e * w) % q;
+        Integer u2 = (r * w) % q;
+        // verify r == (g^u1 * y^u2 mod p) mod q
+        return r == params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(u1, u2)) % q;
+    }
+};
+
+/// \brief DSA signature algorithm based on RFC 6979
+/// \tparam T FieldElement type or class
+/// \tparam H HashTransformation derived class
+/// \details FieldElement T can be Integer, ECP or EC2N.
+/// \sa RFC 6979, Deterministic Usage of the
+///  Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)
+/// \since Crypto++ 6.0
+template 
+class DL_Algorithm_DSA_RFC6979 : public DL_Algorithm_GDSA, public DeterministicSignatureAlgorithm
+{
+public:
+    CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "DSA-RFC6979";}
+
+    virtual ~DL_Algorithm_DSA_RFC6979() {}
+
+    bool IsProbabilistic() const
+        {return false;}
+    bool IsDeterministic() const
+        {return true;}
+
+    // Deterministic K
+    Integer GenerateRandom(const Integer &x, const Integer &q, const Integer &e) const
+    {
+        static const byte zero = 0, one = 1;
+        const size_t qlen = q.BitCount();
+        const size_t rlen = BitsToBytes(qlen);
+
+        // Step (a) - formatted E(m)
+        SecByteBlock BH(e.MinEncodedSize());
+        e.Encode(BH, BH.size());
+        BH = bits2octets(BH, q);
+
+        // Step (a) - private key to byte array
+        SecByteBlock BX(STDMAX(rlen, x.MinEncodedSize()));
+        x.Encode(BX, BX.size());
+
+        // Step (b)
+        SecByteBlock V(H::DIGESTSIZE);
+        std::fill(V.begin(), V.begin()+H::DIGESTSIZE, one);
+
+        // Step (c)
+        SecByteBlock K(H::DIGESTSIZE);
+        std::fill(K.begin(), K.begin()+H::DIGESTSIZE, zero);
+
+        // Step (d)
+        m_hmac.SetKey(K, K.size());
+        m_hmac.Update(V, V.size());
+        m_hmac.Update(&zero, 1);
+        m_hmac.Update(BX, BX.size());
+        m_hmac.Update(BH, BH.size());
+        m_hmac.TruncatedFinal(K, K.size());
+
+        // Step (e)
+        m_hmac.SetKey(K, K.size());
+        m_hmac.Update(V, V.size());
+        m_hmac.TruncatedFinal(V, V.size());
+
+        // Step (f)
+        m_hmac.SetKey(K, K.size());
+        m_hmac.Update(V, V.size());
+        m_hmac.Update(&one, 1);
+        m_hmac.Update(BX, BX.size());
+        m_hmac.Update(BH, BH.size());
+        m_hmac.TruncatedFinal(K, K.size());
+
+        // Step (g)
+        m_hmac.SetKey(K, K.size());
+        m_hmac.Update(V, V.size());
+        m_hmac.TruncatedFinal(V, V.size());
+
+        Integer k;
+        SecByteBlock temp(rlen);
+        for (;;)
+        {
+            // We want qlen bits, but we support only hash functions with an output length
+            //   multiple of 8; hence, we will gather rlen bits, i.e., rolen octets.
+            size_t toff = 0;
+            while (toff < rlen)
+            {
+                m_hmac.Update(V, V.size());
+                m_hmac.TruncatedFinal(V, V.size());
+
+                size_t cc = STDMIN(V.size(), temp.size() - toff);
+                memcpy_s(temp+toff, temp.size() - toff, V, cc);
+                toff += cc;
+            }
+
+            k = bits2int(temp, qlen);
+            if (k > 0 && k < q)
+                break;
+
+            // k is not in the proper range; update K and V, and loop.
+            m_hmac.Update(V, V.size());
+            m_hmac.Update(&zero, 1);
+            m_hmac.TruncatedFinal(K, K.size());
+
+            m_hmac.SetKey(K, K.size());
+            m_hmac.Update(V, V.size());
+            m_hmac.TruncatedFinal(V, V.size());
+        }
+
+        return k;
+    }
+
+protected:
+
+    Integer bits2int(const SecByteBlock& bits, size_t qlen) const
+    {
+        Integer ret(bits, bits.size());
+        size_t blen = bits.size()*8;
+
+        if (blen > qlen)
+            ret >>= blen - qlen;
+
+        return ret;
+    }
+
+    // RFC 6979 support function. Takes an integer and converts it into bytes that
+    // are the same length as an elliptic curve's order.
+    SecByteBlock int2octets(const Integer& val, size_t rlen) const
+    {
+        SecByteBlock block(val.MinEncodedSize());
+        val.Encode(block, val.MinEncodedSize());
+
+        if (block.size() == rlen)
+            return block;
+
+        // The least significant bytes are the ones we need to preserve.
+        SecByteBlock t(rlen);
+        if (block.size() > rlen)
+        {
+            size_t offset = block.size() - rlen;
+            std::memcpy(t, block + offset, rlen);
+        }
+        else // block.size() < rlen
+        {
+            size_t offset = rlen - block.size();
+            std::memset(t, '\x00', offset);
+            std::memcpy(t + offset, block, rlen - offset);
+        }
+
+        return t;
+    }
+
+    // Turn a stream of bits into a set of bytes with the same length as an elliptic
+    // curve's order.
+    SecByteBlock bits2octets(const SecByteBlock& in, const Integer& q) const
+    {
+        Integer b2 = bits2int(in, q.BitCount());
+        Integer b1 = b2 - q;
+        return int2octets(b1.IsNegative() ? b2 : b1, q.ByteCount());
+    }
+
+private:
+    mutable H m_hash;
+    mutable HMAC m_hmac;
+};
+
+/// \brief German Digital Signature Algorithm
+/// \tparam T FieldElement type or class
+/// \details FieldElement T can be Integer, ECP or EC2N.
+/// \details The Digital Signature Scheme ECGDSA does not define the algorithm over integers. Rather, the
+///  signature algorithm is only defined over elliptic curves. However, the library design is such that the
+///  generic algorithm reside in gfpcrypt.h.
+/// \sa Erwin Hess, Marcus Schafheutle, and Pascale Serf 
+///  The Digital Signature Scheme ECGDSA (October 24, 2006)
+template 
+class DL_Algorithm_GDSA_ISO15946 : public DL_ElgamalLikeSignatureAlgorithm
+{
+public:
+    CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "GDSA-ISO15946";}
+
+    virtual ~DL_Algorithm_GDSA_ISO15946() {}
+
+    void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const
+    {
+        const Integer &q = params.GetSubgroupOrder();
+        // r = x(k * G) mod q
+        r = params.ConvertElementToInteger(params.ExponentiateBase(k)) % q;
+        // s = (k * r - h(m)) * d_A mod q
+        s = (k * r - e) * x % q;
+        CRYPTOPP_ASSERT(!!r && !!s);
+    }
+
+    bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const
+    {
+        const Integer &q = params.GetSubgroupOrder();
+        if (r>=q || r<1 || s>=q || s<1)
+            return false;
+
+        const Integer& rInv = r.InverseMod(q);
+        const Integer u1 = (rInv * e) % q;
+        const Integer u2 = (rInv * s) % q;
+        // verify x(G^u1 + P_A^u2) mod q
+        return r == params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(u1, u2)) % q;
+    }
+};
+
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979;
+CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979;
+
+/// \brief NR algorithm
+/// \tparam T FieldElement type or class
+/// \details FieldElement T can be Integer, ECP or EC2N.
+template 
+class DL_Algorithm_NR : public DL_ElgamalLikeSignatureAlgorithm
+{
+public:
+    CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "NR";}
+
+    virtual ~DL_Algorithm_NR() {}
+
+    void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const
+    {
+        const Integer &q = params.GetSubgroupOrder();
+        r = (r + e) % q;
+        s = (k - x*r) % q;
+        CRYPTOPP_ASSERT(!!r);
+    }
+
+    bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const
+    {
+        const Integer &q = params.GetSubgroupOrder();
+        if (r>=q || r<1 || s>=q)
+            return false;
+
+        // check r == (m_g^s * m_y^r + m) mod m_q
+        return r == (params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(s, r)) + e) % q;
+    }
+};
+
+/// \brief Discrete Log (DL) public key in GF(p) groups
+/// \tparam GP GroupParameters derived class
+/// \details DSA public key format is defined in 7.3.3 of RFC 2459. The    private key format is defined in 12.9 of PKCS #11 v2.10.
+template 
+class DL_PublicKey_GFP : public DL_PublicKeyImpl
+{
+public:
+    virtual ~DL_PublicKey_GFP() {}
+
+    /// \brief Initialize a public key over GF(p)
+    /// \param params the group parameters
+    /// \param y the public element
+    void Initialize(const DL_GroupParameters_IntegerBased ¶ms, const Integer &y)
+        {this->AccessGroupParameters().Initialize(params); this->SetPublicElement(y);}
+
+    /// \brief Initialize a public key over GF(p)
+    /// \param p the modulus
+    /// \param g the generator
+    /// \param y the public element
+    void Initialize(const Integer &p, const Integer &g, const Integer &y)
+        {this->AccessGroupParameters().Initialize(p, g); this->SetPublicElement(y);}
+
+    /// \brief Initialize a public key over GF(p)
+    /// \param p the modulus
+    /// \param q the subgroup order
+    /// \param g the generator
+    /// \param y the public element
+    void Initialize(const Integer &p, const Integer &q, const Integer &g, const Integer &y)
+        {this->AccessGroupParameters().Initialize(p, q, g); this->SetPublicElement(y);}
+
+    // X509PublicKey
+    void BERDecodePublicKey(BufferedTransformation &bt, bool, size_t)
+        {this->SetPublicElement(Integer(bt));}
+    void DEREncodePublicKey(BufferedTransformation &bt) const
+        {this->GetPublicElement().DEREncode(bt);}
+};
+
+/// \brief Discrete Log (DL) private key in GF(p) groups
+/// \tparam GP GroupParameters derived class
+template 
+class DL_PrivateKey_GFP : public DL_PrivateKeyImpl
+{
+public:
+    virtual ~DL_PrivateKey_GFP();
+
+    /// \brief Create a private key
+    /// \param rng a RandomNumberGenerator derived class
+    /// \param modulusBits the size of the modulus, in bits
+    /// \details This function overload of Initialize() creates a new private key because it
+    ///  takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+    ///  then use one of the other Initialize() overloads.
+    void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits)
+        {this->GenerateRandomWithKeySize(rng, modulusBits);}
+
+    /// \brief Create a private key
+    /// \param rng a RandomNumberGenerator derived class
+    /// \param p the modulus
+    /// \param g the generator
+    /// \details This function overload of Initialize() creates a new private key because it
+    ///  takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+    ///  then use one of the other Initialize() overloads.
+    void Initialize(RandomNumberGenerator &rng, const Integer &p, const Integer &g)
+        {this->GenerateRandom(rng, MakeParameters("Modulus", p)("SubgroupGenerator", g));}
+
+    /// \brief Create a private key
+    /// \param rng a RandomNumberGenerator derived class
+    /// \param p the modulus
+    /// \param q the subgroup order
+    /// \param g the generator
+    /// \details This function overload of Initialize() creates a new private key because it
+    ///  takes a RandomNumberGenerator() as a parameter. If you have an existing keypair,
+    ///  then use one of the other Initialize() overloads.
+    void Initialize(RandomNumberGenerator &rng, const Integer &p, const Integer &q, const Integer &g)
+        {this->GenerateRandom(rng, MakeParameters("Modulus", p)("SubgroupOrder", q)("SubgroupGenerator", g));}
+
+    /// \brief Initialize a private key over GF(p)
+    /// \param params the group parameters
+    /// \param x the private exponent
+    void Initialize(const DL_GroupParameters_IntegerBased ¶ms, const Integer &x)
+        {this->AccessGroupParameters().Initialize(params); this->SetPrivateExponent(x);}
+
+    /// \brief Initialize a private key over GF(p)
+    /// \param p the modulus
+    /// \param g the generator
+    /// \param x the private exponent
+    void Initialize(const Integer &p, const Integer &g, const Integer &x)
+        {this->AccessGroupParameters().Initialize(p, g); this->SetPrivateExponent(x);}
+
+    /// \brief Initialize a private key over GF(p)
+    /// \param p the modulus
+    /// \param q the subgroup order
+    /// \param g the generator
+    /// \param x the private exponent
+    void Initialize(const Integer &p, const Integer &q, const Integer &g, const Integer &x)
+        {this->AccessGroupParameters().Initialize(p, q, g); this->SetPrivateExponent(x);}
+};
+
+// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499
+template 
+DL_PrivateKey_GFP::~DL_PrivateKey_GFP() {}
+
+/// \brief Discrete Log (DL) signing/verification keys in GF(p) groups
+struct DL_SignatureKeys_GFP
+{
+    typedef DL_GroupParameters_GFP GroupParameters;
+    typedef DL_PublicKey_GFP PublicKey;
+    typedef DL_PrivateKey_GFP PrivateKey;
+};
+
+/// \brief Discrete Log (DL) encryption/decryption keys in GF(p) groups
+struct DL_CryptoKeys_GFP
+{
+    typedef DL_GroupParameters_GFP_DefaultSafePrime GroupParameters;
+    typedef DL_PublicKey_GFP PublicKey;
+    typedef DL_PrivateKey_GFP PrivateKey;
+};
+
+/// ElGamal encryption keys for safe interop
+/// \sa On the
+///  (in)security of ElGamal in OpenPGP,
+///  Issue 1059,
+///  CVE-2021-40530
+/// \since Crypto++ 8.6
+struct DL_CryptoKeys_ElGamal
+{
+    typedef DL_GroupParameters_ElGamal GroupParameters;
+    typedef DL_PublicKey_GFP PublicKey;
+    typedef DL_PrivateKey_GFP PrivateKey;
+};
+
+/// \brief DSA signature scheme
+/// \tparam H HashTransformation derived class
+/// \sa DSA-1363
+/// \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2
+template 
+struct GDSA : public DL_SS<
+    DL_SignatureKeys_GFP,
+    DL_Algorithm_GDSA,
+    DL_SignatureMessageEncodingMethod_DSA,
+    H>
+{
+};
+
+/// \brief NR signature scheme
+/// \tparam H HashTransformation derived class
+/// \sa NR
+template 
+struct NR : public DL_SS<
+    DL_SignatureKeys_GFP,
+    DL_Algorithm_NR,
+    DL_SignatureMessageEncodingMethod_NR,
+    H>
+{
+};
+
+/// \brief DSA group parameters
+/// \details These are GF(p) group parameters that are allowed by the DSA standard
+/// \sa DL_Keys_DSA
+/// \since Crypto++ 1.0
+class CRYPTOPP_DLL DL_GroupParameters_DSA : public DL_GroupParameters_GFP
+{
+public:
+    virtual ~DL_GroupParameters_DSA() {}
+
+    /// \brief Check the group for errors
+    /// \param rng RandomNumberGenerator for objects which use randomized testing
+    /// \param level level of thoroughness
+    /// \return true if the tests succeed, false otherwise
+    /// \details ValidateGroup() also checks that the lengths of p and q are allowed
+    ///  by the DSA standard.
+    /// \details There are four levels of thoroughness:
+    ///  
    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other operations correctly + ///
  • 2 - ensure this object will function correctly, and perform reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may take a long time + ///
+ /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can be used for level 0. + /// Level 1 may not check for weak keys and such. Levels 2 and 3 are recommended. + bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const; + + /// \brief Generate a random key or crypto parameters + /// \param rng a RandomNumberGenerator to produce keying material + /// \param alg additional initialization parameters + /// \details NameValuePairs can be ModulusSize alone; or Modulus, SubgroupOrder, and + /// SubgroupGenerator. ModulusSize must be between DSA::MIN_PRIME_LENGTH and + /// DSA::MAX_PRIME_LENGTH, and divisible by DSA::PRIME_LENGTH_MULTIPLE. + /// \details An example of changing the modulus size using NameValuePairs is shown below. + ///
+    ///  AlgorithmParameters params = MakeParameters
+    ///    (Name::ModulusSize(), 2048);
+    ///
+    ///  DL_GroupParameters_DSA groupParams;
+    ///  groupParams.GenerateRandom(prng, params);
+    /// 
+ /// \throw KeyingErr if a key can't be generated or algorithm parameters are invalid. + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + /// \brief Check the prime length for errors + /// \param pbits number of bits in the prime number + /// \return true if the tests succeed, false otherwise + static bool CRYPTOPP_API IsValidPrimeLength(unsigned int pbits) + {return pbits >= MIN_PRIME_LENGTH && pbits <= MAX_PRIME_LENGTH && pbits % PRIME_LENGTH_MULTIPLE == 0;} + + /// \brief DSA prime length + enum { + /// \brief Minimum prime length + MIN_PRIME_LENGTH = 1024, + /// \brief Maximum prime length + MAX_PRIME_LENGTH = 3072, + /// \brief Prime length multiple + PRIME_LENGTH_MULTIPLE = 1024 + }; +}; + +template +class DSA2; + +/// \brief DSA keys +/// \sa DL_GroupParameters_DSA +/// \since Crypto++ 1.0 +struct DL_Keys_DSA +{ + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_WithSignaturePairwiseConsistencyTest, DSA2 > PrivateKey; +}; + +/// \brief DSA signature scheme +/// \tparam H HashTransformation derived class +/// \details The class is named DSA2 instead of DSA for backwards compatibility because +/// DSA was a non-template class. +/// \details DSA default method GenerateRandom uses a 2048-bit modulus and a 224-bit subgoup by default. +/// The modulus can be changed using the following code: +///
+///  DSA::PrivateKey privateKey;
+///  privateKey.GenerateRandomWithKeySize(prng, 2048);
+/// 
+/// \details The subgroup order can be changed using the following code: +///
+///  AlgorithmParameters params = MakeParameters
+///    (Name::ModulusSize(), 2048)
+///    (Name::SubgroupOrderSize(), 256);
+///
+///  DSA::PrivateKey privateKey;
+///  privateKey.GenerateRandom(prng, params);
+/// 
+/// \sa DSA, as specified in FIPS 186-3, +/// Digital Signature Algorithm on the wiki, and +/// NameValuePairs on the wiki. +/// \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2, Crypto++ 6.1 for 2048-bit modulus. +template +class DSA2 : public DL_SS< + DL_Keys_DSA, + DL_Algorithm_GDSA, + DL_SignatureMessageEncodingMethod_DSA, + H, + DSA2 > +{ +public: + static std::string CRYPTOPP_API StaticAlgorithmName() {return "DSA/" + (std::string)H::StaticAlgorithmName();} +}; + +/// \brief DSA deterministic signature scheme +/// \tparam H HashTransformation derived class +/// \sa DSA-1363 +/// \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2 +template +struct DSA_RFC6979 : public DL_SS< + DL_SignatureKeys_GFP, + DL_Algorithm_DSA_RFC6979, + DL_SignatureMessageEncodingMethod_DSA, + H, + DSA_RFC6979 > +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("DSA-RFC6979/") + H::StaticAlgorithmName();} +}; + +/// DSA with SHA-1, typedef'd for backwards compatibility +typedef DSA2 DSA; + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_GFP; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_GFP; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest, DSA2 >; + +/// \brief P1363 based XOR Encryption Method +/// \tparam MAC MessageAuthenticationCode derived class used for MAC computation +/// \tparam DHAES_MODE flag indicating DHAES mode +/// \tparam LABEL_OCTETS flag indicating the label is octet count +/// \details DL_EncryptionAlgorithm_Xor is based on an early P1363 draft, which itself appears to be based on an +/// early Certicom SEC-1 draft (or an early SEC-1 draft was based on a P1363 draft). Crypto++ 4.2 used it in its Integrated +/// Ecryption Schemes with NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you need this method for Crypto++ 4.2 compatibility, then use the ECIES template class with +/// NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you need this method for Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the ECIES template class with +/// NoCofactorMultiplication, DHAES_MODE=true and LABEL_OCTETS=false. +/// \details Bouncy Castle 1.54 and Botan 1.11 compatibility are the default template parameters. +/// \since Crypto++ 4.0 +template +class DL_EncryptionAlgorithm_Xor : public DL_SymmetricEncryptionAlgorithm +{ +public: + virtual ~DL_EncryptionAlgorithm_Xor() {} + + bool ParameterSupported(const char *name) const {return strcmp(name, Name::EncodingParameters()) == 0;} + size_t GetSymmetricKeyLength(size_t plaintextLength) const + {return plaintextLength + static_cast(MAC::DEFAULT_KEYLENGTH);} + size_t GetSymmetricCiphertextLength(size_t plaintextLength) const + {return plaintextLength + static_cast(MAC::DIGESTSIZE);} + size_t GetMaxSymmetricPlaintextLength(size_t ciphertextLength) const + {return SaturatingSubtract(ciphertextLength, static_cast(MAC::DIGESTSIZE));} + void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters) const + { + CRYPTOPP_UNUSED(rng); + const byte *cipherKey = NULLPTR, *macKey = NULLPTR; + if (DHAES_MODE) + { + macKey = key; + cipherKey = key + MAC::DEFAULT_KEYLENGTH; + } + else + { + cipherKey = key; + macKey = key + plaintextLength; + } + + ConstByteArrayParameter encodingParameters; + parameters.GetValue(Name::EncodingParameters(), encodingParameters); + + if (plaintextLength) // Coverity finding + xorbuf(ciphertext, plaintext, cipherKey, plaintextLength); + + MAC mac(macKey); + mac.Update(ciphertext, plaintextLength); + mac.Update(encodingParameters.begin(), encodingParameters.size()); + if (DHAES_MODE) + { + byte L[8]; + PutWord(false, BIG_ENDIAN_ORDER, L, (LABEL_OCTETS ? word64(encodingParameters.size()) : 8 * word64(encodingParameters.size()))); + mac.Update(L, 8); + } + mac.Final(ciphertext + plaintextLength); + } + DecodingResult SymmetricDecrypt(const byte *key, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters) const + { + size_t plaintextLength = GetMaxSymmetricPlaintextLength(ciphertextLength); + const byte *cipherKey, *macKey; + if (DHAES_MODE) + { + macKey = key; + cipherKey = key + MAC::DEFAULT_KEYLENGTH; + } + else + { + cipherKey = key; + macKey = key + plaintextLength; + } + + ConstByteArrayParameter encodingParameters; + parameters.GetValue(Name::EncodingParameters(), encodingParameters); + + MAC mac(macKey); + mac.Update(ciphertext, plaintextLength); + mac.Update(encodingParameters.begin(), encodingParameters.size()); + if (DHAES_MODE) + { + byte L[8]; + PutWord(false, BIG_ENDIAN_ORDER, L, (LABEL_OCTETS ? word64(encodingParameters.size()) : 8 * word64(encodingParameters.size()))); + mac.Update(L, 8); + } + if (!mac.Verify(ciphertext + plaintextLength)) + return DecodingResult(); + + if (plaintextLength) // Coverity finding + xorbuf(plaintext, ciphertext, cipherKey, plaintextLength); + + return DecodingResult(plaintextLength); + } +}; + +/// \brief P1363 based Key Derivation Method +/// \tparam T FieldElement type or class +/// \tparam DHAES_MODE flag indicating DHAES mode +/// \tparam KDF key derivation function +/// \details FieldElement T can be Integer, ECP or EC2N. +template +class DL_KeyDerivationAlgorithm_P1363 : public DL_KeyDerivationAlgorithm +{ +public: + virtual ~DL_KeyDerivationAlgorithm_P1363() {} + + bool ParameterSupported(const char *name) const {return strcmp(name, Name::KeyDerivationParameters()) == 0;} + void Derive(const DL_GroupParameters ¶ms, byte *derivedKey, size_t derivedLength, const T &agreedElement, const T &ephemeralPublicKey, const NameValuePairs ¶meters) const + { + SecByteBlock agreedSecret; + if (DHAES_MODE) + { + agreedSecret.New(params.GetEncodedElementSize(true) + params.GetEncodedElementSize(false)); + params.EncodeElement(true, ephemeralPublicKey, agreedSecret); + params.EncodeElement(false, agreedElement, agreedSecret + params.GetEncodedElementSize(true)); + } + else + { + agreedSecret.New(params.GetEncodedElementSize(false)); + params.EncodeElement(false, agreedElement, agreedSecret); + } + + ConstByteArrayParameter derivationParameters; + parameters.GetValue(Name::KeyDerivationParameters(), derivationParameters); + KDF::DeriveKey(derivedKey, derivedLength, agreedSecret, agreedSecret.size(), derivationParameters.begin(), derivationParameters.size()); + } +}; + +/// \brief Discrete Log Integrated Encryption Scheme +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \tparam HASH HashTransformation derived class used for key drivation and MAC computation +/// \tparam DHAES_MODE flag indicating if the MAC includes addition context parameters such as the label +/// \tparam LABEL_OCTETS flag indicating if the label size is specified in octets or bits +/// \details DLIES is an Integer based Integrated Encryption Scheme (IES). The scheme combines a Key Encapsulation Method (KEM) +/// with a Data Encapsulation Method (DEM) and a MAC tag. The scheme is +/// IND-CCA2, which is a strong notion of security. +/// You should prefer an Integrated Encryption Scheme over homegrown schemes. +/// \details The library's original implementation is based on an early P1363 draft, which itself appears to be based on an early Certicom +/// SEC-1 draft (or an early SEC-1 draft was based on a P1363 draft). Crypto++ 4.2 used the early draft in its Integrated Ecryption +/// Schemes with NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you desire an Integrated Encryption Scheme with Crypto++ 4.2 compatibility, then use the DLIES template class with +/// NoCofactorMultiplication, DHAES_MODE=false and LABEL_OCTETS=true. +/// \details If you desire an Integrated Encryption Scheme with Bouncy Castle 1.54 and Botan 1.11 compatibility, then use the DLIES +/// template class with NoCofactorMultiplication, DHAES_MODE=true and LABEL_OCTETS=false. +/// \details The default template parameters ensure compatibility with Bouncy Castle 1.54 and Botan 1.11. The combination of +/// IncompatibleCofactorMultiplication and DHAES_MODE=true is recommended for best efficiency and security. +/// SHA1 is used for compatibility reasons, but it can be changed if desired. SHA-256 or another hash will likely improve the +/// security provided by the MAC. The hash is also used in the key derivation function as a PRF. +/// \details Below is an example of constructing a Crypto++ 4.2 compatible DLIES encryptor and decryptor. +///
+///    AutoSeededRandomPool prng;
+///    DL_PrivateKey_GFP key;
+///    key.Initialize(prng, 2048);
+///
+///    DLIES::Decryptor decryptor(key);
+///    DLIES::Encryptor encryptor(decryptor);
+/// 
+/// \sa ECIES, Discrete Log Integrated Encryption Scheme (DLIES), +/// Martínez, Encinas, and Ávila's A Survey of the Elliptic +/// Curve Integrated Encryption Schemes +/// \since Crypto++ 4.0, Crypto++ 5.7 for Bouncy Castle and Botan compatibility +template +struct DLIES + : public DL_ES< + DL_CryptoKeys_GFP, + DL_KeyAgreementAlgorithm_DH, + DL_KeyDerivationAlgorithm_P1363 >, + DL_EncryptionAlgorithm_Xor, DHAES_MODE, LABEL_OCTETS>, + DLIES<> > +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return "DLIES";} // TODO: fix this after name is standardized +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/gost.h b/third_party/cryptoppwin/include/cryptopp/gost.h new file mode 100644 index 00000000..87082a11 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/gost.h @@ -0,0 +1,66 @@ +// gost.h - originally written and placed in the public domain by Wei Dai + +/// \file gost.h +/// \brief Classes for the GIST block cipher + +#ifndef CRYPTOPP_GOST_H +#define CRYPTOPP_GOST_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief GOST block cipher information +/// \since Crypto++ 2.1 +struct GOST_Info : public FixedBlockSize<8>, public FixedKeyLength<32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "GOST";} +}; + +/// \brief GOST block cipher +/// \sa GOST +/// \since Crypto++ 2.1 +class GOST : public GOST_Info, public BlockCipherDocumentation +{ + /// \brief GOST block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + static void PrecalculateSTable(); + + static const byte sBox[8][16]; + static volatile bool sTableCalculated; + static word32 sTable[4][256]; + + FixedSizeSecBlock m_key; + }; + + /// \brief GOST block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief GOST block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef GOST::Encryption GOSTEncryption; +typedef GOST::Decryption GOSTDecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/gzip.h b/third_party/cryptoppwin/include/cryptopp/gzip.h new file mode 100644 index 00000000..437a5209 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/gzip.h @@ -0,0 +1,144 @@ +// gzip.h - originally written and placed in the public domain by Wei Dai + +/// \file gzip.h +/// \brief GZIP compression and decompression (RFC 1952) + +#ifndef CRYPTOPP_GZIP_H +#define CRYPTOPP_GZIP_H + +#include "cryptlib.h" +#include "zdeflate.h" +#include "zinflate.h" +#include "crc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief GZIP Compression (RFC 1952) +class Gzip : public Deflator +{ +public: + /// \brief Construct a Gzip compressor + /// \param attachment an attached transformation + /// \param deflateLevel the deflate level + /// \param log2WindowSize the window size + /// \param detectUncompressible flag to detect if data is compressible + /// \details detectUncompressible makes it faster to process uncompressible files, but + /// if a file has both compressible and uncompressible parts, it may fail to compress + /// some of the compressible parts. + Gzip(BufferedTransformation *attachment=NULLPTR, unsigned int deflateLevel=DEFAULT_DEFLATE_LEVEL, unsigned int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE, bool detectUncompressible=true) + : Deflator(attachment, deflateLevel, log2WindowSize, detectUncompressible), m_totalLen(0), m_filetime(0) { } + + /// \brief Construct a Gzip compressor + /// \param parameters a set of NameValuePairs to initialize this object + /// \param attachment an attached transformation + /// \details Possible parameter names: Log2WindowSize, DeflateLevel, DetectUncompressible + Gzip(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULLPTR) + : Deflator(parameters, attachment), m_totalLen(0), m_filetime(0) + { + IsolatedInitialize(parameters); + } + + /// \param filetime the filetime to set in the header. The application is responsible for setting it. + void SetFiletime(word32 filetime) { m_filetime = filetime; } + + /// \param filename the original filename to set in the header. The application is responsible for setting it. + /// RFC 1952 requires a ISO/IEC 8859-1 encoding. + /// \param throwOnEncodingError if throwOnEncodingError is true, then the filename is checked to ensure it is + /// ISO/IEC 8859-1 encoded. If the filename does not adhere to ISO/IEC 8859-1, then a InvalidDataFormat + /// is thrown. If throwOnEncodingError is false then the filename is not checked. + void SetFilename(const std::string& filename, bool throwOnEncodingError = false); + + /// \param comment the comment to set in the header. The application is responsible for setting it. + /// RFC 1952 requires a ISO/IEC 8859-1 encoding. + /// \param throwOnEncodingError if throwOnEncodingError is true, then the comment is checked to ensure it is + /// ISO/IEC 8859-1 encoded. If the comment does not adhere to ISO/IEC 8859-1, then a InvalidDataFormat + /// is thrown. If throwOnEncodingError is false then the comment is not checked. + void SetComment(const std::string& comment, bool throwOnEncodingError = false); + + void IsolatedInitialize(const NameValuePairs ¶meters); + +protected: + enum {MAGIC1=0x1f, MAGIC2=0x8b, // flags for the header + DEFLATED=8, FAST=4, SLOW=2}; + + enum FLAG_MASKS { + FILENAME=8, COMMENTS=16}; + + void WritePrestreamHeader(); + void ProcessUncompressedData(const byte *string, size_t length); + void WritePoststreamTail(); + + word32 m_totalLen; + CRC32 m_crc; + + word32 m_filetime; + std::string m_filename; + std::string m_comment; +}; + +/// \brief GZIP Decompression (RFC 1952) +class Gunzip : public Inflator +{ +public: + typedef Inflator::Err Err; + + /// \brief Exception thrown when a header decoding error occurs + class HeaderErr : public Err {public: HeaderErr() : Err(INVALID_DATA_FORMAT, "Gunzip: header decoding error") {}}; + /// \brief Exception thrown when the tail is too short + class TailErr : public Err {public: TailErr() : Err(INVALID_DATA_FORMAT, "Gunzip: tail too short") {}}; + /// \brief Exception thrown when a CRC error occurs + class CrcErr : public Err {public: CrcErr() : Err(DATA_INTEGRITY_CHECK_FAILED, "Gunzip: CRC check error") {}}; + /// \brief Exception thrown when a length error occurs + class LengthErr : public Err {public: LengthErr() : Err(DATA_INTEGRITY_CHECK_FAILED, "Gunzip: length check error") {}}; + + /// \brief Construct a Gunzip decompressor + /// \param attachment an attached transformation + /// \param repeat decompress multiple compressed streams in series + /// \param autoSignalPropagation 0 to turn off MessageEnd signal + Gunzip(BufferedTransformation *attachment = NULLPTR, bool repeat = false, int autoSignalPropagation = -1); + + /// \return the filetime of the stream as set in the header. The application is responsible for setting it on the decompressed file. + word32 GetFiletime() const { return m_filetime; } + + /// \return the filename of the stream as set in the header. The application is responsible for setting it on the decompressed file. + /// \param throwOnEncodingError if throwOnEncodingError is true, then the filename is checked to ensure it is + /// ISO/IEC 8859-1 encoded. If the filename does not adhere to ISO/IEC 8859-1, then a InvalidDataFormat is thrown. + /// If throwOnEncodingError is false then the filename is not checked. + const std::string& GetFilename(bool throwOnEncodingError = false) const; + + /// \return the comment of the stream as set in the header. + /// \param throwOnEncodingError if throwOnEncodingError is true, then the comment is checked to ensure it is + /// ISO/IEC 8859-1 encoded. If the comment does not adhere to ISO/IEC 8859-1, then a InvalidDataFormat is thrown. + /// If throwOnEncodingError is false then the comment is not checked. + const std::string& GetComment(bool throwOnEncodingError = false) const; + +protected: + enum { + /// \brief First header magic value + MAGIC1=0x1f, + /// \brief Second header magic value + MAGIC2=0x8b, + /// \brief Deflated flag + DEFLATED=8 + }; + + enum FLAG_MASKS { + CONTINUED=2, EXTRA_FIELDS=4, FILENAME=8, COMMENTS=16, ENCRYPTED=32}; + + unsigned int MaxPrestreamHeaderSize() const {return 1024;} + void ProcessPrestreamHeader(); + void ProcessDecompressedData(const byte *string, size_t length); + unsigned int MaxPoststreamTailSize() const {return 8;} + void ProcessPoststreamTail(); + + word32 m_length; + CRC32 m_crc; + + word32 m_filetime; + std::string m_filename; + std::string m_comment; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/hashfwd.h b/third_party/cryptoppwin/include/cryptopp/hashfwd.h new file mode 100644 index 00000000..5e1309da --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/hashfwd.h @@ -0,0 +1,38 @@ +// hashfwd.h - written and placed in the public domain by Jeffrey Walton + +/// \file hashfwd.h +/// \brief Forward declarations for hash functions used in signature encoding methods + +#ifndef CRYPTOPP_HASHFWD_H +#define CRYPTOPP_HASHFWD_H + +#include "config.h" + +NAMESPACE_BEGIN(CryptoPP) + +class SHA1; +class SHA224; +class SHA256; +class SHA384; +class SHA512; + +class SHA3_256; +class SHA3_384; +class SHA3_512; + +class SHAKE128; +class SHAKE256; + +class Tiger; +class RIPEMD128; +class RIPEMD160; +class Whirlpool; + +namespace Weak1 { + class MD2; + class MD5; +} + +NAMESPACE_END + +#endif // CRYPTOPP_HASHFWD_H diff --git a/third_party/cryptoppwin/include/cryptopp/hc128.h b/third_party/cryptoppwin/include/cryptopp/hc128.h new file mode 100644 index 00000000..a35352c9 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/hc128.h @@ -0,0 +1,67 @@ +// hc128.h - written and placed in the public domain by Jeffrey Walton +// based on public domain code by Hongjun Wu. +// +// The reference materials and source files are available at +// The eSTREAM Project, http://www.ecrypt.eu.org/stream/e2-hc128.html. + +/// \file hc128.h +/// \brief Classes for HC-128 stream cipher +/// \sa The +/// eSTREAM Project | HC-128 and +/// Crypto++ Wiki | HC-128. +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_HC128_H +#define CRYPTOPP_HC128_H + +#include "strciphr.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief HC-128 stream cipher information +/// \since Crypto++ 8.0 +struct HC128Info : public FixedKeyLength<16, SimpleKeyingInterface::UNIQUE_IV, 16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "HC-128"; } +}; + +/// \brief HC-128 stream cipher implementation +/// \since Crypto++ 8.0 +class HC128Policy : public AdditiveCipherConcretePolicy, public HC128Info +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + bool CanOperateKeystream() const { return true; } + bool CipherIsRandomAccess() const { return false; } + + void GenerateKeystream(word32* keystream); + void SetupUpdate(); + +private: + FixedSizeSecBlock m_X; + FixedSizeSecBlock m_Y; + FixedSizeSecBlock m_key; + FixedSizeSecBlock m_iv; + word32 m_T[1024]; + word32 m_ctr; +}; + +/// \brief HC-128 stream cipher +/// \details HC-128 is a stream cipher developed by Hongjun Wu. HC-128 is one of the +/// final four Profile 1 (software) ciphers selected for the eSTREAM portfolio. +/// \sa The +/// eSTREAM Project | HC-128 and +/// Crypto++ Wiki | HC-128. +/// \since Crypto++ 8.0 +struct HC128 : public HC128Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, HC128Info> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_HC128_H diff --git a/third_party/cryptoppwin/include/cryptopp/hc256.h b/third_party/cryptoppwin/include/cryptopp/hc256.h new file mode 100644 index 00000000..169d0b95 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/hc256.h @@ -0,0 +1,69 @@ +// hc256.h - written and placed in the public domain by Jeffrey Walton +// based on public domain code by Hongjun Wu. +// +// The reference materials and source files are available at +// The eSTREAM Project, http://www.ecrypt.eu.org/stream/hc256.html. + +/// \file hc256.h +/// \brief Classes for HC-256 stream cipher +/// \sa The +/// eSTREAM Project | HC-256 and +/// Crypto++ Wiki | HC-128. +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_HC256_H +#define CRYPTOPP_HC256_H + +#include "strciphr.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief HC-256 stream cipher information +/// \since Crypto++ 8.0 +struct HC256Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "HC-256"; } +}; + +/// \brief HC-256 stream cipher implementation +/// \since Crypto++ 8.0 +class HC256Policy : public AdditiveCipherConcretePolicy, public HC256Info +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + bool CanOperateKeystream() const { return true; } + bool CipherIsRandomAccess() const { return false; } + + word32 H1(word32 u); + word32 H2(word32 u); + + void GenerateKeystream(word32* keystream); + word32 Generate(); + +private: + FixedSizeSecBlock m_key; + FixedSizeSecBlock m_iv; + word32 m_P[1024]; + word32 m_Q[1024]; + word32 m_ctr; +}; + +/// \brief HC-256 stream cipher +/// \details HC-256 is a stream cipher developed by Hongjun Wu. HC-256 is the +/// successor to HC-128 from the eSTREAM project. +/// \sa The +/// eSTREAM Project | HC-256 and +/// Crypto++ Wiki | HC-128. +/// \since Crypto++ 8.0 +struct HC256 : public HC256Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, HC256Info> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_HC256_H diff --git a/third_party/cryptoppwin/include/cryptopp/hex.h b/third_party/cryptoppwin/include/cryptopp/hex.h new file mode 100644 index 00000000..bcf2bd03 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/hex.h @@ -0,0 +1,50 @@ +// hex.h - originally written and placed in the public domain by Wei Dai + +/// \file hex.h +/// \brief Classes for HexEncoder and HexDecoder + +#ifndef CRYPTOPP_HEX_H +#define CRYPTOPP_HEX_H + +#include "cryptlib.h" +#include "basecode.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Converts given data to base 16 +class CRYPTOPP_DLL HexEncoder : public SimpleProxyFilter +{ +public: + /// \brief Construct a HexEncoder + /// \param attachment a BufferedTrasformation to attach to this object + /// \param uppercase a flag indicating uppercase output + /// \param groupSize the size of the output grouping + /// \param separator the separator to use between groups + /// \param terminator the terminator append after processing + HexEncoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "") + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::Uppercase(), uppercase)(Name::GroupSize(), groupSize)(Name::Separator(), ConstByteArrayParameter(separator))(Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +/// \brief Decode base 16 data back to bytes +class CRYPTOPP_DLL HexDecoder : public BaseN_Decoder +{ +public: + /// \brief Construct a HexDecoder + /// \param attachment a BufferedTrasformation to attach to this object + HexDecoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDefaultDecodingLookupArray(), 4, attachment) {} + + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + static const int * CRYPTOPP_API GetDefaultDecodingLookupArray(); +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/hight.h b/third_party/cryptoppwin/include/cryptopp/hight.h new file mode 100644 index 00000000..c1ecd79a --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/hight.h @@ -0,0 +1,81 @@ +// hight.h - written and placed in the public domain by Kim Sung Hee and Jeffrey Walton +// Based on "HIGHT: A New Block Cipher Suitable for Low-Resource Device" +// by Deukjo Hong, Jaechul Sung, Seokhie Hong, Jongin Lim, Sangjin Lee, +// Bon-Seok Koo, Changhoon Lee, Donghoon Chang, Jesang Lee, Kitae Jeong, +// Hyun Kim, Jongsung Kim, and Seongtaek Chee + +/// \file hight.h +/// \brief Classes for the HIGHT block cipher +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_HIGHT_H +#define CRYPTOPP_HIGHT_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief HIGHT block cipher information +/// \since Crypto++ 8.0 +struct HIGHT_Info : public FixedBlockSize<8>, public FixedKeyLength<16> +{ + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize + return "HIGHT"; + } +}; + +/// \brief HIGHT 64-bit block cipher +/// \details HIGHT provides 64-bit block size. The valid key size is 128-bits. +/// \note Crypto++ provides a byte oriented implementation +/// \sa HIGHT, +/// Korea Internet & Security +/// Agency website +/// \since Crypto++ 8.0 +class CRYPTOPP_NO_VTABLE HIGHT : public HIGHT_Info, public BlockCipherDocumentation +{ +public: + /// \brief HIGHT block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + + FixedSizeSecBlock m_rkey; + mutable FixedSizeSecBlock m_xx; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef HIGHT::Encryption HIGHTEncryption; +typedef HIGHT::Decryption HIGHTDecryption; + +NAMESPACE_END + +#endif // CRYPTOPP_HIGHT_H diff --git a/third_party/cryptoppwin/include/cryptopp/hkdf.h b/third_party/cryptoppwin/include/cryptopp/hkdf.h new file mode 100644 index 00000000..490f212e --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/hkdf.h @@ -0,0 +1,179 @@ +// hkdf.h - written and placed in public domain by Jeffrey Walton. + +/// \file hkdf.h +/// \brief Classes for HKDF from RFC 5869 +/// \since Crypto++ 5.6.3 + +#ifndef CRYPTOPP_HKDF_H +#define CRYPTOPP_HKDF_H + +#include "cryptlib.h" +#include "secblock.h" +#include "algparam.h" +#include "hmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Extract-and-Expand Key Derivation Function (HKDF) +/// \tparam T HashTransformation class +/// \sa Cryptographic Extraction and Key +/// Derivation: The HKDF Scheme and +/// HMAC-based Extract-and-Expand Key +/// Derivation Function (HKDF) +/// \since Crypto++ 5.6.3 +template +class HKDF : public KeyDerivationFunction +{ +public: + virtual ~HKDF() {} + + static std::string StaticAlgorithmName () { + const std::string name(std::string("HKDF(") + + std::string(T::StaticAlgorithmName()) + std::string(")")); + return name; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // KeyDerivationFunction interface + size_t MaxDerivedKeyLength() const { + return static_cast(T::DIGESTSIZE) * 255; + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params) const; + + /// \brief Derive a key from a seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param info the additional input buffer + /// \param infoLen the size of the info buffer, in bytes + /// \return the number of iterations performed + /// \throw InvalidDerivedKeyLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details salt and info can be nullptr with 0 length. + /// HKDF is unusual in that a non-NULL salt with length 0 is different than a + /// NULL salt. A NULL salt causes HKDF to use a string of 0's + /// of length T::DIGESTSIZE for the salt. + /// \details HKDF always returns 1 because it only performs 1 iteration. Other + /// derivation functions, like PBKDF's, will return more interesting values. + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, const byte* info, size_t infoLen) const; + +protected: + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } + + // If salt is absent (NULL), then use the NULL vector. Missing is different than + // EMPTY (Non-NULL, 0 length). The length of s_NullVector used depends on the Hash + // function. SHA-256 will use 32 bytes of s_NullVector. + typedef byte NullVectorType[T::DIGESTSIZE]; + static const NullVectorType& GetNullVector() { + static const NullVectorType s_NullVector = {0}; + return s_NullVector; + } +}; + +template +size_t HKDF::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedKeyLength()) + return MaxDerivedKeyLength(); + return keylength; +} + +template +size_t HKDF::DeriveKey(byte *derived, size_t derivedLen, + const byte *secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret && secretLen); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + + ConstByteArrayParameter p; + SecByteBlock salt, info; + + if (params.GetValue("Salt", p)) + salt.Assign(p.begin(), p.size()); + else + salt.Assign(GetNullVector(), T::DIGESTSIZE); + + if (params.GetValue("Info", p)) + info.Assign(p.begin(), p.size()); + else + info.Assign(GetNullVector(), 0); + + return DeriveKey(derived, derivedLen, secret, secretLen, salt.begin(), salt.size(), info.begin(), info.size()); +} + +template +size_t HKDF::DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, const byte* info, size_t infoLen) const +{ + CRYPTOPP_ASSERT(secret && secretLen); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + + ThrowIfInvalidDerivedKeyLength(derivedLen); + + // HKDF business logic. NULL is different than empty. + if (salt == NULLPTR) + { + salt = GetNullVector(); + saltLen = T::DIGESTSIZE; + } + + // key is PRK from the RFC, salt is IKM from the RFC + HMAC hmac; + SecByteBlock key(T::DIGESTSIZE), buffer(T::DIGESTSIZE); + + // Extract + hmac.SetKey(salt, saltLen); + hmac.CalculateDigest(key, secret, secretLen); + + // Key + hmac.SetKey(key.begin(), key.size()); + byte block = 0; + + // Expand + while (derivedLen > 0) + { + if (block++) {hmac.Update(buffer, buffer.size());} + if (infoLen) {hmac.Update(info, infoLen);} + hmac.CalculateDigest(buffer, &block, 1); + +#if CRYPTOPP_MSC_VERSION + const size_t digestSize = static_cast(T::DIGESTSIZE); + const size_t segmentLen = STDMIN(derivedLen, digestSize); + memcpy_s(derived, segmentLen, buffer, segmentLen); +#else + const size_t digestSize = static_cast(T::DIGESTSIZE); + const size_t segmentLen = STDMIN(derivedLen, digestSize); + std::memcpy(derived, buffer, segmentLen); +#endif + + derived += segmentLen; + derivedLen -= segmentLen; + } + + return 1; +} + +NAMESPACE_END + +#endif // CRYPTOPP_HKDF_H diff --git a/third_party/cryptoppwin/include/cryptopp/hmac.h b/third_party/cryptoppwin/include/cryptopp/hmac.h new file mode 100644 index 00000000..79ba1aad --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/hmac.h @@ -0,0 +1,80 @@ +// hmac.h - originally written and placed in the public domain by Wei Dai + +/// \file hmac.h +/// \brief Classes for HMAC message authentication codes + +#ifndef CRYPTOPP_HMAC_H +#define CRYPTOPP_HMAC_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief HMAC information +/// \details HMAC_Base derives from VariableKeyLength and MessageAuthenticationCode +/// \since Crypto++ 2.1 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE HMAC_Base : public VariableKeyLength<16, 0, INT_MAX>, public MessageAuthenticationCode +{ +public: + virtual ~HMAC_Base() {} + + /// \brief Construct a HMAC_Base + HMAC_Base() : m_innerHashKeyed(false) {} + void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms); + + void Restart(); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + unsigned int OptimalBlockSize() const {return const_cast(this)->AccessHash().OptimalBlockSize();} + unsigned int DigestSize() const {return const_cast(this)->AccessHash().DigestSize();} + +protected: + virtual HashTransformation & AccessHash() =0; + byte * AccessIpad() {return m_buf;} + byte * AccessOpad() {return m_buf + AccessHash().BlockSize();} + byte * AccessInnerHash() {return m_buf + 2*AccessHash().BlockSize();} + +private: + void KeyInnerHash(); + + SecByteBlock m_buf; + bool m_innerHashKeyed; +}; + +/// \brief HMAC +/// \tparam T HashTransformation derived class +/// \details HMAC derives from MessageAuthenticationCodeImpl. It calculates the HMAC using +/// HMAC(K, text) = H(K XOR opad, H(K XOR ipad, text)). +/// \sa HMAC +/// \since Crypto++ 2.1 +template +class HMAC : public MessageAuthenticationCodeImpl > +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE=T::DIGESTSIZE); + CRYPTOPP_CONSTANT(BLOCKSIZE=T::BLOCKSIZE); + + virtual ~HMAC() {} + + /// \brief Construct a HMAC + HMAC() {} + /// \brief Construct a HMAC + /// \param key the HMAC key + /// \param length the size of the HMAC key + HMAC(const byte *key, size_t length=HMAC_Base::DEFAULT_KEYLENGTH) + {this->SetKey(key, length);} + + static std::string StaticAlgorithmName() {return std::string("HMAC(") + T::StaticAlgorithmName() + ")";} + std::string AlgorithmName() const {return std::string("HMAC(") + m_hash.AlgorithmName() + ")";} + std::string AlgorithmProvider() const {return m_hash.AlgorithmProvider();} + +private: + HashTransformation & AccessHash() {return m_hash;} + + T m_hash; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/hmqv.h b/third_party/cryptoppwin/include/cryptopp/hmqv.h new file mode 100644 index 00000000..4736b055 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/hmqv.h @@ -0,0 +1,417 @@ +// hmqv.h - written and placed in the public domain by Uri Blumenthal +// Shamelessly based upon Wei Dai's MQV source files + +#ifndef CRYPTOPP_HMQV_H +#define CRYPTOPP_HMQV_H + +/// \file hmqv.h +/// \brief Classes for Hashed Menezes-Qu-Vanstone key agreement in GF(p) +/// \since Crypto++ 5.6.4 + +#include "gfpcrypt.h" +#include "algebra.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Hashed Menezes-Qu-Vanstone in GF(p) +/// \details This implementation follows Hugo Krawczyk's HMQV: A High-Performance +/// Secure Diffie-Hellman Protocol. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided. +/// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain +/// \since Crypto++ 5.6.4 +template +class HMQV_Domain: public AuthenticatedKeyAgreementDomain +{ +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef HMQV_Domain Domain; + + virtual ~HMQV_Domain() {} + + /// \brief Construct a HMQV domain + /// \param clientRole flag indicating initiator or recipient + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + HMQV_Domain(bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) {} + + /// \brief Construct a HMQV domain + /// \param params group parameters and options + /// \param clientRole flag indicating initiator or recipient + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + HMQV_Domain(const GroupParameters ¶ms, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {} + + /// \brief Construct a HMQV domain + /// \param bt BufferedTransformation with group parameters and options + /// \param clientRole flag indicating initiator or recipient + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + HMQV_Domain(BufferedTransformation &bt, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.BERDecode(bt);} + + /// \brief Construct a HMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1 is passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + HMQV_Domain(T1 v1, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1);} + + /// \brief Construct a HMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + HMQV_Domain(T1 v1, T2 v2, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Construct a HMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + HMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Construct a HMQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 third parameter + /// \param clientRole flag indicating initiator or recipient + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + /// \details clientRole = true indicates initiator, and + /// clientRole = false indicates recipient or server. + template + HMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true) + : m_role(clientRole ? RoleClient : RoleServer) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + +public: + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a const reference + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a non-const reference + GroupParameters & AccessGroupParameters() {return m_groupParameters;} + + /// \brief Retrieves the crypto parameters for this domain + /// \return the crypto parameters for this domain as a non-const reference + CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + /// \details The length is calculated using GetEncodedElementSize(false), + /// which means the element is encoded in a non-reversible format. A + /// non-reversible format means its a raw byte array, and it lacks presentation + /// format like an ASN.1 BIT_STRING or OCTET_STRING. + unsigned int AgreedValueLength() const + {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + + /// \brief Provides the size of the static private key + /// \return size of static private keys in this domain + /// \details The length is calculated using the byte count of the subgroup order. + unsigned int StaticPrivateKeyLength() const + {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + + /// \brief Provides the size of the static public key + /// \return size of static public keys in this domain + /// \details The length is calculated using GetEncodedElementSize(true), + /// which means the element is encoded in a reversible format. A reversible + /// format means it has a presentation format, and its an ANS.1 encoded element + /// or point. + unsigned int StaticPublicKeyLength() const + {return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + /// \brief Generate static private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \details The private key is a random scalar used as an exponent in the range + /// [1,MaxExponent()]. + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + } + + /// \brief Generate a static public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details The public key is an element or point on the curve, and its stored + /// in a revrsible format. A reversible format means it has a presentation + /// format, and its an ANS.1 encoded element or point. + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + /// \brief Provides the size of the ephemeral private key + /// \return size of ephemeral private keys in this domain + /// \details An ephemeral private key is a private key and public key. + /// The serialized size is different than a static private key. + unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();} + + /// \brief Provides the size of the ephemeral public key + /// \return size of ephemeral public keys in this domain + /// \details An ephemeral public key is a public key. + /// The serialized size is the same as a static public key. + unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();} + + /// \brief Generate ephemeral private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == EphemeralPrivateKeyLength() + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(rng, Integer::One(), params.GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength()); + } + + /// \brief Generate ephemeral public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == EphemeralPublicKeyLength() + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + std::memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength()); + } + + /// \brief Derive agreed value or shared secret + /// \param agreedValue the shared secret + /// \param staticPrivateKey your long term private key + /// \param ephemeralPrivateKey your ephemeral private key + /// \param staticOtherPublicKey couterparty's long term public key + /// \param ephemeralOtherPublicKey couterparty's ephemeral public key + /// \param validateStaticOtherPublicKey flag indicating validation + /// \return true upon success, false in case of failure + /// \details Agree() performs the authenticated key agreement. Agree() + /// derives a shared secret from your private keys and couterparty's + /// public keys. Each instance or run of the protocol should use a new + /// ephemeral key pair. + /// \details The other's ephemeral public key will always be validated at + /// Level 1 to ensure it is a point on the curve. + /// validateStaticOtherPublicKey determines how thoroughly other's + /// static public key is validated. If you have previously validated the + /// couterparty's static public key, then use + /// validateStaticOtherPublicKey=false to save time. + /// \pre COUNTOF(agreedValue) == AgreedValueLength() + /// \pre COUNTOF(staticPrivateKey) == StaticPrivateKeyLength() + /// \pre COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength() + /// \pre COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength() + /// \pre COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength() + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const + { + const byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR; + size_t xxs = 0, yys = 0, aas = 0, bbs = 0; + + // Depending on the role, this will hold either A's or B's static + // (long term) public key. AA or BB will then point into tt. + SecByteBlock tt(StaticPublicKeyLength()); + + try + { + this->GetMaterial().DoQuickSanityCheck(); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + + if(m_role == RoleServer) + { + Integer b(staticPrivateKey, StaticPrivateKeyLength()); + Element B = params.ExponentiateBase(b); + params.EncodeElement(true, B, tt); + + XX = ephemeralOtherPublicKey; + xxs = EphemeralPublicKeyLength(); + YY = ephemeralPrivateKey + StaticPrivateKeyLength(); + yys = EphemeralPublicKeyLength(); + AA = staticOtherPublicKey; + aas = StaticPublicKeyLength(); + BB = tt.BytePtr(); + bbs = tt.SizeInBytes(); + } + else + { + Integer a(staticPrivateKey, StaticPrivateKeyLength()); + Element A = params.ExponentiateBase(a); + params.EncodeElement(true, A, tt); + + XX = ephemeralPrivateKey + StaticPrivateKeyLength(); + xxs = EphemeralPublicKeyLength(); + YY = ephemeralOtherPublicKey; + yys = EphemeralPublicKeyLength(); + AA = tt.BytePtr(); + aas = tt.SizeInBytes(); + BB = staticOtherPublicKey; + bbs = StaticPublicKeyLength(); + } + + Element VV1 = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey); + Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, true); + + const Integer& q = params.GetSubgroupOrder(); + const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8); + SecByteBlock dd(len), ee(len); + + // Compute $d = \hat{H}(X, \hat{B})$ + Hash(NULLPTR, XX, xxs, BB, bbs, dd.BytePtr(), dd.SizeInBytes()); + Integer d(dd.BytePtr(), dd.SizeInBytes()); + + // Compute $e = \hat{H}(Y, \hat{A})$ + Hash(NULLPTR, YY, yys, AA, aas, ee.BytePtr(), ee.SizeInBytes()); + Integer e(ee.BytePtr(), ee.SizeInBytes()); + + Element sigma; + if(m_role == RoleServer) + { + Integer y(ephemeralPrivateKey, StaticPrivateKeyLength()); + Integer b(staticPrivateKey, StaticPrivateKeyLength()); + Integer s_B = (y + e * b) % q; + + Element A = params.DecodeElement(AA, false); + Element X = params.DecodeElement(XX, false); + + Element t1 = params.ExponentiateElement(A, d); + Element t2 = m_groupParameters.MultiplyElements(X, t1); + + // $\sigma_B}=(X \cdot A^{d})^{s_B} + sigma = params.ExponentiateElement(t2, s_B); + } + else + { + Integer x(ephemeralPrivateKey, StaticPrivateKeyLength()); + Integer a(staticPrivateKey, StaticPrivateKeyLength()); + Integer s_A = (x + d * a) % q; + + Element B = params.DecodeElement(BB, false); + Element Y = params.DecodeElement(YY, false); + + Element t3 = params.ExponentiateElement(B, e); + Element t4 = m_groupParameters.MultiplyElements(Y, t3); + + // $\sigma_A}=(Y \cdot B^{e})^{s_A} + sigma = params.ExponentiateElement(t4, s_A); + } + Hash(&sigma, NULLPTR, 0, NULLPTR, 0, agreedValue, AgreedValueLength()); + } + catch (DL_BadElement &) + { + CRYPTOPP_ASSERT(0); + return false; + } + return true; + } + +protected: + // Hash invocation by client and server differ only in what keys + // each provides. + + inline void Hash(const Element* sigma, + const byte* e1, size_t e1len, // Ephemeral key and key length + const byte* s1, size_t s1len, // Static key and key length + byte* digest, size_t dlen) const + { + HASH hash; + size_t idx = 0, req = dlen; + size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE); + + if(sigma) + { + if (e1len != 0 || s1len != 0) { + CRYPTOPP_ASSERT(0); + } + //Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma); + //SecByteBlock sbb(x.MinEncodedSize()); + //x.Encode(sbb.BytePtr(), sbb.SizeInBytes()); + SecByteBlock sbb(GetAbstractGroupParameters().GetEncodedElementSize(false)); + GetAbstractGroupParameters().EncodeElement(false, *sigma, sbb); + hash.Update(sbb.BytePtr(), sbb.SizeInBytes()); + } else { + if (e1len == 0 || s1len == 0) { + CRYPTOPP_ASSERT(0); + } + hash.Update(e1, e1len); + hash.Update(s1, s1len); + } + + hash.TruncatedFinal(digest, blk); + req -= blk; + + // All this to catch tail bytes for large curves and small hashes + while(req != 0) + { + hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE); + + idx += (size_t)HASH::DIGESTSIZE; + blk = STDMIN(req, (size_t)HASH::DIGESTSIZE); + hash.TruncatedFinal(&digest[idx], blk); + + req -= blk; + } + } + +private: + + // The paper uses Initiator and Recipient - make it classical. + enum KeyAgreementRole { RoleServer = 1, RoleClient }; + + DL_GroupParameters & AccessAbstractGroupParameters() + {return m_groupParameters;} + const DL_GroupParameters & GetAbstractGroupParameters() const + {return m_groupParameters;} + + GroupParameters m_groupParameters; + KeyAgreementRole m_role; +}; + +/// \brief Hashed Menezes-Qu-Vanstone in GF(p) +/// \details This implementation follows Hugo Krawczyk's HMQV: A High-Performance +/// Secure Diffie-Hellman Protocol. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided. +/// \sa HMQV, HMQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain +/// \since Crypto++ 5.6.4 +typedef HMQV_Domain HMQV; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/hrtimer.h b/third_party/cryptoppwin/include/cryptopp/hrtimer.h new file mode 100644 index 00000000..db6ad180 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/hrtimer.h @@ -0,0 +1,134 @@ +// hrtimer.h - originally written and placed in the public domain by Wei Dai + +/// \file hrtimer.h +/// \brief Classes for timers + +#ifndef CRYPTOPP_HRTIMER_H +#define CRYPTOPP_HRTIMER_H + +#include "config.h" + +#if !defined(HIGHRES_TIMER_AVAILABLE) || (defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(THREAD_TIMER_AVAILABLE)) +#include +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#ifdef HIGHRES_TIMER_AVAILABLE + /// \brief TimerWord is a 64-bit word + typedef word64 TimerWord; +#else + /// \brief TimerWord is a clock_t + typedef clock_t TimerWord; +#endif + +/// \brief Base class for timers +/// \sa ThreadUserTimer, Timer +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TimerBase +{ +public: + /// \brief Unit of measure + /// \details Unit selects the unit of measure as returned by functions + /// ElapsedTimeAsDouble() and ElapsedTime(). + /// \sa ElapsedTimeAsDouble, ElapsedTime + enum Unit { + /// \brief Timer unit is seconds + /// \details All timers support seconds + SECONDS = 0, + /// \brief Timer unit is milliseconds + /// \details All timers support milliseconds + MILLISECONDS, + /// \brief Timer unit is microseconds + /// \details The timer requires hardware support microseconds + MICROSECONDS, + /// \brief Timer unit is nanoseconds + /// \details The timer requires hardware support nanoseconds + NANOSECONDS + }; + + /// \brief Construct a TimerBase + /// \param unit the unit of measure + /// \param stuckAtZero flag + TimerBase(Unit unit, bool stuckAtZero) + : m_timerUnit(unit), m_stuckAtZero(stuckAtZero), m_started(false) + , m_start(0), m_last(0) {} + + /// \brief Retrieve the current timer value + /// \return the current timer value + virtual TimerWord GetCurrentTimerValue() =0; + + /// \brief Retrieve ticks per second + /// \return ticks per second + /// \details TicksPerSecond() is not the timer resolution. It is a + /// conversion factor into seconds. + virtual TimerWord TicksPerSecond() =0; + + /// \brief Start the timer + void StartTimer(); + + /// \brief Retrieve the elapsed time + /// \return the elapsed time as a double + /// \details The return value of ElapsedTimeAsDouble() depends upon + /// the Unit selected during construction of the timer. For example, + /// if Unit = SECONDS and ElapsedTimeAsDouble() returns 3, + /// then the timer has run for 3 seconds. If + /// Unit = MILLISECONDS and ElapsedTimeAsDouble() returns + /// 3000, then the timer has run for 3 seconds. + /// \sa Unit, ElapsedTime + double ElapsedTimeAsDouble(); + + /// \brief Retrieve the elapsed time + /// \return the elapsed time as an unsigned long + /// \details The return value of ElapsedTime() depends upon the + /// Unit selected during construction of the timer. For example, if + /// Unit = SECONDS and ElapsedTime() returns 3, then + /// the timer has run for 3 seconds. If Unit = MILLISECONDS + /// and ElapsedTime() returns 3000, then the timer has run for 3 + /// seconds. + /// \sa Unit, ElapsedTimeAsDouble + unsigned long ElapsedTime(); + +private: + double ConvertTo(TimerWord t, Unit unit); + + Unit m_timerUnit; // HPUX workaround: m_unit is a system macro on HPUX + bool m_stuckAtZero, m_started; + TimerWord m_start, m_last; +}; + +/// \brief Measure CPU time spent executing instructions of this thread +/// \details ThreadUserTimer requires support of the OS. On Unix-based it +/// reports process time. On Windows NT or later desktops and servers it +/// reports thread times with performance counter precision.. On Windows +/// Phone and Windows Store it reports wall clock time with performance +/// counter precision. On all others it reports wall clock time. +/// \note ThreadUserTimer only works correctly on Windows NT or later +/// desktops and servers. +/// \sa Timer +class ThreadUserTimer : public TimerBase +{ +public: + /// \brief Construct a ThreadUserTimer + /// \param unit the unit of measure + /// \param stuckAtZero flag + ThreadUserTimer(Unit unit = TimerBase::SECONDS, bool stuckAtZero = false) : TimerBase(unit, stuckAtZero) {} + TimerWord GetCurrentTimerValue(); + TimerWord TicksPerSecond(); +}; + +/// \brief High resolution timer +/// \sa ThreadUserTimer +class CRYPTOPP_DLL Timer : public TimerBase +{ +public: + /// \brief Construct a Timer + /// \param unit the unit of measure + /// \param stuckAtZero flag + Timer(Unit unit = TimerBase::SECONDS, bool stuckAtZero = false) : TimerBase(unit, stuckAtZero) {} + TimerWord GetCurrentTimerValue(); + TimerWord TicksPerSecond(); +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/ida.h b/third_party/cryptoppwin/include/cryptopp/ida.h new file mode 100644 index 00000000..534a9ba7 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/ida.h @@ -0,0 +1,182 @@ +// ida.h - originally written and placed in the public domain by Wei Dai + +/// \file ida.h +/// \brief Classes for Rabin's Information Dispersal and Shamir's Secret Sharing algorithms + +#ifndef CRYPTOPP_IDA_H +#define CRYPTOPP_IDA_H + +#include "cryptlib.h" +#include "mqueue.h" +#include "filters.h" +#include "channels.h" +#include "secblock.h" +#include "gf2_32.h" +#include "stdcpp.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Secret sharing and information dispersal base class +/// \since Crypto++ 1.0 +class RawIDA : public AutoSignaling > > +{ +public: + RawIDA(BufferedTransformation *attachment=NULLPTR) + : m_channelsReady(0), m_channelsFinished(0), m_threshold (0) + {Detach(attachment);} + + unsigned int GetThreshold() const {return m_threshold;} + void AddOutputChannel(word32 channelId); + void ChannelData(word32 channelId, const byte *inString, size_t length, bool messageEnd); + lword InputBuffered(word32 channelId) const; + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) + { + if (!blocking) + throw BlockingInputOnly("RawIDA"); + ChannelData(StringToWord(channel), begin, length, messageEnd != 0); + return 0; + } + +protected: + virtual void FlushOutputQueues(); + virtual void OutputMessageEnds(); + + unsigned int InsertInputChannel(word32 channelId); + unsigned int LookupInputChannel(word32 channelId) const; + void ComputeV(unsigned int); + void PrepareInterpolation(); + void ProcessInputQueues(); + + typedef std::map InputChannelMap; + InputChannelMap m_inputChannelMap; + InputChannelMap::iterator m_lastMapPosition; + std::vector m_inputQueues; + std::vector m_inputChannelIds, m_outputChannelIds, m_outputToInput; + std::vector m_outputChannelIdStrings; + std::vector m_outputQueues; + std::vector > m_v; + SecBlock m_u, m_w, m_y; + const GF2_32 m_gf32; + unsigned int m_channelsReady, m_channelsFinished; + int m_threshold; +}; + +/// \brief Shamir's Secret Sharing Algorithm +/// \details SecretSharing is a variant of Shamir's secret sharing algorithm +/// \sa SecretRecovery, SecretRecovery, InformationDispersal, InformationRecovery +/// \since Crypto++ 1.0 +class SecretSharing : public CustomFlushPropagation +{ +public: + /// \brief Construct a SecretSharing + SecretSharing(RandomNumberGenerator &rng, int threshold, int nShares, BufferedTransformation *attachment=NULLPTR, bool addPadding=true) + : m_rng(rng), m_ida(new OutputProxy(*this, true)) + { + Detach(attachment); + IsolatedInitialize(MakeParameters("RecoveryThreshold", threshold)("NumberOfShares", nShares)("AddPadding", addPadding)); + } + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) {return m_ida.Flush(hardFlush, propagation, blocking);} + +protected: + RandomNumberGenerator &m_rng; + RawIDA m_ida; + bool m_pad; +}; + +/// \brief Shamir's Secret Sharing Algorithm +/// \details SecretSharing is a variant of Shamir's secret sharing algorithm +/// \sa SecretRecovery, SecretRecovery, InformationDispersal, InformationRecovery +/// \since Crypto++ 1.0 +class SecretRecovery : public RawIDA +{ +public: + /// \brief Construct a SecretRecovery + SecretRecovery(int threshold, BufferedTransformation *attachment=NULLPTR, bool removePadding=true) + : RawIDA(attachment) + {IsolatedInitialize(MakeParameters("RecoveryThreshold", threshold)("RemovePadding", removePadding));} + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + +protected: + void FlushOutputQueues(); + void OutputMessageEnds(); + + bool m_pad; +}; + +/// a variant of Rabin's Information Dispersal Algorithm + +/// \brief Rabin's Information Dispersal Algorithm +/// \details InformationDispersal is a variant of Rabin's information dispersal algorithm +/// \sa SecretRecovery, SecretRecovery, InformationDispersal, InformationRecovery +/// \since Crypto++ 1.0 +class InformationDispersal : public CustomFlushPropagation +{ +public: + /// \brief Construct a InformationDispersal + InformationDispersal(int threshold, int nShares, BufferedTransformation *attachment=NULLPTR, bool addPadding=true) + : m_ida(new OutputProxy(*this, true)), m_pad(false), m_nextChannel(0) + { + Detach(attachment); + IsolatedInitialize(MakeParameters("RecoveryThreshold", threshold)("NumberOfShares", nShares)("AddPadding", addPadding)); + } + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) {return m_ida.Flush(hardFlush, propagation, blocking);} + +protected: + RawIDA m_ida; + bool m_pad; + unsigned int m_nextChannel; +}; + +/// \brief Rabin's Information Dispersal Algorithm +/// \details InformationDispersal is a variant of Rabin's information dispersal algorithm +/// \sa SecretRecovery, SecretRecovery, InformationDispersal, InformationRecovery +/// \since Crypto++ 1.0 +class InformationRecovery : public RawIDA +{ +public: + /// \brief Construct a InformationRecovery + InformationRecovery(int threshold, BufferedTransformation *attachment=NULLPTR, bool removePadding=true) + : RawIDA(attachment), m_pad(false) + {IsolatedInitialize(MakeParameters("RecoveryThreshold", threshold)("RemovePadding", removePadding));} + + void IsolatedInitialize(const NameValuePairs ¶meters=g_nullNameValuePairs); + +protected: + void FlushOutputQueues(); + void OutputMessageEnds(); + + bool m_pad; + ByteQueue m_queue; +}; + +class PaddingRemover : public Unflushable +{ +public: + PaddingRemover(BufferedTransformation *attachment=NULLPTR) + : m_possiblePadding(false), m_zeroCount(0) {Detach(attachment);} + + void IsolatedInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); m_possiblePadding = false;} + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking); + + // GetPossiblePadding() == false at the end of a message indicates incorrect padding + bool GetPossiblePadding() const {return m_possiblePadding;} + +private: + bool m_possiblePadding; + lword m_zeroCount; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/idea.h b/third_party/cryptoppwin/include/cryptopp/idea.h new file mode 100644 index 00000000..f4846b3a --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/idea.h @@ -0,0 +1,66 @@ +// idea.h - originally written and placed in the public domain by Wei Dai + +/// \file idea.h +/// \brief Classes for the IDEA block cipher + +#ifndef CRYPTOPP_IDEA_H +#define CRYPTOPP_IDEA_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief IDEA block cipher information +/// \since Crypto++ 1.0 +struct IDEA_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public FixedRounds<8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "IDEA";} +}; + +/// \brief IDEA block cipher +/// \sa IDEA +/// \since Crypto++ 1.0 +class IDEA : public IDEA_Info, public BlockCipherDocumentation +{ +public: // made public for internal purposes +#ifdef CRYPTOPP_NATIVE_DWORD_AVAILABLE + typedef word Word; +#else + typedef hword Word; +#endif + +private: + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + unsigned int OptimalDataAlignment() const {return 2;} + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + private: + void EnKey(const byte *); + void DeKey(); + FixedSizeSecBlock m_key; + + #ifdef IDEA_LARGECACHE + static inline void LookupMUL(word &a, word b); + void LookupKeyLogs(); + static void BuildLogTables(); + static volatile bool tablesBuilt; + static word16 log[0x10000], antilog[0x10000]; + #endif + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef IDEA::Encryption IDEAEncryption; +typedef IDEA::Decryption IDEADecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/integer.h b/third_party/cryptoppwin/include/cryptopp/integer.h new file mode 100644 index 00000000..05d7d6ae --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/integer.h @@ -0,0 +1,840 @@ +// integer.h - originally written and placed in the public domain by Wei Dai + +/// \file integer.h +/// \brief Multiple precision integer with arithmetic operations +/// \details The Integer class can represent positive and negative integers +/// with absolute value less than (256**sizeof(word))(256**sizeof(int)). +/// \details Internally, the library uses a sign magnitude representation, and the class +/// has two data members. The first is a IntegerSecBlock (a SecBlock) and it is +/// used to hold the representation. The second is a Sign (an enumeration), and it is +/// used to track the sign of the Integer. +/// \details For details on how the Integer class initializes its function pointers using +/// InitializeInteger and how it creates Integer::Zero(), Integer::One(), and +/// Integer::Two(), then see the comments at the top of integer.cpp. +/// \since Crypto++ 1.0 + +#ifndef CRYPTOPP_INTEGER_H +#define CRYPTOPP_INTEGER_H + +#include "cryptlib.h" +#include "secblock.h" +#include "stdcpp.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \struct InitializeInteger +/// \brief Performs static initialization of the Integer class +struct InitializeInteger +{ + InitializeInteger(); +}; + +// Always align, http://github.com/weidai11/cryptopp/issues/256 +typedef SecBlock > IntegerSecBlock; + +/// \brief Multiple precision integer with arithmetic operations +/// \details The Integer class can represent positive and negative integers +/// with absolute value less than (256**sizeof(word))(256**sizeof(int)). +/// \details Internally, the library uses a sign magnitude representation, and the class +/// has two data members. The first is a IntegerSecBlock (a SecBlock) and it is +/// used to hold the representation. The second is a Sign (an enumeration), and it is +/// used to track the sign of the Integer. +/// \details For details on how the Integer class initializes its function pointers using +/// InitializeInteger and how it creates Integer::Zero(), Integer::One(), and +/// Integer::Two(), then see the comments at the top of integer.cpp. +/// \since Crypto++ 1.0 +/// \nosubgrouping +class CRYPTOPP_DLL Integer : private InitializeInteger, public ASN1Object +{ +public: + /// \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + /// \brief Exception thrown when division by 0 is encountered + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "Integer: division by zero") {} + }; + + /// \brief Exception thrown when a random number cannot be found that + /// satisfies the condition + class RandomNumberNotFound : public Exception + { + public: + RandomNumberNotFound() : Exception(OTHER_ERROR, "Integer: no integer satisfies the given parameters") {} + }; + + /// \enum Sign + /// \brief Used internally to represent the integer + /// \details Sign is used internally to represent the integer. It is also used in a few API functions. + /// \sa SetPositive(), SetNegative(), Signedness + enum Sign { + /// \brief the value is positive or 0 + POSITIVE=0, + /// \brief the value is negative + NEGATIVE=1}; + + /// \enum Signedness + /// \brief Used when importing and exporting integers + /// \details Signedness is usually used in API functions. + /// \sa Sign + enum Signedness { + /// \brief an unsigned value + UNSIGNED, + /// \brief a signed value + SIGNED}; + + /// \enum RandomNumberType + /// \brief Properties of a random integer + enum RandomNumberType { + /// \brief a number with no special properties + ANY, + /// \brief a number which is probabilistically prime + PRIME}; + //@} + + /// \name CREATORS + //@{ + /// \brief Creates the zero integer + Integer(); + + /// copy constructor + Integer(const Integer& t); + + /// \brief Convert from signed long + Integer(signed long value); + + /// \brief Convert from lword + /// \param sign enumeration indicating Sign + /// \param value the long word + Integer(Sign sign, lword value); + + /// \brief Convert from two words + /// \param sign enumeration indicating Sign + /// \param highWord the high word + /// \param lowWord the low word + Integer(Sign sign, word highWord, word lowWord); + + /// \brief Convert from a C-string + /// \param str C-string value + /// \param order the ByteOrder of the string to be processed + /// \details \p str can be in base 8, 10, or 16. Base is determined + /// by a case insensitive suffix of 'o' (8), '.' (10), or 'h' (16). + /// No suffix means base 10. + /// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian + /// integers with curve25519, Poly1305 and Microsoft CAPI. + explicit Integer(const char *str, ByteOrder order = BIG_ENDIAN_ORDER); + + /// \brief Convert from a wide C-string + /// \param str wide C-string value + /// \param order the ByteOrder of the string to be processed + /// \details \p str can be in base 8, 10, or 16. Base is determined + /// by a case insensitive suffix of 'o' (8), '.' (10), or 'h' (16). + /// No suffix means base 10. + /// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian + /// integers with curve25519, Poly1305 and Microsoft CAPI. + explicit Integer(const wchar_t *str, ByteOrder order = BIG_ENDIAN_ORDER); + + /// \brief Convert from a big-endian byte array + /// \param encodedInteger big-endian byte array + /// \param byteCount length of the byte array + /// \param sign enumeration indicating Signedness + /// \param order the ByteOrder of the array to be processed + /// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian + /// integers with curve25519, Poly1305 and Microsoft CAPI. + Integer(const byte *encodedInteger, size_t byteCount, Signedness sign=UNSIGNED, ByteOrder order = BIG_ENDIAN_ORDER); + + /// \brief Convert from a big-endian array + /// \param bt BufferedTransformation object with big-endian byte array + /// \param byteCount length of the byte array + /// \param sign enumeration indicating Signedness + /// \param order the ByteOrder of the data to be processed + /// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian + /// integers with curve25519, Poly1305 and Microsoft CAPI. + Integer(BufferedTransformation &bt, size_t byteCount, Signedness sign=UNSIGNED, ByteOrder order = BIG_ENDIAN_ORDER); + + /// \brief Convert from a BER encoded byte array + /// \param bt BufferedTransformation object with BER encoded byte array + explicit Integer(BufferedTransformation &bt); + + /// \brief Create a random integer + /// \param rng RandomNumberGenerator used to generate material + /// \param bitCount the number of bits in the resulting integer + /// \details The random integer created is uniformly distributed over [0, 2bitCount]. + Integer(RandomNumberGenerator &rng, size_t bitCount); + + /// \brief Integer representing 0 + /// \return an Integer representing 0 + /// \details Zero() avoids calling constructors for frequently used integers + static const Integer & CRYPTOPP_API Zero(); + /// \brief Integer representing 1 + /// \return an Integer representing 1 + /// \details One() avoids calling constructors for frequently used integers + static const Integer & CRYPTOPP_API One(); + /// \brief Integer representing 2 + /// \return an Integer representing 2 + /// \details Two() avoids calling constructors for frequently used integers + static const Integer & CRYPTOPP_API Two(); + + /// \brief Create a random integer of special form + /// \param rng RandomNumberGenerator used to generate material + /// \param min the minimum value + /// \param max the maximum value + /// \param rnType RandomNumberType to specify the type + /// \param equiv the equivalence class based on the parameter \p mod + /// \param mod the modulus used to reduce the equivalence class + /// \throw RandomNumberNotFound if the set is empty. + /// \details Ideally, the random integer created should be uniformly distributed + /// over {x | min \<= x \<= max and \p x is of rnType and x \% mod == equiv}. + /// However the actual distribution may not be uniform because sequential + /// search is used to find an appropriate number from a random starting + /// point. + /// \details May return (with very small probability) a pseudoprime when a prime + /// is requested and max \> lastSmallPrime*lastSmallPrime. \p lastSmallPrime + /// is declared in nbtheory.h. + Integer(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType=ANY, const Integer &equiv=Zero(), const Integer &mod=One()); + + /// \brief Exponentiates to a power of 2 + /// \return the Integer 2e + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + static Integer CRYPTOPP_API Power2(size_t e); + //@} + + /// \name ENCODE/DECODE + //@{ + /// \brief Minimum number of bytes to encode this integer + /// \param sign enumeration indicating Signedness + /// \note The MinEncodedSize() of 0 is 1. + size_t MinEncodedSize(Signedness sign=UNSIGNED) const; + + /// \brief Encode in big-endian format + /// \param output big-endian byte array + /// \param outputLen length of the byte array + /// \param sign enumeration indicating Signedness + /// \details Unsigned means encode absolute value, signed means encode two's complement if negative. + /// \details outputLen can be used to ensure an Integer is encoded to an exact size (rather than a + /// minimum size). An exact size is useful, for example, when encoding to a field element size. + void Encode(byte *output, size_t outputLen, Signedness sign=UNSIGNED) const; + + /// \brief Encode in big-endian format + /// \param bt BufferedTransformation object + /// \param outputLen length of the encoding + /// \param sign enumeration indicating Signedness + /// \details Unsigned means encode absolute value, signed means encode two's complement if negative. + /// \details outputLen can be used to ensure an Integer is encoded to an exact size (rather than a + /// minimum size). An exact size is useful, for example, when encoding to a field element size. + void Encode(BufferedTransformation &bt, size_t outputLen, Signedness sign=UNSIGNED) const; + + /// \brief Encode in DER format + /// \param bt BufferedTransformation object + /// \details Encodes the Integer using Distinguished Encoding Rules + /// The result is placed into a BufferedTransformation object + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Encode absolute value as big-endian octet string + /// \param bt BufferedTransformation object + /// \param length the number of mytes to decode + void DEREncodeAsOctetString(BufferedTransformation &bt, size_t length) const; + + /// \brief Encode absolute value in OpenPGP format + /// \param output big-endian byte array + /// \param bufferSize length of the byte array + /// \return length of the output + /// \details OpenPGPEncode places result into the buffer and returns the + /// number of bytes used for the encoding + size_t OpenPGPEncode(byte *output, size_t bufferSize) const; + + /// \brief Encode absolute value in OpenPGP format + /// \param bt BufferedTransformation object + /// \return length of the output + /// \details OpenPGPEncode places result into a BufferedTransformation object and returns the + /// number of bytes used for the encoding + size_t OpenPGPEncode(BufferedTransformation &bt) const; + + /// \brief Decode from big-endian byte array + /// \param input big-endian byte array + /// \param inputLen length of the byte array + /// \param sign enumeration indicating Signedness + void Decode(const byte *input, size_t inputLen, Signedness sign=UNSIGNED); + + /// \brief Decode nonnegative value from big-endian byte array + /// \param bt BufferedTransformation object + /// \param inputLen length of the byte array + /// \param sign enumeration indicating Signedness + /// \note bt.MaxRetrievable() \>= inputLen. + void Decode(BufferedTransformation &bt, size_t inputLen, Signedness sign=UNSIGNED); + + /// \brief Decode from BER format + /// \param input big-endian byte array + /// \param inputLen length of the byte array + void BERDecode(const byte *input, size_t inputLen); + + /// \brief Decode from BER format + /// \param bt BufferedTransformation object + void BERDecode(BufferedTransformation &bt); + + /// \brief Decode nonnegative value from big-endian octet string + /// \param bt BufferedTransformation object + /// \param length length of the byte array + void BERDecodeAsOctetString(BufferedTransformation &bt, size_t length); + + /// \brief Exception thrown when an error is encountered decoding an OpenPGP integer + class OpenPGPDecodeErr : public Exception + { + public: + OpenPGPDecodeErr() : Exception(INVALID_DATA_FORMAT, "OpenPGP decode error") {} + }; + + /// \brief Decode from OpenPGP format + /// \param input big-endian byte array + /// \param inputLen length of the byte array + void OpenPGPDecode(const byte *input, size_t inputLen); + /// \brief Decode from OpenPGP format + /// \param bt BufferedTransformation object + void OpenPGPDecode(BufferedTransformation &bt); + //@} + + /// \name ACCESSORS + //@{ + /// \brief Determines if the Integer is convertable to Long + /// \return true if *this can be represented as a signed long + /// \sa ConvertToLong() + bool IsConvertableToLong() const; + /// \brief Convert the Integer to Long + /// \return equivalent signed long if possible, otherwise undefined + /// \sa IsConvertableToLong() + signed long ConvertToLong() const; + + /// \brief Determines the number of bits required to represent the Integer + /// \return number of significant bits + /// \details BitCount is calculated as floor(log2(abs(*this))) + 1. + unsigned int BitCount() const; + /// \brief Determines the number of bytes required to represent the Integer + /// \return number of significant bytes + /// \details ByteCount is calculated as ceiling(BitCount()/8). + unsigned int ByteCount() const; + /// \brief Determines the number of words required to represent the Integer + /// \return number of significant words + /// \details WordCount is calculated as ceiling(ByteCount()/sizeof(word)). + unsigned int WordCount() const; + + /// \brief Provides the i-th bit of the Integer + /// \return the i-th bit, i=0 being the least significant bit + bool GetBit(size_t i) const; + /// \brief Provides the i-th byte of the Integer + /// \return the i-th byte + byte GetByte(size_t i) const; + /// \brief Provides the low order bits of the Integer + /// \return n lowest bits of *this >> i + lword GetBits(size_t i, size_t n) const; + + /// \brief Determines if the Integer is 0 + /// \return true if the Integer is 0, false otherwise + bool IsZero() const {return !*this;} + /// \brief Determines if the Integer is non-0 + /// \return true if the Integer is non-0, false otherwise + bool NotZero() const {return !IsZero();} + /// \brief Determines if the Integer is negative + /// \return true if the Integer is negative, false otherwise + bool IsNegative() const {return sign == NEGATIVE;} + /// \brief Determines if the Integer is non-negative + /// \return true if the Integer is non-negative, false otherwise + bool NotNegative() const {return !IsNegative();} + /// \brief Determines if the Integer is positive + /// \return true if the Integer is positive, false otherwise + bool IsPositive() const {return NotNegative() && NotZero();} + /// \brief Determines if the Integer is non-positive + /// \return true if the Integer is non-positive, false otherwise + bool NotPositive() const {return !IsPositive();} + /// \brief Determines if the Integer is even parity + /// \return true if the Integer is even, false otherwise + bool IsEven() const {return GetBit(0) == 0;} + /// \brief Determines if the Integer is odd parity + /// \return true if the Integer is odd, false otherwise + bool IsOdd() const {return GetBit(0) == 1;} + //@} + + /// \name MANIPULATORS + //@{ + /// \brief Assignment + /// \param t the other Integer + /// \return the result of assignment + Integer& operator=(const Integer& t); + /// \brief Addition Assignment + /// \param t the other Integer + /// \return the result of *this + t + Integer& operator+=(const Integer& t); + /// \brief Subtraction Assignment + /// \param t the other Integer + /// \return the result of *this - t + Integer& operator-=(const Integer& t); + /// \brief Multiplication Assignment + /// \param t the other Integer + /// \return the result of *this * t + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer& operator*=(const Integer& t) {return *this = Times(t);} + /// \brief Division Assignment + /// \param t the other Integer + /// \return the result of *this / t + Integer& operator/=(const Integer& t) {return *this = DividedBy(t);} + /// \brief Remainder Assignment + /// \param t the other Integer + /// \return the result of *this % t + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer& operator%=(const Integer& t) {return *this = Modulo(t);} + /// \brief Division Assignment + /// \param t the other word + /// \return the result of *this / t + Integer& operator/=(word t) {return *this = DividedBy(t);} + /// \brief Remainder Assignment + /// \param t the other word + /// \return the result of *this % t + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer& operator%=(word t) {return *this = Integer(POSITIVE, 0, Modulo(t));} + + /// \brief Left-shift Assignment + /// \param n number of bits to shift + /// \return reference to this Integer + Integer& operator<<=(size_t n); + /// \brief Right-shift Assignment + /// \param n number of bits to shift + /// \return reference to this Integer + Integer& operator>>=(size_t n); + + /// \brief Bitwise AND Assignment + /// \param t the other Integer + /// \return the result of *this & t + /// \details operator&=() performs a bitwise AND on *this. Missing bits are truncated + /// at the most significant bit positions, so the result is as small as the + /// smaller of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer& operator&=(const Integer& t); + /// \brief Bitwise OR Assignment + /// \param t the second Integer + /// \return the result of *this | t + /// \details operator|=() performs a bitwise OR on *this. Missing bits are shifted in + /// at the most significant bit positions, so the result is as large as the + /// larger of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer& operator|=(const Integer& t); + /// \brief Bitwise XOR Assignment + /// \param t the other Integer + /// \return the result of *this ^ t + /// \details operator^=() performs a bitwise XOR on *this. Missing bits are shifted + /// in at the most significant bit positions, so the result is as large as the + /// larger of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer& operator^=(const Integer& t); + + /// \brief Set this Integer to random integer + /// \param rng RandomNumberGenerator used to generate material + /// \param bitCount the number of bits in the resulting integer + /// \details The random integer created is uniformly distributed over [0, 2bitCount]. + /// \note If \p bitCount is 0, then this Integer is set to 0 (and not 0 or 1). + void Randomize(RandomNumberGenerator &rng, size_t bitCount); + + /// \brief Set this Integer to random integer + /// \param rng RandomNumberGenerator used to generate material + /// \param min the minimum value + /// \param max the maximum value + /// \details The random integer created is uniformly distributed over [min, max]. + void Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max); + + /// \brief Set this Integer to random integer of special form + /// \param rng RandomNumberGenerator used to generate material + /// \param min the minimum value + /// \param max the maximum value + /// \param rnType RandomNumberType to specify the type + /// \param equiv the equivalence class based on the parameter \p mod + /// \param mod the modulus used to reduce the equivalence class + /// \throw RandomNumberNotFound if the set is empty. + /// \details Ideally, the random integer created should be uniformly distributed + /// over {x | min \<= x \<= max and \p x is of rnType and x \% mod == equiv}. + /// However the actual distribution may not be uniform because sequential + /// search is used to find an appropriate number from a random starting + /// point. + /// \details May return (with very small probability) a pseudoprime when a prime + /// is requested and max \> lastSmallPrime*lastSmallPrime. \p lastSmallPrime + /// is declared in nbtheory.h. + bool Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType, const Integer &equiv=Zero(), const Integer &mod=One()); + + /// \brief Generate a random number + /// \param rng RandomNumberGenerator used to generate material + /// \param params additional parameters that cannot be passed directly to the function + /// \return true if a random number was generated, false otherwise + /// \details GenerateRandomNoThrow attempts to generate a random number according to the + /// parameters specified in params. The function does not throw RandomNumberNotFound. + /// \details The example below generates a prime number using NameValuePairs that Integer + /// class recognizes. The names are not provided in argnames.h. + ///
+		///    AutoSeededRandomPool prng;
+		///    AlgorithmParameters params = MakeParameters("BitLength", 2048)
+		///                                               ("RandomNumberType", Integer::PRIME);
+		///    Integer x;
+		///    if (x.GenerateRandomNoThrow(prng, params) == false)
+		///        throw std::runtime_error("Failed to generate prime number");
+		/// 
+ bool GenerateRandomNoThrow(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs); + + /// \brief Generate a random number + /// \param rng RandomNumberGenerator used to generate material + /// \param params additional parameters that cannot be passed directly to the function + /// \throw RandomNumberNotFound if a random number is not found + /// \details GenerateRandom attempts to generate a random number according to the + /// parameters specified in params. + /// \details The example below generates a prime number using NameValuePairs that Integer + /// class recognizes. The names are not provided in argnames.h. + ///
+		///    AutoSeededRandomPool prng;
+		///    AlgorithmParameters params = MakeParameters("BitLength", 2048)
+		///                                               ("RandomNumberType", Integer::PRIME);
+		///    Integer x;
+		///    try { x.GenerateRandom(prng, params); }
+		///    catch (RandomNumberNotFound&) { x = -1; }
+		/// 
+ void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms = g_nullNameValuePairs) + { + if (!GenerateRandomNoThrow(rng, params)) + throw RandomNumberNotFound(); + } + + /// \brief Set the n-th bit to value + /// \details 0-based numbering. + void SetBit(size_t n, bool value=1); + + /// \brief Set the n-th byte to value + /// \details 0-based numbering. + void SetByte(size_t n, byte value); + + /// \brief Reverse the Sign of the Integer + void Negate(); + + /// \brief Sets the Integer to positive + void SetPositive() {sign = POSITIVE;} + + /// \brief Sets the Integer to negative + void SetNegative() {if (!!(*this)) sign = NEGATIVE;} + + /// \brief Swaps this Integer with another Integer + void swap(Integer &a); + //@} + + /// \name UNARY OPERATORS + //@{ + /// \brief Negation + bool operator!() const; + /// \brief Addition + Integer operator+() const {return *this;} + /// \brief Subtraction + Integer operator-() const; + /// \brief Pre-increment + Integer& operator++(); + /// \brief Pre-decrement + Integer& operator--(); + /// \brief Post-increment + Integer operator++(int) {Integer temp = *this; ++*this; return temp;} + /// \brief Post-decrement + Integer operator--(int) {Integer temp = *this; --*this; return temp;} + //@} + + /// \name BINARY OPERATORS + //@{ + /// \brief Perform signed comparison + /// \param a the Integer to compare + /// \retval -1 if *this < a + /// \retval 0 if *this = a + /// \retval 1 if *this > a + int Compare(const Integer& a) const; + + /// \brief Addition + Integer Plus(const Integer &b) const; + /// \brief Subtraction + Integer Minus(const Integer &b) const; + /// \brief Multiplication + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer Times(const Integer &b) const; + /// \brief Division + Integer DividedBy(const Integer &b) const; + /// \brief Remainder + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer Modulo(const Integer &b) const; + /// \brief Division + Integer DividedBy(word b) const; + /// \brief Remainder + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + word Modulo(word b) const; + + /// \brief Bitwise AND + /// \param t the other Integer + /// \return the result of *this & t + /// \details And() performs a bitwise AND on the operands. Missing bits are truncated + /// at the most significant bit positions, so the result is as small as the + /// smaller of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer And(const Integer& t) const; + + /// \brief Bitwise OR + /// \param t the other Integer + /// \return the result of *this | t + /// \details Or() performs a bitwise OR on the operands. Missing bits are shifted in + /// at the most significant bit positions, so the result is as large as the + /// larger of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer Or(const Integer& t) const; + + /// \brief Bitwise XOR + /// \param t the other Integer + /// \return the result of *this ^ t + /// \details Xor() performs a bitwise XOR on the operands. Missing bits are shifted in + /// at the most significant bit positions, so the result is as large as the + /// larger of the operands. + /// \details Internally, Crypto++ uses a sign-magnitude representation. The library + /// does not attempt to interpret bits, and the result is always POSITIVE. If needed, + /// the integer should be converted to a 2's compliment representation before performing + /// the operation. + /// \since Crypto++ 6.0 + Integer Xor(const Integer& t) const; + + /// \brief Right-shift + Integer operator>>(size_t n) const {return Integer(*this)>>=n;} + /// \brief Left-shift + Integer operator<<(size_t n) const {return Integer(*this)<<=n;} + //@} + + /// \name OTHER ARITHMETIC FUNCTIONS + //@{ + /// \brief Retrieve the absolute value of this integer + Integer AbsoluteValue() const; + /// \brief Add this integer to itself + Integer Doubled() const {return Plus(*this);} + /// \brief Multiply this integer by itself + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer Squared() const {return Times(*this);} + /// \brief Extract square root + /// \details if negative return 0, else return floor of square root + Integer SquareRoot() const; + /// \brief Determine whether this integer is a perfect square + bool IsSquare() const; + + /// \brief Determine if 1 or -1 + /// \return true if this integer is 1 or -1, false otherwise + bool IsUnit() const; + /// \brief Calculate multiplicative inverse + /// \return MultiplicativeInverse inverse if 1 or -1, otherwise return 0. + Integer MultiplicativeInverse() const; + + /// \brief Extended Division + /// \param r a reference for the remainder + /// \param q a reference for the quotient + /// \param a reference to the dividend + /// \param d reference to the divisor + /// \details Divide calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)). + static void CRYPTOPP_API Divide(Integer &r, Integer &q, const Integer &a, const Integer &d); + + /// \brief Extended Division + /// \param r a reference for the remainder + /// \param q a reference for the quotient + /// \param a reference to the dividend + /// \param d reference to the divisor + /// \details Divide calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)). + /// This overload uses a faster division algorithm because the divisor is short. + static void CRYPTOPP_API Divide(word &r, Integer &q, const Integer &a, word d); + + /// \brief Extended Division + /// \param r a reference for the remainder + /// \param q a reference for the quotient + /// \param a reference to the dividend + /// \param n reference to the divisor + /// \details DivideByPowerOf2 calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)). + /// It returns same result as Divide(r, q, a, Power2(n)), but faster. + /// This overload uses a faster division algorithm because the divisor is a power of 2. + static void CRYPTOPP_API DivideByPowerOf2(Integer &r, Integer &q, const Integer &a, unsigned int n); + + /// \brief Calculate greatest common divisor + /// \param a reference to the first number + /// \param n reference to the secind number + /// \return the greatest common divisor a and n. + static Integer CRYPTOPP_API Gcd(const Integer &a, const Integer &n); + + /// \brief Calculate multiplicative inverse + /// \param n reference to the modulus + /// \return an Integer *this % n. + /// \details InverseMod returns the multiplicative inverse of the Integer *this + /// modulo the Integer n. If no Integer exists then Integer 0 is returned. + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + Integer InverseMod(const Integer &n) const; + + /// \brief Calculate multiplicative inverse + /// \param n the modulus + /// \return a word *this % n. + /// \details InverseMod returns the multiplicative inverse of the Integer *this + /// modulo the word n. If no Integer exists then word 0 is returned. + /// \sa a_times_b_mod_c() and a_exp_b_mod_c() + word InverseMod(word n) const; + //@} + + /// \name INPUT/OUTPUT + //@{ + /// \brief Extraction operator + /// \param in reference to a std::istream + /// \param a reference to an Integer + /// \return reference to a std::istream reference + friend CRYPTOPP_DLL std::istream& CRYPTOPP_API operator>>(std::istream& in, Integer &a); + + /// \brief Insertion operator + /// \param out reference to a std::ostream + /// \param a a constant reference to an Integer + /// \return reference to a std::ostream reference + /// \details The output integer responds to hex, std::oct, std::hex, std::upper and + /// std::lower. The output includes the suffix \a h (for hex), \a . (\a dot, for dec) + /// and \a o (for octal). There is currently no way to suppress the suffix. + /// \details If you want to print an Integer without the suffix or using an arbitrary base, then + /// use IntToString(). + /// \sa IntToString + friend CRYPTOPP_DLL std::ostream& CRYPTOPP_API operator<<(std::ostream& out, const Integer &a); + //@} + + /// \brief Modular multiplication + /// \param x reference to the first term + /// \param y reference to the second term + /// \param m reference to the modulus + /// \return an Integer (a * b) % m. + CRYPTOPP_DLL friend Integer CRYPTOPP_API a_times_b_mod_c(const Integer &x, const Integer& y, const Integer& m); + /// \brief Modular exponentiation + /// \param x reference to the base + /// \param e reference to the exponent + /// \param m reference to the modulus + /// \return an Integer (a ^ b) % m. + CRYPTOPP_DLL friend Integer CRYPTOPP_API a_exp_b_mod_c(const Integer &x, const Integer& e, const Integer& m); + +protected: + + // http://github.com/weidai11/cryptopp/issues/602 + Integer InverseModNext(const Integer &n) const; + +private: + + Integer(word value, size_t length); + int PositiveCompare(const Integer &t) const; + + IntegerSecBlock reg; + Sign sign; + +#ifndef CRYPTOPP_DOXYGEN_PROCESSING + friend class ModularArithmetic; + friend class MontgomeryRepresentation; + friend class HalfMontgomeryRepresentation; + + friend void PositiveAdd(Integer &sum, const Integer &a, const Integer &b); + friend void PositiveSubtract(Integer &diff, const Integer &a, const Integer &b); + friend void PositiveMultiply(Integer &product, const Integer &a, const Integer &b); + friend void PositiveDivide(Integer &remainder, Integer "ient, const Integer ÷nd, const Integer &divisor); +#endif +}; + +/// \brief Comparison +inline bool operator==(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)==0;} +/// \brief Comparison +inline bool operator!=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)!=0;} +/// \brief Comparison +inline bool operator> (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)> 0;} +/// \brief Comparison +inline bool operator>=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)>=0;} +/// \brief Comparison +inline bool operator< (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)< 0;} +/// \brief Comparison +inline bool operator<=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)<=0;} +/// \brief Addition +inline CryptoPP::Integer operator+(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Plus(b);} +/// \brief Subtraction +inline CryptoPP::Integer operator-(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Minus(b);} +/// \brief Multiplication +/// \sa a_times_b_mod_c() and a_exp_b_mod_c() +inline CryptoPP::Integer operator*(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Times(b);} +/// \brief Division +inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.DividedBy(b);} +/// \brief Remainder +/// \sa a_times_b_mod_c() and a_exp_b_mod_c() +inline CryptoPP::Integer operator%(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Modulo(b);} +/// \brief Division +inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, CryptoPP::word b) {return a.DividedBy(b);} +/// \brief Remainder +/// \sa a_times_b_mod_c() and a_exp_b_mod_c() +inline CryptoPP::word operator%(const CryptoPP::Integer &a, CryptoPP::word b) {return a.Modulo(b);} + +/// \brief Bitwise AND +/// \param a the first Integer +/// \param b the second Integer +/// \return the result of a & b +/// \details operator&() performs a bitwise AND on the operands. Missing bits are truncated +/// at the most significant bit positions, so the result is as small as the +/// smaller of the operands. +/// \details Internally, Crypto++ uses a sign-magnitude representation. The library +/// does not attempt to interpret bits, and the result is always POSITIVE. If needed, +/// the integer should be converted to a 2's compliment representation before performing +/// the operation. +/// \since Crypto++ 6.0 +inline CryptoPP::Integer operator&(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.And(b);} + +/// \brief Bitwise OR +/// \param a the first Integer +/// \param b the second Integer +/// \return the result of a | b +/// \details operator|() performs a bitwise OR on the operands. Missing bits are shifted in +/// at the most significant bit positions, so the result is as large as the +/// larger of the operands. +/// \details Internally, Crypto++ uses a sign-magnitude representation. The library +/// does not attempt to interpret bits, and the result is always POSITIVE. If needed, +/// the integer should be converted to a 2's compliment representation before performing +/// the operation. +/// \since Crypto++ 6.0 +inline CryptoPP::Integer operator|(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Or(b);} + +/// \brief Bitwise XOR +/// \param a the first Integer +/// \param b the second Integer +/// \return the result of a ^ b +/// \details operator^() performs a bitwise XOR on the operands. Missing bits are shifted +/// in at the most significant bit positions, so the result is as large as the +/// larger of the operands. +/// \details Internally, Crypto++ uses a sign-magnitude representation. The library +/// does not attempt to interpret bits, and the result is always POSITIVE. If needed, +/// the integer should be converted to a 2's compliment representation before performing +/// the operation. +/// \since Crypto++ 6.0 +inline CryptoPP::Integer operator^(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Xor(b);} + +NAMESPACE_END + +#ifndef __BORLANDC__ +NAMESPACE_BEGIN(std) +inline void swap(CryptoPP::Integer &a, CryptoPP::Integer &b) +{ + a.swap(b); +} +NAMESPACE_END +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/iterhash.h b/third_party/cryptoppwin/include/cryptopp/iterhash.h new file mode 100644 index 00000000..af916d9c --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/iterhash.h @@ -0,0 +1,218 @@ +// iterhash.h - originally written and placed in the public domain by Wei Dai + +/// \file iterhash.h +/// \brief Base classes for iterated hashes + +#ifndef CRYPTOPP_ITERHASH_H +#define CRYPTOPP_ITERHASH_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" +#include "simple.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6011 6386 28193) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when trying to hash more data than is allowed by a hash function +class CRYPTOPP_DLL HashInputTooLong : public InvalidDataFormat +{ +public: + explicit HashInputTooLong(const std::string &alg) + : InvalidDataFormat("IteratedHashBase: input data exceeds maximum allowed by hash function " + alg) {} +}; + +/// \brief Iterated hash base class +/// \tparam T Hash word type +/// \tparam BASE HashTransformation derived class +/// \details IteratedHashBase provides an interface for block-based iterated hashes +/// \sa HashTransformation, MessageAuthenticationCode +template +class CRYPTOPP_NO_VTABLE IteratedHashBase : public BASE +{ +public: + typedef T HashWordType; + + virtual ~IteratedHashBase() {} + + /// \brief Construct an IteratedHashBase + IteratedHashBase() : m_countLo(0), m_countHi(0) {} + + /// \brief Provides the input block size most efficient for this cipher. + /// \return The input block size that is most efficient for the cipher + /// \details The base class implementation returns MandatoryBlockSize(). + /// \note Optimal input length is + /// n * OptimalBlockSize() - GetOptimalBlockSizeUsed() for any n \> 0. + unsigned int OptimalBlockSize() const {return this->BlockSize();} + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \details OptimalDataAlignment returns the natural alignment of the hash word. + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + /// \brief Updates a hash with additional input + /// \param input the additional input as a buffer + /// \param length the size of the buffer, in bytes + void Update(const byte *input, size_t length); + + /// \brief Requests space which can be written into by the caller + /// \param size the requested size of the buffer + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink, cannot create a space because its fixed. + byte * CreateUpdateSpace(size_t &size); + + /// \brief Restart the hash + /// \details Discards the current state, and restart for a new message + void Restart(); + + /// \brief Computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param digestSize the size of the truncated digest, in bytes + /// \details TruncatedFinal() calls Final() and then copies digestSize bytes to digest. + /// The hash is restarted the hash for the next message. + void TruncatedFinal(byte *digest, size_t digestSize); + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \note Provider is not universally implemented yet. + virtual std::string AlgorithmProvider() const { return "C++"; } + +protected: + inline T GetBitCountHi() const + {return (m_countLo >> (8*sizeof(T)-3)) + (m_countHi << 3);} + inline T GetBitCountLo() const + {return m_countLo << 3;} + + void PadLastBlock(unsigned int lastBlockSize, byte padFirst=0x80); + virtual void Init() =0; + + virtual ByteOrder GetByteOrder() const =0; + virtual void HashEndianCorrectedBlock(const HashWordType *data) =0; + virtual size_t HashMultipleBlocks(const T *input, size_t length); + void HashBlock(const HashWordType *input) + {HashMultipleBlocks(input, this->BlockSize());} + + virtual T* DataBuf() =0; + virtual T* StateBuf() =0; + +private: + T m_countLo, m_countHi; +}; + +/// \brief Iterated hash base class +/// \tparam T_HashWordType Hash word type +/// \tparam T_Endianness Endianness type of hash +/// \tparam T_BlockSize Block size of the hash +/// \tparam T_Base HashTransformation derived class +/// \details IteratedHash provides a default implementation for block-based iterated hashes +/// \sa HashTransformation, MessageAuthenticationCode +template +class CRYPTOPP_NO_VTABLE IteratedHash : public IteratedHashBase +{ +public: + typedef T_Endianness ByteOrderClass; + typedef T_HashWordType HashWordType; + + CRYPTOPP_CONSTANT(BLOCKSIZE = T_BlockSize); + // BCB2006 workaround: can't use BLOCKSIZE here + CRYPTOPP_COMPILE_ASSERT((T_BlockSize & (T_BlockSize - 1)) == 0); // blockSize is a power of 2 + + virtual ~IteratedHash() {} + + /// \brief Provides the block size of the hash + /// \return the block size of the hash, in bytes + /// \details BlockSize() returns T_BlockSize. + unsigned int BlockSize() const {return T_BlockSize;} + + /// \brief Provides the byte order of the hash + /// \return the byte order of the hash as an enumeration + /// \details GetByteOrder() returns T_Endianness::ToEnum(). + /// \sa ByteOrder() + ByteOrder GetByteOrder() const {return T_Endianness::ToEnum();} + + /// \brief Adjusts the byte ordering of the hash + /// \param out the output buffer + /// \param in the input buffer + /// \param byteCount the size of the buffers, in bytes + /// \details CorrectEndianess() calls ConditionalByteReverse() using T_Endianness. + inline void CorrectEndianess(HashWordType *out, const HashWordType *in, size_t byteCount) + { + CRYPTOPP_ASSERT(in != NULLPTR); + CRYPTOPP_ASSERT(out != NULLPTR); + CRYPTOPP_ASSERT(IsAligned(in)); + CRYPTOPP_ASSERT(IsAligned(out)); + + ConditionalByteReverse(T_Endianness::ToEnum(), out, in, byteCount); + } + +protected: + enum { Blocks = T_BlockSize/sizeof(T_HashWordType) }; + T_HashWordType* DataBuf() {return this->m_data;} + FixedSizeSecBlock m_data; +}; + +/// \brief Iterated hash with a static transformation function +/// \tparam T_HashWordType Hash word type +/// \tparam T_Endianness Endianness type of hash +/// \tparam T_BlockSize Block size of the hash +/// \tparam T_StateSize Internal state size of the hash +/// \tparam T_Transform HashTransformation derived class +/// \tparam T_DigestSize Digest size of the hash +/// \tparam T_StateAligned Flag indicating if state is 16-byte aligned +/// \sa HashTransformation, MessageAuthenticationCode +template +class CRYPTOPP_NO_VTABLE IteratedHashWithStaticTransform + : public ClonableImpl, T_Transform> > +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = T_DigestSize ? T_DigestSize : T_StateSize); + + virtual ~IteratedHashWithStaticTransform() {} + + /// \brief Provides the digest size of the hash + /// \return the digest size of the hash, in bytes + /// \details DigestSize() returns DIGESTSIZE. + unsigned int DigestSize() const {return DIGESTSIZE;} + +protected: + // https://github.com/weidai11/cryptopp/issues/147#issuecomment-766231864 + IteratedHashWithStaticTransform() {IteratedHashWithStaticTransform::Init();} + void HashEndianCorrectedBlock(const T_HashWordType *data) {T_Transform::Transform(this->m_state, data);} + void Init() {T_Transform::InitState(this->m_state);} + + enum { Blocks = T_BlockSize/sizeof(T_HashWordType) }; + T_HashWordType* StateBuf() {return this->m_state;} + FixedSizeAlignedSecBlock m_state; +}; + +#if !defined(__GNUC__) && !defined(__clang__) + CRYPTOPP_DLL_TEMPLATE_CLASS IteratedHashBase; + CRYPTOPP_STATIC_TEMPLATE_CLASS IteratedHashBase; + + CRYPTOPP_DLL_TEMPLATE_CLASS IteratedHashBase; + CRYPTOPP_STATIC_TEMPLATE_CLASS IteratedHashBase; +#endif + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/kalyna.h b/third_party/cryptoppwin/include/cryptopp/kalyna.h new file mode 100644 index 00000000..0466ac14 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/kalyna.h @@ -0,0 +1,218 @@ +// kalyna.h - written and placed in the public domain by Jeffrey Walton +// Based on public domain code by Keru Kuro. + +/// \file kalyna.h +/// \brief Classes for the Kalyna block cipher +/// \details The Crypto++ implementation relied upon three sources. First was Oliynykov, Gorbenko, Kazymyrov, +/// Ruzhentsev, Kuznetsov, Gorbenko, Dyrda, Dolgov, Pushkaryov, Mordvinov and Kaidalov's "A New Encryption +/// Standard of Ukraine: The Kalyna Block Cipher" (http://eprint.iacr.org/2015/650.pdf). Second was Roman +/// Oliynykov and Oleksandr Kazymyrov's GitHub with the reference implementation +/// (http://github.com/Roman-Oliynykov/Kalyna-reference). The third resource was Keru Kuro's implementation +/// of Kalyna in CppCrypto (http://sourceforge.net/projects/cppcrypto/). Kuro has an outstanding +/// implementation that performed better than the reference implementation and our initial attempts. + +#ifndef CRYPTOPP_KALYNA_H +#define CRYPTOPP_KALYNA_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Kalyna-128 block cipher information +/// \since Crypto++ 6.0 +struct CRYPTOPP_NO_VTABLE Kalyna128_Info : public FixedBlockSize<16>, VariableKeyLength<16, 16, 32> +{ + static const char* StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "Kalyna-128"; + } +}; + +/// \brief Kalyna-256 block cipher information +/// \since Crypto++ 6.0 +struct CRYPTOPP_NO_VTABLE Kalyna256_Info : public FixedBlockSize<32>, VariableKeyLength<32, 32, 64> +{ + static const char* StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "Kalyna-256"; + } +}; + +/// \brief Kalyna-512 block cipher information +/// \since Crypto++ 6.0 +struct CRYPTOPP_NO_VTABLE Kalyna512_Info : public FixedBlockSize<64>, FixedKeyLength<64> +{ + static const char* StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "Kalyna-512"; + } +}; + +/// \brief Kalyna block cipher base class +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE Kalyna_Base +{ +public: + virtual ~Kalyna_Base() {} + +protected: + typedef SecBlock > AlignedSecBlock64; + mutable AlignedSecBlock64 m_wspace; // work space + AlignedSecBlock64 m_mkey; // master key + AlignedSecBlock64 m_rkeys; // round keys + unsigned int m_kl, m_nb, m_nk; // number 64-bit blocks and keys +}; + +/// \brief Kalyna 128-bit block cipher +/// \details Kalyna128 provides 128-bit block size. The valid key sizes are 128-bit and 256-bit. +/// \since Crypto++ 6.0 +class Kalyna128 : public Kalyna128_Info, public BlockCipherDocumentation +{ +public: + class CRYPTOPP_NO_VTABLE Base : public Kalyna_Base, public BlockCipherImpl + { + public: + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details If the object is unkeyed, then the generic name "Kalyna" is returned + /// to the caller. If the algorithm is keyed, then a two or three part name is + /// returned to the caller. The name follows DSTU 7624:2014, where block size is + /// provided first and then key length. The library uses a dash to identify block size + /// and parenthesis to identify key length. For example, Kalyna-128(256) is Kalyna + /// with a 128-bit block size and a 256-bit key length. If a mode is associated + /// with the object, then it follows as expected. For example, Kalyna-128(256)/ECB. + /// DSTU is a little more complex with more parameters, dashes, underscores, but the + /// library does not use the delimiters or full convention. + std::string AlgorithmName() const { + return std::string("Kalyna-128") + "(" + IntToString(m_kl*8) + ")"; + } + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const { + return GetAlignmentOf(); + } + + protected: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + void SetKey_22(const word64 key[2]); + void SetKey_24(const word64 key[4]); + void ProcessBlock_22(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + void ProcessBlock_24(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief Kalyna 256-bit block cipher +/// \details Kalyna256 provides 256-bit block size. The valid key sizes are 256-bit and 512-bit. +/// \since Crypto++ 6.0 +class Kalyna256 : public Kalyna256_Info, public BlockCipherDocumentation +{ +public: + class CRYPTOPP_NO_VTABLE Base : public Kalyna_Base, public BlockCipherImpl + { + public: + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details If the object is unkeyed, then the generic name "Kalyna" is returned + /// to the caller. If the algorithm is keyed, then a two or three part name is + /// returned to the caller. The name follows DSTU 7624:2014, where block size is + /// provided first and then key length. The library uses a dash to identify block size + /// and parenthesis to identify key length. For example, Kalyna-128(256) is Kalyna + /// with a 128-bit block size and a 256-bit key length. If a mode is associated + /// with the object, then it follows as expected. For example, Kalyna-128(256)/ECB. + /// DSTU is a little more complex with more parameters, dashes, underscores, but the + /// library does not use the delimiters or full convention. + std::string AlgorithmName() const { + return std::string("Kalyna-256") + "(" + IntToString(m_kl*8) + ")"; + } + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const { + return GetAlignmentOf(); + } + + protected: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + void SetKey_44(const word64 key[4]); + void SetKey_48(const word64 key[8]); + void ProcessBlock_44(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + void ProcessBlock_48(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief Kalyna 512-bit block cipher +/// \details Kalyna512 provides 512-bit block size. The valid key size is 512-bit. +/// \since Crypto++ 6.0 +class Kalyna512 : public Kalyna512_Info, public BlockCipherDocumentation +{ +public: + class CRYPTOPP_NO_VTABLE Base : public Kalyna_Base, public BlockCipherImpl + { + public: + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details If the object is unkeyed, then the generic name "Kalyna" is returned + /// to the caller. If the algorithm is keyed, then a two or three part name is + /// returned to the caller. The name follows DSTU 7624:2014, where block size is + /// provided first and then key length. The library uses a dash to identify block size + /// and parenthesis to identify key length. For example, Kalyna-128(256) is Kalyna + /// with a 128-bit block size and a 256-bit key length. If a mode is associated + /// with the object, then it follows as expected. For example, Kalyna-128(256)/ECB. + /// DSTU is a little more complex with more parameters, dashes, underscores, but the + /// library does not use the delimiters or full convention. + std::string AlgorithmName() const { + return std::string("Kalyna-512") + "(" + IntToString(m_kl*8) + ")"; + } + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const { + return GetAlignmentOf(); + } + + protected: + void UncheckedSetKey(const byte *key, unsigned int keylen, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + void SetKey_88(const word64 key[8]); + void ProcessBlock_88(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Kalyna128::Encryption Kalyna128Encryption; +typedef Kalyna128::Decryption Kalyna128Decryption; + +typedef Kalyna256::Encryption Kalyna256Encryption; +typedef Kalyna256::Decryption Kalyna256Decryption; + +typedef Kalyna512::Encryption Kalyna512Encryption; +typedef Kalyna512::Decryption Kalyna512Decryption; + +NAMESPACE_END + +#endif // CRYPTOPP_KALYNA_H diff --git a/third_party/cryptoppwin/include/cryptopp/keccak.h b/third_party/cryptoppwin/include/cryptopp/keccak.h new file mode 100644 index 00000000..2d9e3603 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/keccak.h @@ -0,0 +1,118 @@ +// keccak.h - originally written and placed in the public domain by Wei Dai + +/// \file keccak.h +/// \brief Classes for Keccak message digests +/// \details The Crypto++ Keccak implementation uses F1600 with XOF d=0x01. +/// FIPS 202 conformance (XOF d=0x06) is available in SHA3 classes. +/// \details Keccak will likely change in the future to accommodate extensibility of the +/// round function and the XOF functions. +/// \sa Keccak +/// \since Crypto++ 5.6.4 + +#ifndef CRYPTOPP_KECCAK_H +#define CRYPTOPP_KECCAK_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Keccak message digest base class +/// \details The Crypto++ Keccak implementation uses F1600 with XOF d=0x01. +/// FIPS 202 conformance (XOF d=0x06) is available in SHA3 classes. +/// \details Keccak is the base class for Keccak_224, Keccak_256, Keccak_384 and Keccak_512. +/// Library users should instantiate a derived class, and only use Keccak +/// as a base class reference or pointer. +/// \details Keccak will likely change in the future to accommodate extensibility of the +/// round function and the XOF functions. +/// \details Perform the following to specify a different digest size. The class will use F1600, +/// XOF d=0x01, and a new value for r() (which will be 200-2*24 = 152). +///
  Keccack_192 : public Keccack
+///   {
+///     public:
+///       CRYPTOPP_CONSTANT(DIGESTSIZE = 24);
+///       Keccack_192() : Keccack(DIGESTSIZE) {}
+///   };
+///   
+/// +/// \sa SHA3, Keccak_224, Keccak_256, Keccak_384 and Keccak_512. +/// \since Crypto++ 5.6.4 +class Keccak : public HashTransformation +{ +protected: + /// \brief Construct a Keccak + /// \param digestSize the digest size, in bytes + /// \details Keccak is the base class for Keccak_224, Keccak_256, Keccak_384 and Keccak_512. + /// Library users should instantiate a derived class, and only use Keccak + /// as a base class reference or pointer. + /// \details This constructor was moved to protected at Crypto++ 8.1 + /// because users were attempting to create Keccak objects with it. + /// \since Crypto++ 5.6.4 + Keccak(unsigned int digestSize) : m_digestSize(digestSize) {Restart();} + +public: + unsigned int DigestSize() const {return m_digestSize;} + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + void Update(const byte *input, size_t length); + void Restart(); + void TruncatedFinal(byte *hash, size_t size); + +protected: + inline unsigned int r() const {return BlockSize();} + + FixedSizeSecBlock m_state; + unsigned int m_digestSize, m_counter; +}; + +/// \brief Keccak message digest template +/// \tparam T_DigestSize the size of the digest, in bytes +/// \since Crypto++ 6.0 +template +class Keccak_Final : public Keccak +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = T_DigestSize); + CRYPTOPP_CONSTANT(BLOCKSIZE = 200 - 2 * DIGESTSIZE); + static std::string StaticAlgorithmName() + { return "Keccak-" + IntToString(DIGESTSIZE * 8); } + + /// \brief Construct a Keccak-X message digest + Keccak_Final() : Keccak(DIGESTSIZE) {} + + /// \brief Provides the block size of the compression function + /// \return block size of the compression function, in bytes + /// \details BlockSize() will return 0 if the hash is not block based + /// or does not have an equivalent block size. For example, Keccak + /// and SHA-3 do not have a block size, but they do have an equivalent + /// block size called rate expressed as r. + unsigned int BlockSize() const { return BLOCKSIZE; } + + std::string AlgorithmName() const { return StaticAlgorithmName(); } + +private: +#if !defined(__BORLANDC__) + // ensure there was no underflow in the math + CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE < 200); +#endif +}; + +/// \brief Keccak-224 message digest +/// \since Crypto++ 5.6.4 +DOCUMENTED_TYPEDEF(Keccak_Final<28>, Keccak_224); + +/// \brief Keccak-256 message digest +/// \since Crypto++ 5.6.4 +DOCUMENTED_TYPEDEF(Keccak_Final<32>, Keccak_256); + +/// \brief Keccak-384 message digest +/// \since Crypto++ 5.6.4 +DOCUMENTED_TYPEDEF(Keccak_Final<48>, Keccak_384); + +/// \brief Keccak-512 message digest +/// \since Crypto++ 5.6.4 +DOCUMENTED_TYPEDEF(Keccak_Final<64>, Keccak_512); + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/lea.h b/third_party/cryptoppwin/include/cryptopp/lea.h new file mode 100644 index 00000000..3ede3813 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/lea.h @@ -0,0 +1,108 @@ +// lea.h - written and placed in the public domain by Kim Sung Hee and Jeffrey Walton +// Based on "LEA: A 128-Bit Block Cipher for Fast Encryption on Common +// Processors" by Deukjo Hong, Jung-Keun Lee, Dong-Chan Kim, Daesung Kwon, +// Kwon Ho Ryu, and Dong-Geon Lee. + +/// \file lea.h +/// \brief Classes for the LEA block cipher +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_LEA_H +#define CRYPTOPP_LEA_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" + +#if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8) +# ifndef CRYPTOPP_DISABLE_LEA_SIMD +# define CRYPTOPP_LEA_ADVANCED_PROCESS_BLOCKS 1 +# endif +#endif + +// Yet another SunStudio/SunCC workaround. Failed self tests +// in SSE code paths on i386 for SunStudio 12.3 and below. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120) +# undef CRYPTOPP_LEA_ADVANCED_PROCESS_BLOCKS +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief LEA block cipher information +/// \since Crypto++ 8.0 +struct LEA_Info : public FixedBlockSize<16>, public VariableKeyLength<16,16,32,8> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize + return "LEA-128"; + } +}; + +/// \brief LEA 128-bit block cipher +/// \details LEA provides 128-bit block size. The valid key size is 128-bits, 192-bits and 256-bits. +/// \note Crypto++ provides a byte oriented implementation +/// \sa LEA, +/// +/// LEA: A 128-Bit Block Cipher for Fast Encryption on Common Processors +/// \since Crypto++ 8.0 +class CRYPTOPP_NO_VTABLE LEA : public LEA_Info, public BlockCipherDocumentation +{ +public: + /// \brief LEA block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + std::string AlgorithmProvider() const; + + SecBlock m_rkey; + mutable SecBlock m_temp; + unsigned int m_rounds; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_LEA_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_LEA_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef LEA::Encryption LEAEncryption; +typedef LEA::Decryption LEADecryption; + +NAMESPACE_END + +#endif // CRYPTOPP_LEA_H diff --git a/third_party/cryptoppwin/include/cryptopp/lsh.h b/third_party/cryptoppwin/include/cryptopp/lsh.h new file mode 100644 index 00000000..f89630a7 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/lsh.h @@ -0,0 +1,262 @@ +// lsh.h - written and placed in the public domain by Jeffrey Walton +// Based on the specification and source code provided by +// Korea Internet & Security Agency (KISA) website. Also +// see https://seed.kisa.or.kr/kisa/algorithm/EgovLSHInfo.do +// and https://seed.kisa.or.kr/kisa/Board/22/detailView.do. + +// We are hitting some sort of GCC bug in the LSH AVX2 code path. +// Clang is OK on the AVX2 code path. We believe it is GCC Issue +// 82735, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82735. It +// makes using zeroupper a little tricky. + +/// \file lsh.h +/// \brief Classes for the LSH hash functions +/// \since Crypto++ 8.6 +/// \sa LSH +/// on the Korea Internet & Security Agency (KISA) website. +#ifndef CRYPTOPP_LSH_H +#define CRYPTOPP_LSH_H + +#include "cryptlib.h" +#include "secblock.h" + +// Enable SSE2 and AVX2 for 64-bit machines. +// 32-bit machines slow down with SSE2. +#if (CRYPTOPP_BOOL_X32) || (CRYPTOPP_BOOL_X64) +# define CRYPTOPP_ENABLE_64BIT_SSE 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief LSH-224 and LSH-256 hash base class +/// \details LSH256_Base is the base class for both LSH-224 and LSH-256 +/// \since Crypto++ 8.6 +class LSH256_Base : public HashTransformation +{ +public: + /// \brief Block size, in bytes + /// \details LSH_256 uses LSH256_MSG_BLK_BYTE_LEN for block size, which is 128 + CRYPTOPP_CONSTANT(BLOCKSIZE = 128); + + virtual ~LSH256_Base() {} + + unsigned int BlockSize() const { return BLOCKSIZE; } + unsigned int DigestSize() const { return m_digestSize; } + unsigned int OptimalDataAlignment() const { return GetAlignmentOf(); } + + void Restart(); + void Update(const byte *input, size_t size); + void TruncatedFinal(byte *hash, size_t size); + + std::string AlgorithmProvider() const; + +protected: + LSH256_Base(unsigned int algType, unsigned int digestSize) + : m_digestSize(digestSize) { m_state[80] = algType; } + +protected: + // Working state is: + // * cv_l = 8 32-bit words + // * cv_r = 8 32-bit words + // * submsg_e_l = 8 32-bit words + // * submsg_e_r = 8 32-bit words + // * submsg_o_l = 8 32-bit words + // * submsg_o_r = 8 32-bit words + // * last_block = 32 32-bit words (128 bytes) + // * algType + // * remainingBitLength + FixedSizeSecBlock m_state; + // word32 m_algType, m_remainingBitLength; + word32 m_digestSize; +}; + +/// \brief LSH-224 hash function +/// \sa LSH +/// on the Korea Internet & Security Agency (KISA) website. +/// \since Crypto++ 8.6 +class LSH224 : public LSH256_Base +{ +public: + /// \brief Digest size, in bytes + /// \details LSH_256 uses LSH_GET_HASHBYTE(algType) for digest size, which is 28 + CRYPTOPP_CONSTANT(DIGESTSIZE = 28); + /// \brief Block size, in bytes + /// \details LSH_256 uses LSH256_MSG_BLK_BYTE_LEN for block size, which is 128 + CRYPTOPP_CONSTANT(BLOCKSIZE = LSH256_Base::BLOCKSIZE); + + /// \brief The algorithm's name + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like AES or AES/GCM. + /// Some algorithms do not have standard names yet. For example, there is no standard + /// algorithm name for Shoup's ECIES. + /// \note StaticAlgorithmName is not universally implemented yet. + static std::string StaticAlgorithmName() { return "LSH-224"; } + + /// \brief Construct a LSH-224 + /// \details LSH_TYPE_224 is the magic value 0x000001C defined in lsh.cpp. + LSH224() : LSH256_Base(0x000001C, DIGESTSIZE) { Restart(); } + + std::string AlgorithmName() const { return StaticAlgorithmName(); } +}; + +/// \brief LSH-256 hash function +/// \sa LSH +/// on the Korea Internet & Security Agency (KISA) website. +/// \since Crypto++ 8.6 +class LSH256 : public LSH256_Base +{ +public: + /// \brief Digest size, in bytes + /// \details LSH_256 uses LSH_GET_HASHBYTE(algType) for digest size, which is 32 + CRYPTOPP_CONSTANT(DIGESTSIZE = 32); + /// \brief Block size, in bytes + /// \details LSH_256 uses LSH256_MSG_BLK_BYTE_LEN for block size, which is 128 + CRYPTOPP_CONSTANT(BLOCKSIZE = LSH256_Base::BLOCKSIZE); + + /// \brief The algorithm's name + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like AES or AES/GCM. + /// Some algorithms do not have standard names yet. For example, there is no standard + /// algorithm name for Shoup's ECIES. + /// \note StaticAlgorithmName is not universally implemented yet. + static std::string StaticAlgorithmName() { return "LSH-256"; } + + /// \brief Construct a LSH-256 + /// \details LSH_TYPE_256 is the magic value 0x0000020 defined in lsh.cpp. + LSH256() : LSH256_Base(0x0000020, DIGESTSIZE) { Restart(); } + + std::string AlgorithmName() const { return StaticAlgorithmName(); } +}; + +/// \brief LSH-384 and LSH-512 hash base class +/// \details LSH512_Base is the base class for both LSH-384 and LSH-512 +/// \since Crypto++ 8.6 +class LSH512_Base : public HashTransformation +{ +public: + /// \brief Block size, in bytes + /// \details LSH_512 uses LSH512_MSG_BLK_BYTE_LEN for block size, which is 256 + CRYPTOPP_CONSTANT(BLOCKSIZE = 256); + + virtual ~LSH512_Base() {} + + unsigned int BlockSize() const { return BLOCKSIZE; } + unsigned int DigestSize() const { return m_digestSize; } + unsigned int OptimalDataAlignment() const { return GetAlignmentOf(); } + + void Restart(); + void Update(const byte *input, size_t size); + void TruncatedFinal(byte *hash, size_t size); + + std::string AlgorithmProvider() const; + +protected: + LSH512_Base(unsigned int algType, unsigned int digestSize) + : m_digestSize(digestSize) { m_state[80] = algType; } + +protected: + // Working state is: + // * cv_l = 8 64-bit words + // * cv_r = 8 64-bit words + // * submsg_e_l = 8 64-bit words + // * submsg_e_r = 8 64-bit words + // * submsg_o_l = 8 64-bit words + // * submsg_o_r = 8 64-bit words + // * last_block = 32 64-bit words (256 bytes) + // * algType + // * remainingBitLength + FixedSizeSecBlock m_state; + // word32 m_algType, m_remainingBitLength; + word32 m_digestSize; +}; + +/// \brief LSH-384 hash function +/// \sa LSH +/// on the Korea Internet & Security Agency (KISA) website. +/// \since Crypto++ 8.6 +class LSH384 : public LSH512_Base +{ +public: + /// \brief Digest size, in bytes + /// \details LSH_512 uses LSH_GET_HASHBYTE(algType) for digest size, which is 48 + CRYPTOPP_CONSTANT(DIGESTSIZE = 48); + /// \brief Block size, in bytes + /// \details LSH_512 uses LSH512_MSG_BLK_BYTE_LEN for block size, which is 256 + CRYPTOPP_CONSTANT(BLOCKSIZE = LSH512_Base::BLOCKSIZE); + + /// \brief The algorithm's name + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like AES or AES/GCM. + /// Some algorithms do not have standard names yet. For example, there is no standard + /// algorithm name for Shoup's ECIES. + /// \note StaticAlgorithmName is not universally implemented yet. + static std::string StaticAlgorithmName() { return "LSH-384"; } + + /// \brief Construct a LSH-384 + /// \details LSH_TYPE_384 is the magic value 0x0010030 defined in lsh.cpp. + LSH384() : LSH512_Base(0x0010030, DIGESTSIZE) { Restart(); } + + std::string AlgorithmName() const { return StaticAlgorithmName(); } +}; + +/// \brief LSH-512 hash function +/// \sa LSH +/// on the Korea Internet & Security Agency (KISA) website. +/// \since Crypto++ 8.6 +class LSH512 : public LSH512_Base +{ +public: + /// \brief Digest size, in bytes + /// \details LSH_512 uses LSH_GET_HASHBYTE(algType) for digest size, which is 64 + CRYPTOPP_CONSTANT(DIGESTSIZE = 64); + /// \brief Block size, in bytes + /// \details LSH_512 uses LSH512_MSG_BLK_BYTE_LEN for block size, which is 256 + CRYPTOPP_CONSTANT(BLOCKSIZE = LSH512_Base::BLOCKSIZE); + + /// \brief The algorithm's name + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like AES or AES/GCM. + /// Some algorithms do not have standard names yet. For example, there is no standard + /// algorithm name for Shoup's ECIES. + /// \note StaticAlgorithmName is not universally implemented yet. + static std::string StaticAlgorithmName() { return "LSH-512"; } + + /// \brief Construct a LSH-512 + /// \details LSH_TYPE_512 is the magic value 0x0010040 defined in lsh.cpp. + LSH512() : LSH512_Base(0x0010040, DIGESTSIZE) { Restart(); } + + std::string AlgorithmName() const { return StaticAlgorithmName(); } +}; + +/// \brief LSH-512-256 hash function +/// \sa LSH +/// on the Korea Internet & Security Agency (KISA) website. +/// \since Crypto++ 8.6 +class LSH512_256 : public LSH512_Base +{ +public: + /// \brief Digest size, in bytes + /// \details LSH_512 uses LSH_GET_HASHBYTE(algType) for digest size, which is 32 + CRYPTOPP_CONSTANT(DIGESTSIZE = 32); + /// \brief Block size, in bytes + /// \details LSH_512 uses LSH512_MSG_BLK_BYTE_LEN for block size, which is 256 + CRYPTOPP_CONSTANT(BLOCKSIZE = LSH512_Base::BLOCKSIZE); + + /// \brief The algorithm's name + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like AES or AES/GCM. + /// Some algorithms do not have standard names yet. For example, there is no standard + /// algorithm name for Shoup's ECIES. + /// \note StaticAlgorithmName is not universally implemented yet. + static std::string StaticAlgorithmName() { return "LSH-512-256"; } + + /// \brief Construct a LSH-512-256 + /// \details LSH_TYPE_512_256 is the magic value 0x0010020 defined in lsh.cpp. + LSH512_256() : LSH512_Base(0x0010020, DIGESTSIZE) { Restart(); } + + std::string AlgorithmName() const { return StaticAlgorithmName(); } +}; + +NAMESPACE_END + +#endif // CRYPTOPP_LSH_H diff --git a/third_party/cryptoppwin/include/cryptopp/lubyrack.h b/third_party/cryptoppwin/include/cryptopp/lubyrack.h new file mode 100644 index 00000000..e671303d --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/lubyrack.h @@ -0,0 +1,137 @@ +// lubyrack.h - originally written and placed in the public domain by Wei Dai + +/// \file lubyrack.h +/// \brief Classes for the Luby-Rackoff block cipher + +#ifndef CRYPTOPP_LUBYRACK_H +#define CRYPTOPP_LUBYRACK_H + +#include "simple.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Luby-Rackoff block cipher information +template +struct LR_Info : public VariableKeyLength<16, 0, 2*(INT_MAX/2), 2>, public FixedBlockSize<2*T::DIGESTSIZE> +{ + static std::string StaticAlgorithmName() {return std::string("LR/")+T::StaticAlgorithmName();} +}; + +/// \brief Luby-Rackoff block cipher +template +class LR : public LR_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl > + { + public: + // VC60 workaround: have to define these functions within class definition + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms) + { + this->AssertValidKeyLength(length); + + L = length/2; + buffer.New(2*S); + digest.New(S); + key.Assign(userKey, 2*L); + } + + protected: + CRYPTOPP_CONSTANT(S=T::DIGESTSIZE); + unsigned int L; // key length / 2 + SecByteBlock key; + + mutable T hm; + mutable SecByteBlock buffer, digest; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + +#define KL this->key +#define KR this->key+this->L +#define BL this->buffer +#define BR this->buffer+this->S +#define IL inBlock +#define IR inBlock+this->S +#define OL outBlock +#define OR outBlock+this->S + + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const + { + this->hm.Update(KL, this->L); + this->hm.Update(IL, this->S); + this->hm.Final(BR); + xorbuf(BR, IR, this->S); + + this->hm.Update(KR, this->L); + this->hm.Update(BR, this->S); + this->hm.Final(BL); + xorbuf(BL, IL, this->S); + + this->hm.Update(KL, this->L); + this->hm.Update(BL, this->S); + this->hm.Final(this->digest); + xorbuf(BR, this->digest, this->S); + + this->hm.Update(KR, this->L); + this->hm.Update(OR, this->S); + this->hm.Final(this->digest); + xorbuf(BL, this->digest, this->S); + + if (xorBlock) + xorbuf(outBlock, xorBlock, this->buffer, 2*this->S); + else + memcpy_s(outBlock, 2*this->S, this->buffer, 2*this->S); + } + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const + { + this->hm.Update(KR, this->L); + this->hm.Update(IR, this->S); + this->hm.Final(BL); + xorbuf(BL, IL, this->S); + + this->hm.Update(KL, this->L); + this->hm.Update(BL, this->S); + this->hm.Final(BR); + xorbuf(BR, IR, this->S); + + this->hm.Update(KR, this->L); + this->hm.Update(BR, this->S); + this->hm.Final(this->digest); + xorbuf(BL, this->digest, this->S); + + this->hm.Update(KL, this->L); + this->hm.Update(OL, this->S); + this->hm.Final(this->digest); + xorbuf(BR, this->digest, this->S); + + if (xorBlock) + xorbuf(outBlock, xorBlock, this->buffer, 2*this->S); + else + std::memcpy(outBlock, this->buffer, 2*this->S); + } +#undef KL +#undef KR +#undef BL +#undef BR +#undef IL +#undef IR +#undef OL +#undef OR + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/luc.h b/third_party/cryptoppwin/include/cryptopp/luc.h new file mode 100644 index 00000000..7c0c1b7c --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/luc.h @@ -0,0 +1,338 @@ +// luc.h - originally written and placed in the public domain by Wei Dai + +/// \file luc.h +/// \brief Classes for the LUC cryptosystem +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_LUC_H +#define CRYPTOPP_LUC_H + +#include "cryptlib.h" +#include "gfpcrypt.h" +#include "integer.h" +#include "algebra.h" +#include "secblock.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189) +#endif + +#include "pkcspad.h" +#include "integer.h" +#include "oaep.h" +#include "dh.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief The LUC function. +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +class LUCFunction : public TrapdoorFunction, public PublicKey +{ + typedef LUCFunction ThisClass; + +public: + virtual ~LUCFunction() {} + + /// \brief Initialize a LUC public key with {n,e} + /// \param n the modulus + /// \param e the public exponent + void Initialize(const Integer &n, const Integer &e) + {m_n = n; m_e = e;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // non-derived interface + const Integer & GetModulus() const {return m_n;} + const Integer & GetPublicExponent() const {return m_e;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetPublicExponent(const Integer &e) {m_e = e;} + +protected: + Integer m_n, m_e; +}; + +/// \brief The LUC inverse function. +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +class InvertibleLUCFunction : public LUCFunction, public TrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleLUCFunction ThisClass; + +public: + virtual ~InvertibleLUCFunction() {} + + /// \brief Create a LUC private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \param eStart the desired starting public exponent + /// \details Initialize() creates a new keypair using a starting public exponent of 17. + /// \details This function overload of Initialize() creates a new keypair because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits, const Integer &eStart=17); + + /// \brief Initialize a LUC private key with {n,e,p,q,dp,dq,u} + /// \param n modulus + /// \param e public exponent + /// \param p first prime factor + /// \param q second prime factor + /// \param u q-1 mod p + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &e, const Integer &p, const Integer &q, const Integer &u) + {m_n = n; m_e = e; m_p = p; m_q = q; m_u = u;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize, PublicExponent (default 17)) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + // non-derived interface + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + Integer m_p, m_q, m_u; +}; + +/// \brief LUC cryptosystem +/// \since Crypto++ 2.1 +struct LUC +{ + static std::string StaticAlgorithmName() {return "LUC";} + typedef LUCFunction PublicKey; + typedef InvertibleLUCFunction PrivateKey; +}; + +/// \brief LUC encryption scheme +/// \tparam STANDARD signature standard +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +template +struct LUCES : public TF_ES +{ +}; + +/// \brief LUC signature scheme with appendix +/// \tparam STANDARD signature standard +/// \tparam H hash transformation +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +template +struct LUCSS : public TF_SS +{ +}; + +// analogous to the RSA schemes defined in PKCS #1 v2.0 +typedef LUCES >::Decryptor LUCES_OAEP_SHA_Decryptor; +typedef LUCES >::Encryptor LUCES_OAEP_SHA_Encryptor; + +typedef LUCSS::Signer LUCSSA_PKCS1v15_SHA_Signer; +typedef LUCSS::Verifier LUCSSA_PKCS1v15_SHA_Verifier; + +// ******************************************************** + +/// \brief LUC GroupParameters precomputation +/// \details No actual precomputation is performed +/// \since Crypto++ 2.1 +class DL_GroupPrecomputation_LUC : public DL_GroupPrecomputation +{ +public: + virtual ~DL_GroupPrecomputation_LUC() {} + + const AbstractGroup & GetGroup() const {CRYPTOPP_ASSERT(false); throw 0;} + Element BERDecodeElement(BufferedTransformation &bt) const {return Integer(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {v.DEREncode(bt);} + + // non-inherited + void SetModulus(const Integer &v) {m_p = v;} + const Integer & GetModulus() const {return m_p;} + +private: + Integer m_p; +}; + +/// \brief LUC Precomputation +/// \since Crypto++ 2.1 +class DL_BasePrecomputation_LUC : public DL_FixedBasePrecomputation +{ +public: + virtual ~DL_BasePrecomputation_LUC() {} + + // DL_FixedBasePrecomputation + bool IsInitialized() const {return m_g.NotZero();} + void SetBase(const DL_GroupPrecomputation &group, const Integer &base) + {CRYPTOPP_UNUSED(group); m_g = base;} + const Integer & GetBase(const DL_GroupPrecomputation &group) const + {CRYPTOPP_UNUSED(group); return m_g;} + void Precompute(const DL_GroupPrecomputation &group, unsigned int maxExpBits, unsigned int storage) + {CRYPTOPP_UNUSED(group); CRYPTOPP_UNUSED(maxExpBits); CRYPTOPP_UNUSED(storage);} + void Load(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) + {CRYPTOPP_UNUSED(group); CRYPTOPP_UNUSED(storedPrecomputation);} + void Save(const DL_GroupPrecomputation &group, BufferedTransformation &storedPrecomputation) const + {CRYPTOPP_UNUSED(group); CRYPTOPP_UNUSED(storedPrecomputation);} + Integer Exponentiate(const DL_GroupPrecomputation &group, const Integer &exponent) const; + Integer CascadeExponentiate(const DL_GroupPrecomputation &group, const Integer &exponent, const DL_FixedBasePrecomputation &pc2, const Integer &exponent2) const + { + CRYPTOPP_UNUSED(group); CRYPTOPP_UNUSED(exponent); CRYPTOPP_UNUSED(pc2); CRYPTOPP_UNUSED(exponent2); + // shouldn't be called + throw NotImplemented("DL_BasePrecomputation_LUC: CascadeExponentiate not implemented"); + } + +private: + Integer m_g; +}; + +/// \brief LUC GroupParameters specialization +/// \since Crypto++ 2.1 +class DL_GroupParameters_LUC : public DL_GroupParameters_IntegerBasedImpl +{ +public: + virtual ~DL_GroupParameters_LUC() {} + + // DL_GroupParameters + bool IsIdentity(const Integer &element) const {return element == Integer::Two();} + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + Element MultiplyElements(const Element &a, const Element &b) const + { + CRYPTOPP_UNUSED(a); CRYPTOPP_UNUSED(b); + throw NotImplemented("LUC_GroupParameters: MultiplyElements can not be implemented"); + } + Element CascadeExponentiate(const Element &element1, const Integer &exponent1, const Element &element2, const Integer &exponent2) const + { + CRYPTOPP_UNUSED(element1); CRYPTOPP_UNUSED(exponent1); CRYPTOPP_UNUSED(element2); CRYPTOPP_UNUSED(exponent2); + throw NotImplemented("LUC_GroupParameters: MultiplyElements can not be implemented"); + } + + // NameValuePairs interface + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue).Assignable(); + } + +private: + int GetFieldType() const {return 2;} +}; + +/// \brief GF(p) group parameters that default to safe primes +/// \since Crypto++ 2.1 +class DL_GroupParameters_LUC_DefaultSafePrime : public DL_GroupParameters_LUC +{ +public: + typedef NoCofactorMultiplication DefaultCofactorOption; + +protected: + unsigned int GetDefaultSubgroupOrderSize(unsigned int modulusSize) const {return modulusSize-1;} +}; + +/// \brief LUC HMP signature algorithm +/// \since Crypto++ 2.1 +class DL_Algorithm_LUC_HMP : public DL_ElgamalLikeSignatureAlgorithm +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "LUC-HMP";} + + virtual ~DL_Algorithm_LUC_HMP() {} + + void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const; + bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const; + + size_t RLen(const DL_GroupParameters ¶ms) const + {return params.GetGroupOrder().ByteCount();} +}; + +/// \brief LUC signature keys +/// \since Crypto++ 2.1 +struct DL_SignatureKeys_LUC +{ + typedef DL_GroupParameters_LUC GroupParameters; + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_GFP PrivateKey; +}; + +/// \brief LUC-HMP, based on "Digital signature schemes based on Lucas functions" by Patrick Horster, Markus Michels, Holger Petersen +/// \tparam H hash transformation +/// \details This class is here for historical and pedagogical interest. It has no practical advantages over other +/// trapdoor functions and probably shouldn't be used in production software. The discrete log based LUC schemes +/// defined later in this .h file may be of more practical interest. +/// \since Crypto++ 2.1 +template +struct LUC_HMP : public DL_SS +{ +}; + +/// \brief LUC encryption keys +/// \since Crypto++ 2.1 +struct DL_CryptoKeys_LUC +{ + typedef DL_GroupParameters_LUC_DefaultSafePrime GroupParameters; + typedef DL_PublicKey_GFP PublicKey; + typedef DL_PrivateKey_GFP PrivateKey; +}; + +/// \brief LUC Integrated Encryption Scheme +/// \tparam COFACTOR_OPTION cofactor multiplication option +/// \tparam HASH HashTransformation derived class used for key drivation and MAC computation +/// \tparam DHAES_MODE flag indicating if the MAC includes additional context parameters such as u·V, v·U and label +/// \tparam LABEL_OCTETS flag indicating if the label size is specified in octets or bits +/// \sa CofactorMultiplicationOption +/// \since Crypto++ 2.1, Crypto++ 5.7 for Bouncy Castle and Botan compatibility +template +struct LUC_IES + : public DL_ES< + DL_CryptoKeys_LUC, + DL_KeyAgreementAlgorithm_DH, + DL_KeyDerivationAlgorithm_P1363 >, + DL_EncryptionAlgorithm_Xor, DHAES_MODE, LABEL_OCTETS>, + LUC_IES<> > +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "LUC-IES";} // non-standard name +}; + +// ******************************************************** + +/// \brief LUC-DH +typedef DH_Domain LUC_DH; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/mars.h b/third_party/cryptoppwin/include/cryptopp/mars.h new file mode 100644 index 00000000..53c093c9 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/mars.h @@ -0,0 +1,60 @@ +// mars.h - originally written and placed in the public domain by Wei Dai + +/// \file mars.h +/// \brief Classes for the MARS block cipher (IBM AES submission) +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_MARS_H +#define CRYPTOPP_MARS_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief MARS block cipher information +/// \since Crypto++ 3.0 +struct MARS_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 56, 8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MARS";} +}; + +/// \brief MARS block cipher +/// \sa MARS +/// \since Crypto++ 3.0 +class MARS : public MARS_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + static const word32 Sbox[512]; + + FixedSizeSecBlock m_k; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef MARS::Encryption MARSEncryption; +typedef MARS::Decryption MARSDecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/md2.h b/third_party/cryptoppwin/include/cryptopp/md2.h new file mode 100644 index 00000000..83335d30 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/md2.h @@ -0,0 +1,56 @@ +// md2.h - originally written and placed in the public domain by Wei Dai + +/// \file md2.h +/// \brief Classes for the MD2 message digest +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_MD2_H +#define CRYPTOPP_MD2_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +namespace Weak1 { + +/// \brief MD2 message digest +/// \sa MD2 +/// \since Crypto++ 3.0 +class MD2 : public HashTransformation +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MD2";} + + MD2(); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *hash, size_t size); + unsigned int DigestSize() const {return DIGESTSIZE;} + unsigned int BlockSize() const {return BLOCKSIZE;} + std::string AlgorithmName() const {return StaticAlgorithmName();} + + CRYPTOPP_CONSTANT(DIGESTSIZE = 16); + CRYPTOPP_CONSTANT(BLOCKSIZE = 16); + +private: + void Transform(); + void Init(); + SecByteBlock m_X, m_C, m_buf; + unsigned int m_count; +}; + +} +#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1 +namespace Weak {using namespace Weak1;} // import Weak1 into CryptoPP::Weak +#else +using namespace Weak1; // import Weak1 into CryptoPP with warning +#ifdef __GNUC__ +#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning." +#else +#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.") +#endif +#endif + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/md4.h b/third_party/cryptoppwin/include/cryptopp/md4.h new file mode 100644 index 00000000..8984b5e0 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/md4.h @@ -0,0 +1,35 @@ +#ifndef CRYPTOPP_MD4_H +#define CRYPTOPP_MD4_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +namespace Weak1 { + +/// MD4 +/*! \warning MD4 is considered insecure, and should not be used + unless you absolutely need it for compatibility. */ +class MD4 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MD4";} +}; + +} +#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1 +namespace Weak {using namespace Weak1;} // import Weak1 into CryptoPP::Weak +#else +using namespace Weak1; // import Weak1 into CryptoPP with warning +#ifdef __GNUC__ +#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning." +#else +#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.") +#endif +#endif + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/md5.h b/third_party/cryptoppwin/include/cryptopp/md5.h new file mode 100644 index 00000000..2b3e2c3b --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/md5.h @@ -0,0 +1,35 @@ +#ifndef CRYPTOPP_MD5_H +#define CRYPTOPP_MD5_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +namespace Weak1 { + +/// \brief MD5 message digest +/// \sa MD5 +/// \since Crypto++ 1.0 +class MD5 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "MD5";} +}; + +} +#if CRYPTOPP_ENABLE_NAMESPACE_WEAK >= 1 +namespace Weak {using namespace Weak1;} // import Weak1 into CryptoPP::Weak +#else +using namespace Weak1; // import Weak1 into CryptoPP with warning +#ifdef __GNUC__ +#warning "You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning." +#else +#pragma message("You may be using a weak algorithm that has been retained for backwards compatibility. Please '#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1' before including this .h file and prepend the class name with 'Weak::' to remove this warning.") +#endif +#endif + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/mdc.h b/third_party/cryptoppwin/include/cryptopp/mdc.h new file mode 100644 index 00000000..68d5ab8c --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/mdc.h @@ -0,0 +1,84 @@ +// mdc.h - originally written and placed in the public domain by Wei Dai + +/// \file mdc.h +/// \brief Classes for the MDC message digest + +#ifndef CRYPTOPP_MDC_H +#define CRYPTOPP_MDC_H + +#include "seckey.h" +#include "secblock.h" +#include "misc.h" + +// GCC cast warning +#define HashWordPtr(x) ((HashWordType*)(void*)(x)) +#define ConstHashWordPtr(x) ((const HashWordType*)(const void*)(x)) + +NAMESPACE_BEGIN(CryptoPP) + +/// \tparam B BlockCipher derived class +/// \brief MDC_Info cipher information +template +struct MDC_Info : public FixedBlockSize, public FixedKeyLength +{ + static std::string StaticAlgorithmName() {return std::string("MDC/")+B::StaticAlgorithmName();} +}; + +/// \brief MDC cipher +/// \tparam H HashTransformation derived class +/// \details MDC() is a construction by Peter Gutmann to turn an iterated hash function into a PRF +/// \sa MDC +template +class MDC : public MDC_Info +{ + /// \brief MDC cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public BlockCipherImpl > + { + typedef typename H::HashWordType HashWordType; + + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms) + { + CRYPTOPP_UNUSED(params); + this->AssertValidKeyLength(length); + ConditionalByteReverse(BIG_ENDIAN_ORDER, Key(), ConstHashWordPtr(userKey), this->KEYLENGTH); + } + + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const + { + ConditionalByteReverse(BIG_ENDIAN_ORDER, Buffer(), ConstHashWordPtr(inBlock), this->BLOCKSIZE); + H::Transform(Buffer(), Key()); + + if (xorBlock) + { + ConditionalByteReverse(BIG_ENDIAN_ORDER, Buffer(), Buffer(), this->BLOCKSIZE); + xorbuf(outBlock, xorBlock, m_buffer, this->BLOCKSIZE); + } + else + { + ConditionalByteReverse(BIG_ENDIAN_ORDER, HashWordPtr(outBlock), Buffer(), this->BLOCKSIZE); + } + } + + bool IsPermutation() const {return false;} + + unsigned int OptimalDataAlignment() const {return sizeof(HashWordType);} + + private: + HashWordType *Key() {return HashWordPtr(m_key.data());} + const HashWordType *Key() const {return ConstHashWordPtr(m_key.data());} + HashWordType *Buffer() const {return HashWordPtr(m_buffer.data());} + + // VC60 workaround: bug triggered if using FixedSizeAllocatorWithCleanup + FixedSizeSecBlock::KEYLENGTH, AllocatorWithCleanup > m_key; + mutable FixedSizeSecBlock::BLOCKSIZE, AllocatorWithCleanup > m_buffer; + }; + +public: + // use BlockCipher interface + typedef BlockCipherFinal Encryption; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/mersenne.h b/third_party/cryptoppwin/include/cryptopp/mersenne.h new file mode 100644 index 00000000..326d9116 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/mersenne.h @@ -0,0 +1,231 @@ +// mersenne.h - written and placed in public domain by Jeffrey Walton. + +/// \file mersenne.h +/// \brief Class file for Mersenne Twister +/// \warning MersenneTwister is suitable for Monte-Carlo simulations, where uniformaly distributed +/// numbers are required quickly. It should not be used for cryptographic purposes. +/// \since Crypto++ 5.6.3 +#ifndef CRYPTOPP_MERSENNE_TWISTER_H +#define CRYPTOPP_MERSENNE_TWISTER_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Mersenne Twister class for Monte-Carlo simulations +/// \tparam K Magic constant +/// \tparam M Period parameter +/// \tparam N Size of the state vector +/// \tparam F Multiplier constant +/// \tparam S Initial seed +/// \details Provides the MersenneTwister implementation. The class is a header-only implementation. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \warning MersenneTwister is suitable for simulations, where uniformaly distributed numbers are +/// required quickly. It should not be used for cryptographic purposes. +/// \sa MT19937, MT19937ar +/// \since Crypto++ 5.6.3 +template +class MersenneTwister : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return (S==5489 ? "MT19937ar" : (S==4537 ? "MT19937" : "MT19937x")); } + + ~MersenneTwister() {} + + /// \brief Construct a Mersenne Twister + /// \param seed 32-bit seed + /// \details Defaults to template parameter S due to changing algorithm + /// parameters over time + MersenneTwister(word32 seed = S) : m_idx(N) + { + Reset(seed); + } + + bool CanIncorporateEntropy() const {return true;} + + /// \brief Update RNG state with additional unpredictable values + /// \param input the entropy to add to the generator + /// \param length the size of the input buffer + /// \details MersenneTwister uses the first 32-bits of input to reseed the + /// generator. If fewer bytes are provided, then the seed is padded with 0's. + void IncorporateEntropy(const byte *input, size_t length) + { + // Handle word32 size blocks + FixedSizeSecBlock temp; + temp[0] = 0; + + if (length > 4) + length = 4; + + for (size_t i=0; i temp; + for (size_t i=0; i < size/4; i++, output += 4) + { + temp[0] = NextMersenneWord(); + std::memcpy(output, temp+0, 4); + } + + // No tail bytes + if (size%4 == 0) + return; + + // Handle tail bytes + temp[0] = NextMersenneWord(); + switch (size%4) + { + case 3: output[2] = CRYPTOPP_GET_BYTE_AS_BYTE(temp[0], 1); /* fall through */ + case 2: output[1] = CRYPTOPP_GET_BYTE_AS_BYTE(temp[0], 2); /* fall through */ + case 1: output[0] = CRYPTOPP_GET_BYTE_AS_BYTE(temp[0], 3); break; + + default: CRYPTOPP_ASSERT(0);; + } + } + + /// \brief Generate a random 32-bit word in the range min to max, inclusive + /// \return random 32-bit word in the range min to max, inclusive + /// \details If the 32-bit candidate is not within the range, then it is discarded + /// and a new candidate is used. + word32 GenerateWord32(word32 min=0, word32 max=0xffffffffL) + { + const word32 range = max-min; + if (range == 0xffffffffL) + return NextMersenneWord(); + + const int maxBits = BitPrecision(range); + word32 value; + + do{ + value = Crop(NextMersenneWord(), maxBits); + } while (value > range); + + return value+min; + } + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to discard, rounded up to a word32 size + /// \details If n is not a multiple of word32, then unused bytes are + /// not accumulated for subsequent calls to GenerateBlock. Rather, the unused + /// tail bytes are discarded, and the stream is continued at the next + /// word32 boundary from the state array. + void DiscardBytes(size_t n) + { + for(size_t i=0; i < RoundUpToMultipleOf(n, 4U); i++) + NextMersenneWord(); + } + +protected: + + void Reset(word32 seed) + { + m_idx = N; + + m_state[0] = seed; + for (unsigned int i = 1; i < N+1; i++) + m_state[i] = word32(F * (m_state[i-1] ^ (m_state[i-1] >> 30)) + i); + } + + /// \brief Returns the next 32-bit word from the state array + /// \return the next 32-bit word from the state array + /// \details fetches the next word frm the state array, performs bit operations on + /// it, and then returns the value to the caller. + word32 NextMersenneWord() + { + if (m_idx >= N) { Twist(); } + + word32 temp = m_state[m_idx++]; + + temp ^= (temp >> 11); + temp ^= (temp << 7) & 0x9D2C5680; // 0x9D2C5680 (2636928640) + temp ^= (temp << 15) & 0xEFC60000; // 0xEFC60000 (4022730752) + + return temp ^ (temp >> 18); + } + + /// \brief Performs the twist operation on the state array + void Twist() + { + static const word32 magic[2]={0x0UL, K}; + word32 kk, temp; + + CRYPTOPP_ASSERT(N >= M); + for (kk=0;kk> 1) ^ magic[temp & 0x1UL]; + } + + for (;kk> 1) ^ magic[temp & 0x1UL]; + } + + temp = (m_state[N-1] & 0x80000000)|(m_state[0] & 0x7FFFFFFF); + m_state[N-1] = m_state[M-1] ^ (temp >> 1) ^ magic[temp & 0x1UL]; + + // Reset index + m_idx = 0; + + // Wipe temp + SecureWipeArray(&temp, 1); + } + +private: + + /// \brief 32-bit word state array of size N + FixedSizeSecBlock m_state; + /// \brief the current index into the state array + word32 m_idx; +}; + +/// \brief Original MT19937 generator provided in the ACM paper. +/// \details MT19937 uses 4537 as default initial seed. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa MT19937ar, Mersenne twister: +/// a 623-dimensionally equidistributed uniform pseudo-random number generator +/// \since Crypto++ 5.6.3 +#if CRYPTOPP_DOXYGEN_PROCESSING +class MT19937 : public MersenneTwister<0x9908B0DF /*2567483615*/, 397, 624, 0x10DCD /*69069*/, 4537> {}; +#else +typedef MersenneTwister<0x9908B0DF /*2567483615*/, 397, 624, 0x10DCD /*69069*/, 4537> MT19937; +#endif + +/// \brief Updated MT19937 generator adapted to provide an array for initialization. +/// \details MT19937 uses 5489 as default initial seed. Use this generator when interoperating with C++11's +/// mt19937 class. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa MT19937, Mersenne Twister +/// with improved initialization +/// \since Crypto++ 5.6.3 +#if CRYPTOPP_DOXYGEN_PROCESSING +class MT19937ar : public MersenneTwister<0x9908B0DF /*2567483615*/, 397, 624, 0x6C078965 /*1812433253*/, 5489> {}; +#else +typedef MersenneTwister<0x9908B0DF /*2567483615*/, 397, 624, 0x6C078965 /*1812433253*/, 5489> MT19937ar; +#endif + +NAMESPACE_END + +#endif // CRYPTOPP_MERSENNE_TWISTER_H diff --git a/third_party/cryptoppwin/include/cryptopp/misc.h b/third_party/cryptoppwin/include/cryptopp/misc.h new file mode 100644 index 00000000..2e2bd5a5 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/misc.h @@ -0,0 +1,3222 @@ +// misc.h - originally written and placed in the public domain by Wei Dai + +/// \file misc.h +/// \brief Utility functions for the Crypto++ library. + +#ifndef CRYPTOPP_MISC_H +#define CRYPTOPP_MISC_H + +#include "config.h" + +#include "cryptlib.h" +#include "secblockfwd.h" +#include "smartptr.h" +#include "stdcpp.h" +#include "trap.h" + +#if !defined(CRYPTOPP_DOXYGEN_PROCESSING) + +#if (CRYPTOPP_MSC_VERSION) +# pragma warning(push) +# pragma warning(disable: 4146 4514) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6326) +# endif +#endif + +// Issue 340 and Issue 793 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifdef CRYPTOPP_MSC_VERSION + #if CRYPTOPP_MSC_VERSION >= 1400 + // VC2005 workaround: disable declarations that conflict with winnt.h + #define _interlockedbittestandset CRYPTOPP_DISABLED_INTRINSIC_1 + #define _interlockedbittestandreset CRYPTOPP_DISABLED_INTRINSIC_2 + #define _interlockedbittestandset64 CRYPTOPP_DISABLED_INTRINSIC_3 + #define _interlockedbittestandreset64 CRYPTOPP_DISABLED_INTRINSIC_4 + #include + #undef _interlockedbittestandset + #undef _interlockedbittestandreset + #undef _interlockedbittestandset64 + #undef _interlockedbittestandreset64 + #define CRYPTOPP_FAST_ROTATE(x) 1 + #elif CRYPTOPP_MSC_VERSION >= 1300 + #define CRYPTOPP_FAST_ROTATE(x) ((x) == 32 | (x) == 64) + #else + #define CRYPTOPP_FAST_ROTATE(x) ((x) == 32) + #endif +#elif (defined(__MWERKS__) && TARGET_CPU_PPC) || \ + (defined(__GNUC__) && (defined(_ARCH_PWR2) || defined(_ARCH_PWR) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || defined(_ARCH_COM))) + #define CRYPTOPP_FAST_ROTATE(x) ((x) == 32) +#elif defined(__GNUC__) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86) // depend on GCC's peephole optimization to generate rotate instructions + #define CRYPTOPP_FAST_ROTATE(x) 1 +#else + #define CRYPTOPP_FAST_ROTATE(x) 0 +#endif + +#ifdef __BORLANDC__ +#include +#include +#endif + +#if (defined(__GNUC__) || defined(__clang__)) && defined(__linux__) +#define CRYPTOPP_BYTESWAP_AVAILABLE 1 +#include +#endif + +// Limit to ARM A-32. Aarch64 is failing self tests. +#if defined(__arm__) && (defined(__GNUC__) || defined(__clang__)) && (__ARM_ARCH >= 6) +#define CRYPTOPP_ARM_BYTEREV_AVAILABLE 1 +#endif + +// Limit to ARM A-32. Aarch64 is failing self tests. +#if defined(__arm__) && (defined(__GNUC__) || defined(__clang__)) && (__ARM_ARCH >= 7) +#define CRYPTOPP_ARM_BITREV_AVAILABLE 1 +#endif + +#if defined(__BMI__) +# if defined(CRYPTOPP_GCC_COMPATIBLE) +# include +# endif +# include +#endif // BMI + +// More LLVM bullshit. Apple Clang 6.0 does not define them. +// Later version of Clang defines them and results in warnings. +#if defined(__clang__) +# ifndef _blsr_u32 +# define _blsr_u32 __blsr_u32 +# endif +# ifndef _blsr_u64 +# define _blsr_u64 __blsr_u64 +# endif +# ifndef _tzcnt_u32 +# define _tzcnt_u32 __tzcnt_u32 +# endif +# ifndef _tzcnt_u64 +# define _tzcnt_u64 __tzcnt_u64 +# endif +#endif + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief The maximum value of a machine word +/// \details SIZE_MAX provides the maximum value of a machine word. The value +/// is 0xffffffff on 32-bit targets, and 0xffffffffffffffff on 64-bit +/// targets. +/// \details If SIZE_MAX is not defined, then __SIZE_MAX__ is used if +/// defined. If not defined, then SIZE_T_MAX is used if defined. If not defined, +/// then the library uses std::numeric_limits::max(). +/// \details The library prefers __SIZE_MAX__ or __SIZE_T_MAX__ because +/// they are effectively constexpr that is optimized well by all compilers. +/// std::numeric_limits::max() is not always a constexpr, and +/// it is not always optimized well. +# define SIZE_MAX ... +#else +// Its amazing portability problems still plague this simple concept in 2015. +// http://stackoverflow.com/questions/30472731/which-c-standard-header-defines-size-max +// Avoid NOMINMAX macro on Windows. http://support.microsoft.com/en-us/kb/143208 +#ifndef SIZE_MAX +# if defined(__SIZE_MAX__) +# define SIZE_MAX __SIZE_MAX__ +# elif defined(SIZE_T_MAX) +# define SIZE_MAX SIZE_T_MAX +# elif defined(__SIZE_TYPE__) +# define SIZE_MAX (~(__SIZE_TYPE__)0) +# else +# define SIZE_MAX ((std::numeric_limits::max)()) +# endif +#endif + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_BEGIN(CryptoPP) + +// Forward declaration for IntToString specialization +class Integer; + +// ************** compile-time assertion *************** + +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Compile time assertion +/// \param expr the expression to evaluate +/// \details Asserts the expression expr during compile. If C++14 and +/// N3928 are available, then C++14 static_assert is used. Otherwise, +/// a CompileAssert structure is used. When the structure is used +/// a negative-sized array triggers the assert at compile time. +# define CRYPTOPP_COMPILE_ASSERT(expr) { ... } +#elif defined(CRYPTOPP_CXX17_STATIC_ASSERT) +# define CRYPTOPP_COMPILE_ASSERT(expr) static_assert(expr) +#else // CRYPTOPP_DOXYGEN_PROCESSING +template +struct CompileAssert +{ + static char dummy[2*b-1]; +}; + +#define CRYPTOPP_COMPILE_ASSERT(assertion) CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, __LINE__) +#define CRYPTOPP_ASSERT_JOIN(X, Y) CRYPTOPP_DO_ASSERT_JOIN(X, Y) +#define CRYPTOPP_DO_ASSERT_JOIN(X, Y) X##Y + +#if defined(CRYPTOPP_EXPORTS) || defined(CRYPTOPP_IMPORTS) +# define CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, instance) +#else +# if defined(__GNUC__) || defined(__clang__) +# define CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, instance) \ + static CompileAssert<(assertion)> \ + CRYPTOPP_ASSERT_JOIN(cryptopp_CRYPTOPP_ASSERT_, instance) __attribute__ ((unused)) +# else +# define CRYPTOPP_COMPILE_ASSERT_INSTANCE(assertion, instance) \ + static CompileAssert<(assertion)> \ + CRYPTOPP_ASSERT_JOIN(cryptopp_CRYPTOPP_ASSERT_, instance) +# endif // GCC or Clang +#endif + +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +// ************** count elements in an array *************** + +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief Counts elements in an array +/// \param arr an array of elements +/// \details COUNTOF counts elements in an array. On Windows COUNTOF(x) is defined +/// to _countof(x) to ensure correct results for pointers. +/// \note COUNTOF does not produce correct results with pointers, and an array must be used. +/// sizeof(x)/sizeof(x[0]) suffers the same problem. The risk is eliminated by using +/// _countof(x) on Windows. Windows will provide the immunity for other platforms. +# define COUNTOF(arr) +#else +// VS2005 added _countof +#ifndef COUNTOF +# if defined(CRYPTOPP_MSC_VERSION) && (CRYPTOPP_MSC_VERSION >= 1400) +# define COUNTOF(x) _countof(x) +# else +# define COUNTOF(x) (sizeof(x)/sizeof(x[0])) +# endif +#endif // COUNTOF +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +// ************** misc classes *************** + +/// \brief An Empty class +/// \details The Empty class can be used as a template parameter BASE when no base class exists. +class CRYPTOPP_DLL Empty +{ +}; + +#if !defined(CRYPTOPP_DOXYGEN_PROCESSING) +template +class CRYPTOPP_NO_VTABLE TwoBases : public BASE1, public BASE2 +{ +}; + +template +class CRYPTOPP_NO_VTABLE ThreeBases : public BASE1, public BASE2, public BASE3 +{ +}; +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \tparam T class or type +/// \brief Uses encapsulation to hide an object in derived classes +/// \details The object T is declared as protected. +template +class ObjectHolder +{ +protected: + T m_object; +}; + +/// \brief Ensures an object is not copyable +/// \details NotCopyable ensures an object is not copyable by making the +/// copy constructor and assignment operator private. Deleters are used +/// under C++11. +/// \sa Clonable class +class NotCopyable +{ +public: + NotCopyable() {} +#if CRYPTOPP_CXX11_DELETED_FUNCTIONS + NotCopyable(const NotCopyable &) = delete; + void operator=(const NotCopyable &) = delete; +#else +private: + NotCopyable(const NotCopyable &); + void operator=(const NotCopyable &); +#endif +}; + +/// \brief An object factory function +/// \tparam T class or type +/// \details NewObject overloads operator()(). +template +struct NewObject +{ + T* operator()() const {return new T;} +}; + +#if CRYPTOPP_DOXYGEN_PROCESSING +/// \brief A memory barrier +/// \details MEMORY_BARRIER attempts to ensure reads and writes are completed +/// in the absence of a language synchronization point. It is used by the +/// Singleton class if the compiler supports it. The barrier is provided at the +/// customary places in a double-checked initialization. +/// \details Internally, MEMORY_BARRIER uses std::atomic_thread_fence if +/// C++11 atomics are available. Otherwise, intrinsic(_ReadWriteBarrier), +/// _ReadWriteBarrier() or __asm__("" ::: "memory") is used. +#define MEMORY_BARRIER ... +#else +#if defined(CRYPTOPP_CXX11_ATOMIC) +# define MEMORY_BARRIER() std::atomic_thread_fence(std::memory_order_acq_rel) +#elif (CRYPTOPP_MSC_VERSION >= 1400) +# pragma intrinsic(_ReadWriteBarrier) +# define MEMORY_BARRIER() _ReadWriteBarrier() +#elif defined(__INTEL_COMPILER) +# define MEMORY_BARRIER() __memory_barrier() +#elif defined(__GNUC__) || defined(__clang__) +# define MEMORY_BARRIER() __asm__ __volatile__ ("" ::: "memory") +#else +# define MEMORY_BARRIER() +#endif +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +/// \brief Restricts the instantiation of a class to one static object without locks +/// \tparam T the class or type +/// \tparam F the object factory for T +/// \tparam instance an instance counter for the class object +/// \details This class safely initializes a static object in a multi-threaded environment. For C++03 +/// and below it will do so without using locks for portability. If two threads call Ref() at the same +/// time, they may get back different references, and one object may end up being memory leaked. This +/// is by design and it avoids a subtle initialization problem in a multi-threaded environment with thread +/// local storage on early Windows platforms, like Windows XP and Windows 2003. +/// \details For C++11 and above, a standard double-checked locking pattern with thread fences +/// are used. The locks and fences are standard and do not hinder portability. +/// \details Microsoft's C++11 implementation provides the necessary primitive support on Windows Vista and +/// above when using Visual Studio 2015 (cl.exe version 19.00). If C++11 is desired, you should +/// set WINVER or _WIN32_WINNT to 0x600 (or above), and compile with Visual Studio 2015. +/// \sa Double-Checked Locking +/// is Fixed In C++11, Dynamic +/// Initialization and Destruction with Concurrency and +/// Thread Local Storage (TLS) on MSDN. +/// \since Crypto++ 5.2 +template , int instance=0> +class Singleton +{ +public: + Singleton(F objectFactory = F()) : m_objectFactory(objectFactory) {} + + // prevent this function from being inlined + CRYPTOPP_NOINLINE const T & Ref(CRYPTOPP_NOINLINE_DOTDOTDOT) const; + +private: + F m_objectFactory; +}; + +/// \brief Return a reference to the inner Singleton object +/// \tparam T the class or type +/// \tparam F the object factory for T +/// \tparam instance an instance counter for the class object +/// \details Ref() is used to create the object using the object factory. The +/// object is only created once with the limitations discussed in the class documentation. +/// \sa Double-Checked Locking is Fixed In C++11 +/// \since Crypto++ 5.2 +template + const T & Singleton::Ref(CRYPTOPP_NOINLINE_DOTDOTDOT) const +{ +#if defined(CRYPTOPP_CXX11_ATOMIC) && defined(CRYPTOPP_CXX11_SYNCHRONIZATION) && defined(CRYPTOPP_CXX11_STATIC_INIT) + static std::mutex s_mutex; + static std::atomic s_pObject; + + T *p = s_pObject.load(std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_acquire); + + if (p) + return *p; + + std::lock_guard lock(s_mutex); + p = s_pObject.load(std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_acquire); + + if (p) + return *p; + + T *newObject = m_objectFactory(); + std::atomic_thread_fence(std::memory_order_release); + s_pObject.store(newObject, std::memory_order_relaxed); + + return *newObject; +#else + static volatile simple_ptr s_pObject; + T *p = s_pObject.m_p; + MEMORY_BARRIER(); + + if (p) + return *p; + + T *newObject = m_objectFactory(); + p = s_pObject.m_p; + MEMORY_BARRIER(); + + if (p) + { + delete newObject; + return *p; + } + + s_pObject.m_p = newObject; + MEMORY_BARRIER(); + + return *newObject; +#endif +} + +// ************** misc functions *************** + +/// \brief Create a pointer with an offset +/// \tparam PTR a pointer type +/// \tparam OFF a size type +/// \param pointer a pointer +/// \param offset a offset into the pointer +/// \details PtrAdd can be used to squash Clang and GCC +/// UBsan findings for pointer addition and subtraction. +template +inline PTR PtrAdd(PTR pointer, OFF offset) +{ + return pointer+static_cast(offset); +} + +/// \brief Create a pointer with an offset +/// \tparam PTR a pointer type +/// \tparam OFF a size type +/// \param pointer a pointer +/// \param offset a offset into the pointer +/// \details PtrSub can be used to squash Clang and GCC +/// UBsan findings for pointer addition and subtraction. +template +inline PTR PtrSub(PTR pointer, OFF offset) +{ + return pointer-static_cast(offset); +} + +/// \brief Determine pointer difference +/// \tparam PTR a pointer type +/// \param pointer1 the first pointer +/// \param pointer2 the second pointer +/// \details PtrDiff can be used to squash Clang and GCC +/// UBsan findings for pointer addition and subtraction. +/// pointer1 and pointer2 must point to the same object or +/// array (or one past the end), and yields the number of +/// elements (not bytes) difference. +template +inline ptrdiff_t PtrDiff(const PTR pointer1, const PTR pointer2) +{ + return pointer1 - pointer2; +} + +/// \brief Determine pointer difference +/// \tparam PTR a pointer type +/// \param pointer1 the first pointer +/// \param pointer2 the second pointer +/// \details PtrByteDiff can be used to squash Clang and GCC +/// UBsan findings for pointer addition and subtraction. +/// pointer1 and pointer2 must point to the same object or +/// array (or one past the end), and yields the number of +/// bytes (not elements) difference. +template +inline size_t PtrByteDiff(const PTR pointer1, const PTR pointer2) +{ + return (size_t)(reinterpret_cast(pointer1) - reinterpret_cast(pointer2)); +} + +/// \brief Pointer to the first element of a string +/// \param str string +/// \details BytePtr returns NULL pointer for an empty string. +/// \return Pointer to the first element of a string +/// \since Crypto++ 8.0 +inline byte* BytePtr(std::string& str) +{ + // Caller wants a writable pointer + CRYPTOPP_ASSERT(str.empty() == false); + + if (str.empty()) + return NULLPTR; + return reinterpret_cast(&str[0]); +} + +/// \brief Pointer to the first element of a string +/// \param str SecByteBlock +/// \details BytePtr returns NULL pointer for an empty string. +/// \return Pointer to the first element of a string +/// \since Crypto++ 8.3 +byte* BytePtr(SecByteBlock& str); + +/// \brief Const pointer to the first element of a string +/// \param str string +/// \details ConstBytePtr returns non-NULL pointer for an empty string. +/// \return Pointer to the first element of a string +/// \since Crypto++ 8.0 +inline const byte* ConstBytePtr(const std::string& str) +{ + if (str.empty()) + return NULLPTR; + return reinterpret_cast(&str[0]); +} + +/// \brief Const pointer to the first element of a string +/// \param str SecByteBlock +/// \details ConstBytePtr returns non-NULL pointer for an empty string. +/// \return Pointer to the first element of a string +/// \since Crypto++ 8.3 +const byte* ConstBytePtr(const SecByteBlock& str); + +/// \brief Size of a string +/// \param str string +/// \return size of a string +/// \since Crypto++ 8.3 +inline size_t BytePtrSize(const std::string& str) +{ + return str.size(); +} + +/// \brief Size of a string +/// \param str SecByteBlock +/// \return size of a string +/// \since Crypto++ 8.3 +size_t BytePtrSize(const SecByteBlock& str); + +/// \brief Integer value +/// \details EnumToInt avoids C++20 enum-enum conversion +/// warnings under GCC and Clang. C++11 and above use a +/// constexpr function. C++03 and below use a macro due +/// to [lack of] constexpr-ness in early versions of C++. +/// \since Crypto++ 8.6 +#if (CRYPTOPP_CXX11_CONSTEXPR) +template +constexpr int EnumToInt(T v) { + return static_cast(v); +} +#else +# define EnumToInt(v) static_cast(v) +#endif + +#if (!__STDC_WANT_SECURE_LIB__ && !defined(_MEMORY_S_DEFINED)) || defined(CRYPTOPP_WANT_SECURE_LIB) + +/// \brief Bounds checking replacement for memcpy() +/// \param dest pointer to the destination memory block +/// \param sizeInBytes size of the destination memory block, in bytes +/// \param src pointer to the source memory block +/// \param count the number of bytes to copy +/// \throw InvalidArgument +/// \details ISO/IEC TR-24772 provides bounds checking interfaces for potentially +/// unsafe functions like memcpy(), strcpy() and memmove(). However, +/// not all standard libraries provides them, like Glibc. The library's +/// memcpy_s() is a near-drop in replacement. Its only a near-replacement +/// because the library's version throws an InvalidArgument on a bounds violation. +/// \details memcpy_s() and memmove_s() are guarded by __STDC_WANT_SECURE_LIB__. +/// If __STDC_WANT_SECURE_LIB__ is not defined or defined to 0, then the library +/// makes memcpy_s() and memmove_s() available. The library will also optionally +/// make the symbols available if CRYPTOPP_WANT_SECURE_LIB is defined. +/// CRYPTOPP_WANT_SECURE_LIB is in config.h, but it is disabled by default. +/// \details memcpy_s() will assert the pointers src and dest are not NULL +/// in debug builds. Passing NULL for either pointer is undefined behavior. +inline void memcpy_s(void *dest, size_t sizeInBytes, const void *src, size_t count) +{ + // Safer functions on Windows for C&A, http://github.com/weidai11/cryptopp/issues/55 + + // Pointers must be valid; otherwise undefined behavior + CRYPTOPP_ASSERT(dest != NULLPTR); CRYPTOPP_ASSERT(src != NULLPTR); + // Restricted pointers. We want to check ranges, but it is not clear how to do it. + CRYPTOPP_ASSERT(src != dest); + // Destination buffer must be large enough to satisfy request + CRYPTOPP_ASSERT(sizeInBytes >= count); + + if (count > sizeInBytes) + throw InvalidArgument("memcpy_s: buffer overflow"); + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4996) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6386) +# endif +#endif + if (src != NULLPTR && dest != NULLPTR) + std::memcpy(dest, src, count); +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif +} + +/// \brief Bounds checking replacement for memmove() +/// \param dest pointer to the destination memory block +/// \param sizeInBytes size of the destination memory block, in bytes +/// \param src pointer to the source memory block +/// \param count the number of bytes to copy +/// \throw InvalidArgument +/// \details ISO/IEC TR-24772 provides bounds checking interfaces for potentially +/// unsafe functions like memcpy(), strcpy() and memmove(). However, +/// not all standard libraries provides them, like Glibc. The library's +/// memmove_s() is a near-drop in replacement. Its only a near-replacement +/// because the library's version throws an InvalidArgument on a bounds violation. +/// \details memcpy_s() and memmove_s() are guarded by __STDC_WANT_SECURE_LIB__. +/// If __STDC_WANT_SECURE_LIB__ is not defined or defined to 0, then the library +/// makes memcpy_s() and memmove_s() available. The library will also optionally +/// make the symbols available if CRYPTOPP_WANT_SECURE_LIB is defined. +/// CRYPTOPP_WANT_SECURE_LIB is in config.h, but it is disabled by default. +/// \details memmove_s() will assert the pointers src and dest are not NULL +/// in debug builds. Passing NULL for either pointer is undefined behavior. +inline void memmove_s(void *dest, size_t sizeInBytes, const void *src, size_t count) +{ + // Safer functions on Windows for C&A, http://github.com/weidai11/cryptopp/issues/55 + + // Pointers must be valid; otherwise undefined behavior + CRYPTOPP_ASSERT(dest != NULLPTR); CRYPTOPP_ASSERT(src != NULLPTR); + // Destination buffer must be large enough to satisfy request + CRYPTOPP_ASSERT(sizeInBytes >= count); + + if (count > sizeInBytes) + throw InvalidArgument("memmove_s: buffer overflow"); + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4996) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6386) +# endif +#endif + if (src != NULLPTR && dest != NULLPTR) + std::memmove(dest, src, count); +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif +} + +#if __BORLANDC__ >= 0x620 +// C++Builder 2010 workaround: can't use memcpy_s +// because it doesn't allow 0 lengths +# define memcpy_s CryptoPP::memcpy_s +# define memmove_s CryptoPP::memmove_s +#endif + +#endif // __STDC_WANT_SECURE_LIB__ + +/// \brief Swaps two variables which are arrays +/// \tparam T class or type +/// \param a the first value +/// \param b the second value +/// \details C++03 does not provide support for std::swap(__m128i a, __m128i b) +/// because __m128i is an unsigned long long[2]. Most compilers +/// support it out of the box, but Sun Studio C++ compilers 12.2 and 12.3 do not. +/// \sa How to swap two __m128i variables +/// in C++03 given its an opaque type and an array? on Stack Overflow. +template +inline void vec_swap(T& a, T& b) +{ + // __m128i is an unsigned long long[2], and support for swapping it was + // not added until C++11. SunCC 12.1 - 12.3 fail to consume the swap; while + // SunCC 12.4 consumes it without -std=c++11. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120) + T t; + t=a, a=b, b=t; +#else + std::swap(a, b); +#endif +} + +/// \brief Memory block initializer +/// \param ptr pointer to the memory block being written +/// \param val the integer value to write for each byte +/// \param num the size of the source memory block, in bytes +/// \details Internally the function calls memset with the value val. +/// memset_z can be used to initialize a freshly allocated memory block. +/// To zeroize a memory block on destruction use SecureWipeBuffer. +/// \return the pointer to the memory block +/// \sa SecureWipeBuffer +inline void * memset_z(void *ptr, int val, size_t num) +{ +// avoid extraneous warning on GCC 4.3.2 Ubuntu 8.10 +#if CRYPTOPP_GCC_VERSION >= 30001 || CRYPTOPP_LLVM_CLANG_VERSION >= 20800 || \ + CRYPTOPP_APPLE_CLANG_VERSION >= 30000 + if (__builtin_constant_p(num) && num==0) + return ptr; +#endif + return std::memset(ptr, val, num); +} + +/// \brief Replacement function for std::min +/// \tparam T class or type +/// \param a the first value +/// \param b the second value +/// \return the minimum value based on a comparison of b \< a using operator\< +/// \details STDMIN was provided because the library could not easily use std::min or std::max in Windows or Cygwin 1.1.0 +template inline const T& STDMIN(const T& a, const T& b) +{ + return b < a ? b : a; +} + +/// \brief Replacement function for std::max +/// \tparam T class or type +/// \param a the first value +/// \param b the second value +/// \return the minimum value based on a comparison of a \< b using operator\< +/// \details STDMAX was provided because the library could not easily use std::min or std::max in Windows or Cygwin 1.1.0 +template inline const T& STDMAX(const T& a, const T& b) +{ + return a < b ? b : a; +} + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4389) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wstrict-overflow" +# if (CRYPTOPP_LLVM_CLANG_VERSION >= 20800) || (CRYPTOPP_APPLE_CLANG_VERSION >= 30000) +# pragma GCC diagnostic ignored "-Wtautological-compare" +# elif (CRYPTOPP_GCC_VERSION >= 40300) +# pragma GCC diagnostic ignored "-Wtype-limits" +# endif +#endif + +/// \brief Safe comparison of values that could be negative and incorrectly promoted +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param a the first value +/// \param b the second value +/// \return the minimum value based on a comparison a and b using operator<. +/// \details The comparison b \< a is performed and the value returned is type T1. +template inline const T1 UnsignedMin(const T1& a, const T2& b) +{ + CRYPTOPP_COMPILE_ASSERT((sizeof(T1)<=sizeof(T2) && T2(-1)>0) || (sizeof(T1)>sizeof(T2) && T1(-1)>0)); + CRYPTOPP_COMPILE_ASSERT(std::numeric_limits::is_signed == false); + CRYPTOPP_COMPILE_ASSERT(std::numeric_limits::is_signed == false); + + if (sizeof(T1)<=sizeof(T2)) + return b < (T2)a ? (T1)b : a; + else + return (T1)b < a ? (T1)b : a; +} + +/// \brief Perform a conversion from \p from to \p to +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function returns false, +/// then \p to is undefined and should not be used. +/// \note for integral conversions, a template specialization should be provided. The specialization +/// will perform more efficiently, and avoid warnings for truncation and sign compares. +template +inline bool SafeConvert(T1 from, T2 &to) +{ + to = static_cast(from); + if (from != to || (from > 0) != (to > 0)) + return false; + return true; +} + +// The following specializations are the product of {word32, sword32, word64, sword64} -> +// {word32, sword32, word64, sword64}. There are 16 of them, but we can omit specializations +// of {word64} -> {word64}, {word32} -> {word32}, etc. +// +// The list below proceeds to list the conversion to word64 (3 each), followed by +// sword64 (3 each), followed by word32 (3 each), and finally follwed by sword32 (3 each). + +/// \brief Perform a conversion from \p from to \p to +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function +/// returns false, then \p to is undefined and should not be used. +/// \since Crypto++ 8.8 +template<> +inline bool SafeConvert(sword64 from, word64 &to) +{ + if (from < 0) + return false; + to = static_cast(from); + return true; +} + +/// \brief Perform a conversion from \p from to \p to +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function +/// returns false, then \p to is undefined and should not be used. +/// \since Crypto++ 8.8 +template<> +inline bool SafeConvert(word32 from, word64 &to) +{ + to = static_cast(from); + return true; +} + +/// \brief Perform a conversion from \p from to \p to +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function +/// returns false, then \p to is undefined and should not be used. +/// \since Crypto++ 8.8 +template<> +inline bool SafeConvert(sword32 from, word64 &to) +{ + if (from < 0) + return false; + to = static_cast(from); + return true; +} + +/// \brief Perform a conversion from \p from to \p to +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function +/// returns false, then \p to is undefined and should not be used. +/// \since Crypto++ 8.8 +template<> +inline bool SafeConvert(word64 from, sword64 &to) +{ + if (from > static_cast((std::numeric_limits::max)())) + return false; + to = static_cast(from); + return true; +} + +/// \brief Perform a conversion from \p from to \p to +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function +/// returns false, then \p to is undefined and should not be used. +/// \since Crypto++ 8.8 +template<> +inline bool SafeConvert(word32 from, sword64 &to) +{ + to = static_cast(from); + return true; +} + +/// \brief Perform a conversion from \p from to \p to +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function +/// returns false, then \p to is undefined and should not be used. +/// \since Crypto++ 8.8 +template<> +inline bool SafeConvert(sword32 from, sword64 &to) +{ + to = static_cast(from); + return true; +} + +/// \brief Perform a conversion from \p from to \p to +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function +/// returns false, then \p to is undefined and should not be used. +/// \since Crypto++ 8.8 +template<> +inline bool SafeConvert(word64 from, word32 &to) +{ + if (from > static_cast((std::numeric_limits::max)())) + return false; + to = static_cast(from); + return true; +} + +/// \brief Perform a conversion from \p from to \p to +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function +/// returns false, then \p to is undefined and should not be used. +/// \since Crypto++ 8.8 +template<> +inline bool SafeConvert(sword64 from, word32 &to) +{ + if (from < 0) + return false; + else if (from > static_cast((std::numeric_limits::max)())) + return false; + to = static_cast(from); + return true; +} + +/// \brief Perform a conversion from \p from to \p to +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function +/// returns false, then \p to is undefined and should not be used. +/// \since Crypto++ 8.8 +template<> +inline bool SafeConvert(sword32 from, word32 &to) +{ + if (from < 0) + return false; + to = static_cast(from); + return true; +} + +/// \brief Perform a conversion from \p from to \p to +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function +/// returns false, then \p to is undefined and should not be used. +/// \since Crypto++ 8.8 +template<> +inline bool SafeConvert(word64 from, sword32 &to) +{ + if (from > static_cast((std::numeric_limits::max)())) + return false; + to = static_cast(from); + return true; +} + +/// \brief Perform a conversion from \p from to \p to +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function +/// returns false, then \p to is undefined and should not be used. +/// \since Crypto++ 8.8 +template<> +inline bool SafeConvert(sword64 from, sword32 &to) +{ + if (from > static_cast((std::numeric_limits::max)())) + return false; + else if (from < static_cast((std::numeric_limits::min)())) + return false; + to = static_cast(from); + return true; +} + +/// \brief Perform a conversion from \p from to \p to +/// \param from the first value +/// \param to the second value +/// \return true if its safe to convert from \p from to \p to, false otherwise. +/// \details if the function returns true, then it is safe to use \p to. If the function +/// returns false, then \p to is undefined and should not be used. +/// \since Crypto++ 8.8 +template<> +inline bool SafeConvert(word32 from, sword32 &to) +{ + if (from > static_cast((std::numeric_limits::max)())) + return false; + to = static_cast(from); + return true; +} + +/// \brief Converts a value to a string +/// \tparam T class or type +/// \param value the value to convert +/// \param base the base to use during the conversion +/// \return the string representation of value in base. +template +std::string IntToString(T value, unsigned int base = 10) +{ + // Hack... set the high bit for uppercase. + const unsigned int HIGH_BIT = (1U << 31); + const char CH = !!(base & HIGH_BIT) ? 'A' : 'a'; + base &= ~HIGH_BIT; + + CRYPTOPP_ASSERT(base >= 2); + if (value == 0) + return "0"; + + bool negate = false; + if (value < 0) + { + negate = true; + value = 0-value; // VC .NET does not like -a + } + std::string result; + while (value > 0) + { + T digit = value % base; + result = char((digit < 10 ? '0' : (CH - 10)) + digit) + result; + value /= base; + } + if (negate) + result = "-" + result; + return result; +} + +/// \brief Converts an unsigned value to a string +/// \param value the value to convert +/// \param base the base to use during the conversion +/// \return the string representation of value in base. +/// \details this template function specialization was added to suppress +/// Coverity findings on IntToString() with unsigned types. +template <> CRYPTOPP_DLL +std::string IntToString(word64 value, unsigned int base); + +/// \brief Converts an Integer to a string +/// \param value the Integer to convert +/// \param base the base to use during the conversion +/// \return the string representation of value in base. +/// \details This is a template specialization of IntToString(). Use it +/// like IntToString(): +///
+///  // Print integer in base 10
+///  Integer n...
+///  std::string s = IntToString(n, 10);
+/// 
+/// \details The string is presented with lowercase letters by default. A +/// hack is available to switch to uppercase letters without modifying +/// the function signature. +///
+///  // Print integer in base 16, uppercase letters
+///  Integer n...
+///  const unsigned int UPPER = (1 << 31);
+///  std::string s = IntToString(n, (UPPER | 16));
+template <> CRYPTOPP_DLL +std::string IntToString(Integer value, unsigned int base); + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#define RETURN_IF_NONZERO(x) size_t returnedValue = x; if (returnedValue) return returnedValue + +// this version of the macro is fastest on Pentium 3 and Pentium 4 with MSVC 6 SP5 w/ Processor Pack +#define GETBYTE(x, y) (unsigned int)byte((x)>>(8*(y))) +// these may be faster on other CPUs/compilers +// #define GETBYTE(x, y) (unsigned int)(((x)>>(8*(y)))&255) +// #define GETBYTE(x, y) (((byte *)&(x))[y]) + +#define CRYPTOPP_GET_BYTE_AS_BYTE(x, y) byte((x)>>(8*(y))) + +/// \brief Returns the parity of a value +/// \tparam T class or type +/// \param value the value to provide the parity +/// \return 1 if the number 1-bits in the value is odd, 0 otherwise +template +unsigned int Parity(T value) +{ + for (unsigned int i=8*sizeof(value)/2; i>0; i/=2) + value ^= value >> i; + return (unsigned int)value&1; +} + +/// \brief Returns the number of 8-bit bytes or octets required for a value +/// \tparam T class or type +/// \param value the value to test +/// \return the minimum number of 8-bit bytes or octets required to represent a value +template +unsigned int BytePrecision(const T &value) +{ + if (!value) + return 0; + + unsigned int l=0, h=8*sizeof(value); + while (h-l > 8) + { + unsigned int t = (l+h)/2; + if (value >> t) + l = t; + else + h = t; + } + + return h/8; +} + +/// \brief Returns the number of bits required for a value +/// \tparam T class or type +/// \param value the value to test +/// \return the maximum number of bits required to represent a value. +template +unsigned int BitPrecision(const T &value) +{ + if (!value) + return 0; + + unsigned int l=0, h=8*sizeof(value); + + while (h-l > 1) + { + unsigned int t = (l+h)/2; + if (value >> t) + l = t; + else + h = t; + } + + return h; +} + +/// Determines the number of trailing 0-bits in a value +/// \param v the 32-bit value to test +/// \return the number of trailing 0-bits in v, starting at the least significant bit position +/// \details TrailingZeros returns the number of trailing 0-bits in v, starting at the least +/// significant bit position. The return value is undefined if there are no 1-bits set in the value v. +/// \note The function does not return 0 if no 1-bits are set because 0 collides with a 1-bit at the 0-th position. +inline unsigned int TrailingZeros(word32 v) +{ + // GCC 4.7 and VS2012 provides tzcnt on AVX2/BMI enabled processors + // We don't enable for Microsoft because it requires a runtime check. + // http://msdn.microsoft.com/en-us/library/hh977023%28v=vs.110%29.aspx + CRYPTOPP_ASSERT(v != 0); +#if defined(__BMI__) + return (unsigned int)_tzcnt_u32(v); +#elif defined(__GNUC__) && (CRYPTOPP_GCC_VERSION >= 30400) + return (unsigned int)__builtin_ctz(v); +#elif defined(CRYPTOPP_MSC_VERSION) && (CRYPTOPP_MSC_VERSION >= 1400) + unsigned long result; + _BitScanForward(&result, v); + return static_cast(result); +#else + // from http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup + static const int MultiplyDeBruijnBitPosition[32] = + { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + }; + return MultiplyDeBruijnBitPosition[((word32)((v & -v) * 0x077CB531U)) >> 27]; +#endif +} + +/// Determines the number of trailing 0-bits in a value +/// \param v the 64-bit value to test +/// \return the number of trailing 0-bits in v, starting at the least significant bit position +/// \details TrailingZeros returns the number of trailing 0-bits in v, starting at the least +/// significant bit position. The return value is undefined if there are no 1-bits set in the value v. +/// \note The function does not return 0 if no 1-bits are set because 0 collides with a 1-bit at the 0-th position. +inline unsigned int TrailingZeros(word64 v) +{ + // GCC 4.7 and VS2012 provides tzcnt on AVX2/BMI enabled processors + // We don't enable for Microsoft because it requires a runtime check. + // http://msdn.microsoft.com/en-us/library/hh977023%28v=vs.110%29.aspx + CRYPTOPP_ASSERT(v != 0); +#if defined(__BMI__) && defined(__x86_64__) + return (unsigned int)_tzcnt_u64(v); +#elif defined(__GNUC__) && (CRYPTOPP_GCC_VERSION >= 30400) + return (unsigned int)__builtin_ctzll(v); +#elif defined(CRYPTOPP_MSC_VERSION) && (CRYPTOPP_MSC_VERSION >= 1400) && (defined(_M_X64) || defined(_M_IA64)) + unsigned long result; + _BitScanForward64(&result, v); + return static_cast(result); +#else + return word32(v) ? TrailingZeros(word32(v)) : 32 + TrailingZeros(word32(v>>32)); +#endif +} + +/// \brief Truncates the value to the specified number of bits. +/// \tparam T class or type +/// \param value the value to truncate or mask +/// \param bits the number of bits to truncate or mask +/// \return the value truncated to the specified number of bits, starting at the least +/// significant bit position +/// \details This function masks the low-order bits of value and returns the result. The +/// mask is created with (1 << bits) - 1. +template +inline T Crop(T value, size_t bits) +{ + if (bits < 8*sizeof(value)) + return T(value & ((T(1) << bits) - 1)); + else + return value; +} + +/// \brief Returns the number of 8-bit bytes or octets required for the specified number of bits +/// \param bitCount the number of bits +/// \return the minimum number of 8-bit bytes or octets required by bitCount +/// \details BitsToBytes is effectively a ceiling function based on 8-bit bytes. +inline size_t BitsToBytes(size_t bitCount) +{ + return ((bitCount+7)/(8)); +} + +/// \brief Returns the number of words required for the specified number of bytes +/// \param byteCount the number of bytes +/// \return the minimum number of words required by byteCount +/// \details BytesToWords is effectively a ceiling function based on WORD_SIZE. +/// WORD_SIZE is defined in config.h +inline size_t BytesToWords(size_t byteCount) +{ + return ((byteCount+WORD_SIZE-1)/WORD_SIZE); +} + +/// \brief Returns the number of words required for the specified number of bits +/// \param bitCount the number of bits +/// \return the minimum number of words required by bitCount +/// \details BitsToWords is effectively a ceiling function based on WORD_BITS. +/// WORD_BITS is defined in config.h +inline size_t BitsToWords(size_t bitCount) +{ + return ((bitCount+WORD_BITS-1)/(WORD_BITS)); +} + +/// \brief Returns the number of double words required for the specified number of bits +/// \param bitCount the number of bits +/// \return the minimum number of double words required by bitCount +/// \details BitsToDwords is effectively a ceiling function based on 2*WORD_BITS. +/// WORD_BITS is defined in config.h +inline size_t BitsToDwords(size_t bitCount) +{ + return ((bitCount+2*WORD_BITS-1)/(2*WORD_BITS)); +} + +/// Performs an XOR of a buffer with a mask +/// \param buf the buffer to XOR with the mask +/// \param mask the mask to XOR with the buffer +/// \param count the size of the buffers, in bytes +/// \details The function effectively visits each element in the buffers and performs +/// buf[i] ^= mask[i]. buf and mask must be of equal size. +CRYPTOPP_DLL void CRYPTOPP_API xorbuf(byte *buf, const byte *mask, size_t count); + +/// Performs an XOR of an input buffer with a mask and stores the result in an output buffer +/// \param output the destination buffer +/// \param input the source buffer to XOR with the mask +/// \param mask the mask buffer to XOR with the input buffer +/// \param count the size of the buffers, in bytes +/// \details The function effectively visits each element in the buffers and performs +/// output[i] = input[i] ^ mask[i]. output, input and mask must be of equal size. +CRYPTOPP_DLL void CRYPTOPP_API xorbuf(byte *output, const byte *input, const byte *mask, size_t count); + +/// \brief Performs a near constant-time comparison of two equally sized buffers +/// \param buf1 the first buffer +/// \param buf2 the second buffer +/// \param count the size of the buffers, in bytes +/// \details VerifyBufsEqual performs an XOR of the elements in two equally sized +/// buffers and returns a result based on the XOR operation. A count of 0 returns +/// true because two empty buffers are considered equal. +/// \details The function is near constant-time because CPU micro-code timings could +/// affect the "constant-ness". Calling code is responsible for mitigating timing +/// attacks if the buffers are not equally sized. +/// \sa ModPowerOf2 +CRYPTOPP_DLL bool CRYPTOPP_API VerifyBufsEqual(const byte *buf1, const byte *buf2, size_t count); + +/// \brief Tests whether a value is a power of 2 +/// \param value the value to test +/// \return true if value is a power of 2, false otherwise +/// \details The function creates a mask of value - 1 and returns the result +/// of an AND operation compared to 0. If value is 0 or less than 0, then the function +/// returns false. +template +inline bool IsPowerOf2(const T &value) +{ + return value > 0 && (value & (value-1)) == 0; +} + +#if defined(__BMI__) +template <> +inline bool IsPowerOf2(const word32 &value) +{ + return value > 0 && _blsr_u32(value) == 0; +} + +# if defined(__x86_64__) +template <> +inline bool IsPowerOf2(const word64 &value) +{ + return value > 0 && _blsr_u64(value) == 0; +} +# endif // __x86_64__ +#endif // __BMI__ + +/// \brief Provide the minimum value for a type +/// \tparam T type of class +/// \return the minimum value of the type or class +/// \details NumericLimitsMin() was introduced for Clang at Issue 364, +/// Apple Clang 6.0 and numeric_limits::max() returns 0. +/// \details NumericLimitsMin() requires a specialization for T, +/// meaning std::numeric_limits::is_specialized must return +/// true. In the case of word128 Clang did not specialize +/// numeric_limits for the type. +/// \since Crypto++ 8.1 +template +inline T NumericLimitsMin() +{ + CRYPTOPP_ASSERT(std::numeric_limits::is_specialized); + return (std::numeric_limits::min)(); +} + +/// \brief Provide the maximum value for a type +/// \tparam T type of class +/// \return the maximum value of the type or class +/// \details NumericLimitsMax() was introduced for Clang at Issue 364, +/// Apple Clang 6.0 and numeric_limits::max() returns 0. +/// \details NumericLimitsMax() requires a specialization for T, +/// meaning std::numeric_limits::is_specialized must return +/// true. In the case of word128 Clang did not specialize +/// numeric_limits for the type. +/// \since Crypto++ 8.1 +template +inline T NumericLimitsMax() +{ + CRYPTOPP_ASSERT(std::numeric_limits::is_specialized); + return (std::numeric_limits::max)(); +} + +// NumericLimitsMin and NumericLimitsMax added for word128 types, +// see http://github.com/weidai11/cryptopp/issues/364 +#if defined(CRYPTOPP_WORD128_AVAILABLE) +template<> +inline word128 NumericLimitsMin() +{ + return 0; +} +template<> +inline word128 NumericLimitsMax() +{ +#if defined(CRYPTOPP_APPLE_CLANG_VERSION) + return (static_cast(LWORD_MAX) << 64U) | LWORD_MAX; +#else + return (std::numeric_limits::max)(); +#endif +} +#endif + +/// \brief Performs a saturating subtract clamped at 0 +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param a the minuend +/// \param b the subtrahend +/// \return the difference produced by the saturating subtract +/// \details Saturating arithmetic restricts results to a fixed range. Results that are +/// less than 0 are clamped at 0. +/// \details Use of saturating arithmetic in places can be advantageous because it can +/// avoid a branch by using an instruction like a conditional move (CMOVE). +template +inline T1 SaturatingSubtract(const T1 &a, const T2 &b) +{ + // Generated ASM of a typical clamp, http://gcc.gnu.org/ml/gcc-help/2014-10/msg00112.html + return T1((a > b) ? (a - b) : 0); +} + +/// \brief Performs a saturating subtract clamped at 1 +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param a the minuend +/// \param b the subtrahend +/// \return the difference produced by the saturating subtract +/// \details Saturating arithmetic restricts results to a fixed range. Results that are +/// less than 1 are clamped at 1. +/// \details Use of saturating arithmetic in places can be advantageous because it can +/// avoid a branch by using an instruction like a conditional move (CMOVE). +template +inline T1 SaturatingSubtract1(const T1 &a, const T2 &b) +{ + // Generated ASM of a typical clamp, http://gcc.gnu.org/ml/gcc-help/2014-10/msg00112.html + return T1((a > b) ? (a - b) : 1); +} + +/// \brief Reduces a value to a power of 2 +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param a the first value +/// \param b the second value +/// \return ModPowerOf2() returns a & (b-1). b must be a power of 2. +/// Use IsPowerOf2() to determine if b is a suitable candidate. +/// \sa IsPowerOf2 +template +inline T2 ModPowerOf2(const T1 &a, const T2 &b) +{ + CRYPTOPP_ASSERT(IsPowerOf2(b)); + // Coverity finding CID 170383 Overflowed return value (INTEGER_OVERFLOW) + // Visual Studio and /RTCc warning, https://docs.microsoft.com/en-us/cpp/build/reference/rtc-run-time-error-checks + return T2(a & SaturatingSubtract(b,1U)); +} + +/// \brief Rounds a value down to a multiple of a second value +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param n the value to reduce +/// \param m the value to reduce n to a multiple +/// \return the possibly unmodified value \n +/// \details RoundDownToMultipleOf is effectively a floor function based on m. The function returns +/// the value n - n\%m. If n is a multiple of m, then the original value is returned. +/// \note T1 and T2 should be unsigned arithmetic types. If T1 or +/// T2 is signed, then the value should be non-negative. The library asserts in +/// debug builds when practical, but allows you to perform the operation in release builds. +template +inline T1 RoundDownToMultipleOf(const T1 &n, const T2 &m) +{ + // http://github.com/weidai11/cryptopp/issues/364 +#if !defined(CRYPTOPP_APPLE_CLANG_VERSION) || (CRYPTOPP_APPLE_CLANG_VERSION >= 80000) + CRYPTOPP_ASSERT(std::numeric_limits::is_integer); + CRYPTOPP_ASSERT(std::numeric_limits::is_integer); +#endif + + CRYPTOPP_ASSERT(!std::numeric_limits::is_signed || n > 0); + CRYPTOPP_ASSERT(!std::numeric_limits::is_signed || m > 0); + + if (IsPowerOf2(m)) + return n - ModPowerOf2(n, m); + else + return n - n%m; +} + +/// \brief Rounds a value up to a multiple of a second value +/// \tparam T1 class or type +/// \tparam T2 class or type +/// \param n the value to reduce +/// \param m the value to reduce n to a multiple +/// \return the possibly unmodified value \n +/// \details RoundUpToMultipleOf is effectively a ceiling function based on m. The function +/// returns the value n + n\%m. If n is a multiple of m, then the original value is +/// returned. If the value n would overflow, then an InvalidArgument exception is thrown. +/// \note T1 and T2 should be unsigned arithmetic types. If T1 or +/// T2 is signed, then the value should be non-negative. The library asserts in +/// debug builds when practical, but allows you to perform the operation in release builds. +template +inline T1 RoundUpToMultipleOf(const T1 &n, const T2 &m) +{ + // http://github.com/weidai11/cryptopp/issues/364 +#if !defined(CRYPTOPP_APPLE_CLANG_VERSION) || (CRYPTOPP_APPLE_CLANG_VERSION >= 80000) + CRYPTOPP_ASSERT(std::numeric_limits::is_integer); + CRYPTOPP_ASSERT(std::numeric_limits::is_integer); +#endif + + CRYPTOPP_ASSERT(!std::numeric_limits::is_signed || n > 0); + CRYPTOPP_ASSERT(!std::numeric_limits::is_signed || m > 0); + + if (NumericLimitsMax() - m + 1 < n) + throw InvalidArgument("RoundUpToMultipleOf: integer overflow"); + return RoundDownToMultipleOf(T1(n+m-1), m); +} + +/// \brief Returns the minimum alignment requirements of a type +/// \tparam T class or type +/// \return the minimum alignment requirements of T, in bytes +/// \details Internally the function calls C++11's alignof if +/// available. If not available, then the function uses compiler +/// specific extensions such as __alignof and _alignof_. +/// If an extension is not available, then the function uses +/// sizeof(T). +template +inline unsigned int GetAlignmentOf() +{ +#if defined(CRYPTOPP_CXX11_ALIGNOF) + return alignof(T); +#elif (CRYPTOPP_MSC_VERSION >= 1300) + return __alignof(T); +#elif defined(__GNUC__) + return __alignof__(T); +#elif defined(__SUNPRO_CC) + return __alignof__(T); +#elif defined(__IBM_ALIGNOF__) + return __alignof__(T); +#elif CRYPTOPP_BOOL_SLOW_WORD64 + return UnsignedMin(4U, sizeof(T)); +#else + return sizeof(T); +#endif +} + +/// \brief Determines whether ptr is aligned to a minimum value +/// \param ptr the pointer being checked for alignment +/// \param alignment the alignment value to test the pointer against +/// \return true if ptr is aligned on at least alignment +/// boundary, false otherwise +/// \details Internally the function tests whether alignment is 1. If so, +/// the function returns true. If not, then the function effectively +/// performs a modular reduction and returns true if the residue is 0. +inline bool IsAlignedOn(const void *ptr, unsigned int alignment) +{ + const uintptr_t x = reinterpret_cast(ptr); + return alignment==1 || (IsPowerOf2(alignment) ? ModPowerOf2(x, alignment) == 0 : x % alignment == 0); +} + +/// \brief Determines whether ptr is minimally aligned +/// \tparam T class or type +/// \param ptr the pointer to check for alignment +/// \return true if ptr is aligned to at least T +/// boundary, false otherwise +/// \details Internally the function calls IsAlignedOn with a second +/// parameter of GetAlignmentOf. +template +inline bool IsAligned(const void *ptr) +{ + return IsAlignedOn(ptr, GetAlignmentOf()); +} + +#if (CRYPTOPP_LITTLE_ENDIAN) +typedef LittleEndian NativeByteOrder; +#elif (CRYPTOPP_BIG_ENDIAN) +typedef BigEndian NativeByteOrder; +#else +# error "Unable to determine endianness" +#endif + +/// \brief Returns NativeByteOrder as an enumerated ByteOrder value +/// \return LittleEndian if the native byte order is little-endian, +/// and BigEndian if the native byte order is big-endian +/// \details NativeByteOrder is a typedef depending on the platform. +/// If CRYPTOPP_LITTLE_ENDIAN is set in config.h, then +/// GetNativeByteOrder returns LittleEndian. If CRYPTOPP_BIG_ENDIAN +/// is set, then GetNativeByteOrder returns BigEndian. +/// \note There are other byte orders besides little- and big-endian, +/// and they include bi-endian and PDP-endian. If a system is neither +/// little-endian nor big-endian, then a compile time error occurs. +inline ByteOrder GetNativeByteOrder() +{ + return NativeByteOrder::ToEnum(); +} + +/// \brief Determines whether order follows native byte ordering +/// \param order the ordering being tested against native byte ordering +/// \return true if order follows native byte ordering, false otherwise +inline bool NativeByteOrderIs(ByteOrder order) +{ + return order == GetNativeByteOrder(); +} + +/// \brief Returns the direction the cipher is being operated +/// \tparam T class or type +/// \param obj the cipher object being queried +/// \return ENCRYPTION if the cipher obj is being operated in its forward direction, +/// DECRYPTION otherwise +/// \details A cipher can be operated in a "forward" direction (encryption) or a "reverse" +/// direction (decryption). The operations do not have to be symmetric, meaning a second +/// application of the transformation does not necessarily return the original message. +/// That is, E(D(m)) may not equal E(E(m)); and D(E(m)) may not +/// equal D(D(m)). +template +inline CipherDir GetCipherDir(const T &obj) +{ + return obj.IsForwardTransformation() ? ENCRYPTION : DECRYPTION; +} + +/// \brief Performs an addition with carry on a block of bytes +/// \param inout the byte block +/// \param size the size of the block, in bytes +/// \details Performs an addition with carry by adding 1 on a block of bytes starting at the least +/// significant byte. Once carry is 0, the function terminates and returns to the caller. +/// \note The function is not constant time because it stops processing when the carry is 0. +inline void IncrementCounterByOne(byte *inout, unsigned int size) +{ + CRYPTOPP_ASSERT(inout != NULLPTR); + + unsigned int carry=1; + while (carry && size != 0) + { + // On carry inout[n] equals 0 + carry = ! ++inout[size-1]; + size--; + } +} + +/// \brief Performs an addition with carry on a block of bytes +/// \param output the destination block of bytes +/// \param input the source block of bytes +/// \param size the size of the block +/// \details Performs an addition with carry on a block of bytes starting at the least significant +/// byte. Once carry is 0, the remaining bytes from input are copied to output using memcpy. +/// \details The function is close to near-constant time because it operates on all the bytes in the blocks. +inline void IncrementCounterByOne(byte *output, const byte *input, unsigned int size) +{ + CRYPTOPP_ASSERT(output != NULLPTR); + CRYPTOPP_ASSERT(input != NULLPTR); + + unsigned int carry=1; + while (carry && size != 0) + { + // On carry output[n] equals 0 + carry = ! (output[size-1] = input[size-1] + 1); + size--; + } + + while (size != 0) + { + output[size-1] = input[size-1]; + size--; + } +} + +/// \brief Performs a branch-less swap of values a and b if condition c is true +/// \tparam T class or type +/// \param c the condition to perform the swap +/// \param a the first value +/// \param b the second value +template +inline void ConditionalSwap(bool c, T &a, T &b) +{ + T t = c * (a ^ b); + a ^= t; + b ^= t; +} + +/// \brief Performs a branch-less swap of pointers a and b if condition c is true +/// \tparam T class or type +/// \param c the condition to perform the swap +/// \param a the first pointer +/// \param b the second pointer +template +inline void ConditionalSwapPointers(bool c, T &a, T &b) +{ + ptrdiff_t t = size_t(c) * (a - b); + a -= t; + b += t; +} + +// see http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html +// and http://www.securecoding.cert.org/confluence/display/cplusplus/MSC06-CPP.+Be+aware+of+compiler+optimization+when+dealing+with+sensitive+data + +/// \brief Sets each element of an array to 0 +/// \tparam T class or type +/// \param buf an array of elements +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function +/// attempts to survive optimizations and dead code removal. +template +void SecureWipeBuffer(T *buf, size_t n) +{ + // GCC 4.3.2 on Cygwin optimizes away the first store if this + // loop is done in the forward direction + volatile T *p = buf+n; + while (n--) + *(--p) = 0; +} + +#if !defined(CRYPTOPP_DISABLE_ASM) && \ + (CRYPTOPP_MSC_VERSION >= 1400 || defined(__GNUC__)) && \ + (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X86) + +/// \brief Sets each byte of an array to 0 +/// \param buf an array of bytes +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function +/// attempts to survive optimizations and dead code removal. +template<> inline void SecureWipeBuffer(byte *buf, size_t n) +{ + volatile byte *p = buf; +#ifdef __GNUC__ + asm volatile("rep stosb" : "+c"(n), "+D"(p) : "a"(0) : "memory"); +#else + __stosb(reinterpret_cast(reinterpret_cast(p)), 0, n); +#endif +} + +/// \brief Sets each 16-bit element of an array to 0 +/// \param buf an array of 16-bit words +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function +/// attempts to survive optimizations and dead code removal. +template<> inline void SecureWipeBuffer(word16 *buf, size_t n) +{ + volatile word16 *p = buf; +#ifdef __GNUC__ + asm volatile("rep stosw" : "+c"(n), "+D"(p) : "a"(0) : "memory"); +#else + __stosw(reinterpret_cast(reinterpret_cast(p)), 0, n); +#endif +} + +/// \brief Sets each 32-bit element of an array to 0 +/// \param buf an array of 32-bit words +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function +/// attempts to survive optimizations and dead code removal. +template<> inline void SecureWipeBuffer(word32 *buf, size_t n) +{ + volatile word32 *p = buf; +#ifdef __GNUC__ + asm volatile("rep stosl" : "+c"(n), "+D"(p) : "a"(0) : "memory"); +#else + __stosd(reinterpret_cast(reinterpret_cast(p)), 0, n); +#endif +} + +/// \brief Sets each 64-bit element of an array to 0 +/// \param buf an array of 64-bit words +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function +/// attempts to survive optimizations and dead code removal. +template<> inline void SecureWipeBuffer(word64 *buf, size_t n) +{ +#if CRYPTOPP_BOOL_X64 + volatile word64 *p = buf; +# ifdef __GNUC__ + asm volatile("rep stosq" : "+c"(n), "+D"(p) : "a"(0) : "memory"); +# else + __stosq(const_cast(p), 0, n); +# endif +#else + SecureWipeBuffer(reinterpret_cast(buf), 2*n); +#endif +} + +#endif // CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X86 + +#if !defined(CRYPTOPP_DISABLE_ASM) && (CRYPTOPP_MSC_VERSION >= 1700) && defined(_M_ARM) +template<> inline void SecureWipeBuffer(byte *buf, size_t n) +{ + char *p = reinterpret_cast(buf+n); + while (n--) + __iso_volatile_store8(--p, 0); +} + +template<> inline void SecureWipeBuffer(word16 *buf, size_t n) +{ + short *p = reinterpret_cast(buf+n); + while (n--) + __iso_volatile_store16(--p, 0); +} + +template<> inline void SecureWipeBuffer(word32 *buf, size_t n) +{ + int *p = reinterpret_cast(buf+n); + while (n--) + __iso_volatile_store32(--p, 0); +} + +template<> inline void SecureWipeBuffer(word64 *buf, size_t n) +{ + __int64 *p = reinterpret_cast<__int64*>(buf+n); + while (n--) + __iso_volatile_store64(--p, 0); +} +#endif + +/// \brief Sets each element of an array to 0 +/// \tparam T class or type +/// \param buf an array of elements +/// \param n the number of elements in the array +/// \details The operation performs a wipe or zeroization. The function +/// attempts to survive optimizations and dead code removal. +template +inline void SecureWipeArray(T *buf, size_t n) +{ + if (sizeof(T) % 8 == 0 && GetAlignmentOf() % GetAlignmentOf() == 0) + SecureWipeBuffer(reinterpret_cast(static_cast(buf)), n * (sizeof(T)/8)); + else if (sizeof(T) % 4 == 0 && GetAlignmentOf() % GetAlignmentOf() == 0) + SecureWipeBuffer(reinterpret_cast(static_cast(buf)), n * (sizeof(T)/4)); + else if (sizeof(T) % 2 == 0 && GetAlignmentOf() % GetAlignmentOf() == 0) + SecureWipeBuffer(reinterpret_cast(static_cast(buf)), n * (sizeof(T)/2)); + else + SecureWipeBuffer(reinterpret_cast(static_cast(buf)), n * sizeof(T)); +} + +/// \brief Converts a wide character C-string to a multibyte string +/// \param str C-string consisting of wide characters +/// \param throwOnError flag indicating the function should throw on error +/// \return str converted to a multibyte string or an empty string. +/// \details StringNarrow() converts a wide string to a narrow string using C++ std::wcstombs() under +/// the executing thread's locale. A locale must be set before using this function, and it can be +/// set with std::setlocale() if needed. Upon success, the converted string is returned. +/// \details Upon failure with throwOnError as false, the function returns an empty string. If +/// throwOnError as true, the function throws an InvalidArgument() exception. +/// \note If you try to convert, say, the Chinese character for "bone" from UTF-16 (0x9AA8) to UTF-8 +/// (0xE9 0xAA 0xA8), then you must ensure the locale is available. If the locale is not available, +/// then a 0x21 error is returned on Windows which eventually results in an InvalidArgument() exception. +std::string StringNarrow(const wchar_t *str, bool throwOnError = true); + +/// \brief Converts a multibyte C-string to a wide character string +/// \param str C-string consisting of wide characters +/// \param throwOnError flag indicating the function should throw on error +/// \return str converted to a multibyte string or an empty string. +/// \details StringWiden() converts a narrow string to a wide string using C++ std::mbstowcs() under +/// the executing thread's locale. A locale must be set before using this function, and it can be +/// set with std::setlocale() if needed. Upon success, the converted string is returned. +/// \details Upon failure with throwOnError as false, the function returns an empty string. If +/// throwOnError as true, the function throws an InvalidArgument() exception. +/// \note If you try to convert, say, the Chinese character for "bone" from UTF-8 (0xE9 0xAA 0xA8) +/// to UTF-16 (0x9AA8), then you must ensure the locale is available. If the locale is not available, +/// then a 0x21 error is returned on Windows which eventually results in an InvalidArgument() exception. +std::wstring StringWiden(const char *str, bool throwOnError = true); + +// ************** rotate functions *************** + +/// \brief Performs a left rotate +/// \tparam R the number of bit positions to rotate the value +/// \tparam T the word type +/// \param x the value to rotate +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details R must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotlMod if the rotate amount R is outside the range. +/// \details Use rotlConstant when the rotate amount is constant. The template function was added +/// because Clang did not propagate the constant when passed as a function parameter. Clang's +/// need for a constexpr meant rotlFixed failed to compile on occasion. +/// \note rotlConstant attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 6.0 +template inline T rotlConstant(T x) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + CRYPTOPP_ASSERT(static_cast(R) < THIS_SIZE); + return T((x<>(-R&MASK))); +} + +/// \brief Performs a right rotate +/// \tparam R the number of bit positions to rotate the value +/// \tparam T the word type +/// \param x the value to rotate +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details R must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotrMod if the rotate amount R is outside the range. +/// \details Use rotrConstant when the rotate amount is constant. The template function was added +/// because Clang did not propagate the constant when passed as a function parameter. Clang's +/// need for a constexpr meant rotrFixed failed to compile on occasion. +/// \note rotrConstant attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +template inline T rotrConstant(T x) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + CRYPTOPP_ASSERT(static_cast(R) < THIS_SIZE); + return T((x >> R)|(x<<(-R&MASK))); +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotlMod if the rotate amount y is outside the range. +/// \note rotlFixed attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. New code should use rotlConstant, which accepts the rotate amount as a +/// template parameter. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 6.0 +template inline T rotlFixed(T x, unsigned int y) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + CRYPTOPP_ASSERT(static_cast(y) < THIS_SIZE); + return T((x<>(-y&MASK))); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotrMod if the rotate amount y is outside the range. +/// \note rotrFixed attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. New code should use rotrConstant, which accepts the rotate amount as a +/// template parameter. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotrFixed(T x, unsigned int y) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + CRYPTOPP_ASSERT(static_cast(y) < THIS_SIZE); + return T((x >> y)|(x<<(-y&MASK))); +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotlMod if the rotate amount y is outside the range. +/// \note rotlVariable attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotlVariable(T x, unsigned int y) +{ + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + CRYPTOPP_ASSERT(static_cast(y) < THIS_SIZE); + return T((x<>(-y&MASK))); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// Use rotrMod if the rotate amount y is outside the range. +/// \note rotrVariable attempts to enlist a rotate IMM instruction because its often faster +/// than a rotate REG. Immediate rotates can be up to three times faster than their register +/// counterparts. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotrVariable(T x, unsigned int y) +{ + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + CRYPTOPP_ASSERT(static_cast(y) < THIS_SIZE); + return T((x>>y)|(x<<(-y&MASK))); +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y is reduced to the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrVariable will use either rotate IMM or rotate REG. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotlMod(T x, unsigned int y) +{ + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + return T((x<<(y&MASK))|(x>>(-y&MASK))); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +/// \details y is reduced to the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrVariable will use either rotate IMM or rotate REG. +/// \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +/// \since Crypto++ 3.0 +template inline T rotrMod(T x, unsigned int y) +{ + CRYPTOPP_CONSTANT(THIS_SIZE = sizeof(T)*8); + CRYPTOPP_CONSTANT(MASK = THIS_SIZE-1); + return T((x>>(y&MASK))|(x<<(-y&MASK))); +} + +#ifdef CRYPTOPP_MSC_VERSION + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotlFixed will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word32 rotlFixed(word32 x, unsigned int y) +{ + // Uses Microsoft call, bound to C/C++ language rules. + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _lrotl(x, static_cast(y)) : x; +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrFixed will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word32 rotrFixed(word32 x, unsigned int y) +{ + // Uses Microsoft call, bound to C/C++ language rules. + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _lrotr(x, static_cast(y)) : x; +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotlVariable will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word32 rotlVariable(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return _lrotl(x, static_cast(y)); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrVariable will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word32 rotrVariable(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return _lrotr(x, static_cast(y)); +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \since Crypto++ 3.0 +template<> inline word32 rotlMod(word32 x, unsigned int y) +{ + y %= 8*sizeof(x); + return _lrotl(x, static_cast(y)); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 32-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 32-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \since Crypto++ 3.0 +template<> inline word32 rotrMod(word32 x, unsigned int y) +{ + y %= 8*sizeof(x); + return _lrotr(x, static_cast(y)); +} + +#endif // #ifdef CRYPTOPP_MSC_VERSION + +#if (CRYPTOPP_MSC_VERSION >= 1400) || (defined(CRYPTOPP_MSC_VERSION) && !defined(_DLL)) +// Intel C++ Compiler 10.0 calls a function instead of using the rotate instruction when using these instructions + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrFixed will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word64 rotlFixed(word64 x, unsigned int y) +{ + // Uses Microsoft call, bound to C/C++ language rules. + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotl64(x, static_cast(y)) : x; +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrFixed will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word64 rotrFixed(word64 x, unsigned int y) +{ + // Uses Microsoft call, bound to C/C++ language rules. + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotr64(x, static_cast(y)) : x; +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotlVariable will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word64 rotlVariable(word64 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return _rotl64(x, static_cast(y)); +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \note rotrVariable will assert in Debug builds if is outside the allowed range. +/// \since Crypto++ 3.0 +template<> inline word64 rotrVariable(word64 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotr64(x, static_cast(y)) : x; +} + +/// \brief Performs a left rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotl provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \since Crypto++ 3.0 +template<> inline word64 rotlMod(word64 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotl64(x, static_cast(y)) : x; +} + +/// \brief Performs a right rotate +/// \tparam T the word type +/// \param x the 64-bit value to rotate +/// \param y the number of bit positions to rotate the value +/// \details This is a Microsoft specific implementation using _lrotr provided by +/// . The value x to be rotated is 64-bits. y must be in the range +/// [0, sizeof(T)*8 - 1] to avoid undefined behavior. +/// \since Crypto++ 3.0 +template<> inline word64 rotrMod(word64 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 8*sizeof(x)); + return y ? _rotr64(x, static_cast(y)) : x; +} + +#endif // #if CRYPTOPP_MSC_VERSION >= 1310 + +#if CRYPTOPP_MSC_VERSION >= 1400 && !defined(__INTEL_COMPILER) +// Intel C++ Compiler 10.0 gives undefined externals with these +template<> inline word16 rotlFixed(word16 x, unsigned int y) +{ + // Intrinsic, not bound to C/C++ language rules. + return _rotl16(x, static_cast(y)); +} + +template<> inline word16 rotrFixed(word16 x, unsigned int y) +{ + // Intrinsic, not bound to C/C++ language rules. + return _rotr16(x, static_cast(y)); +} + +template<> inline word16 rotlVariable(word16 x, unsigned int y) +{ + return _rotl16(x, static_cast(y)); +} + +template<> inline word16 rotrVariable(word16 x, unsigned int y) +{ + return _rotr16(x, static_cast(y)); +} + +template<> inline word16 rotlMod(word16 x, unsigned int y) +{ + return _rotl16(x, static_cast(y)); +} + +template<> inline word16 rotrMod(word16 x, unsigned int y) +{ + return _rotr16(x, static_cast(y)); +} + +template<> inline byte rotlFixed(byte x, unsigned int y) +{ + // Intrinsic, not bound to C/C++ language rules. + return _rotl8(x, static_cast(y)); +} + +template<> inline byte rotrFixed(byte x, unsigned int y) +{ + // Intrinsic, not bound to C/C++ language rules. + return _rotr8(x, static_cast(y)); +} + +template<> inline byte rotlVariable(byte x, unsigned int y) +{ + return _rotl8(x, static_cast(y)); +} + +template<> inline byte rotrVariable(byte x, unsigned int y) +{ + return _rotr8(x, static_cast(y)); +} + +template<> inline byte rotlMod(byte x, unsigned int y) +{ + return _rotl8(x, static_cast(y)); +} + +template<> inline byte rotrMod(byte x, unsigned int y) +{ + return _rotr8(x, static_cast(y)); +} + +#endif // #if CRYPTOPP_MSC_VERSION >= 1400 + +#if (defined(__MWERKS__) && TARGET_CPU_PPC) + +template<> inline word32 rotlFixed(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 32); + return y ? __rlwinm(x,y,0,31) : x; +} + +template<> inline word32 rotrFixed(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 32); + return y ? __rlwinm(x,32-y,0,31) : x; +} + +template<> inline word32 rotlVariable(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 32); + return (__rlwnm(x,y,0,31)); +} + +template<> inline word32 rotrVariable(word32 x, unsigned int y) +{ + CRYPTOPP_ASSERT(y < 32); + return (__rlwnm(x,32-y,0,31)); +} + +template<> inline word32 rotlMod(word32 x, unsigned int y) +{ + return (__rlwnm(x,y,0,31)); +} + +template<> inline word32 rotrMod(word32 x, unsigned int y) +{ + return (__rlwnm(x,32-y,0,31)); +} + +#endif // __MWERKS__ && TARGET_CPU_PPC + +// ************** endian reversal *************** + +/// \brief Gets a byte from a value +/// \param order the ByteOrder of the value +/// \param value the value to retrieve the byte +/// \param index the location of the byte to retrieve +template +inline unsigned int GetByte(ByteOrder order, T value, unsigned int index) +{ + if (order == LITTLE_ENDIAN_ORDER) + return GETBYTE(value, index); + else + return GETBYTE(value, sizeof(T)-index-1); +} + +/// \brief Reverses bytes in a 8-bit value +/// \param value the 8-bit value to reverse +/// \note ByteReverse returns the value passed to it since there is nothing to +/// reverse. +inline byte ByteReverse(byte value) +{ + return value; +} + +/// \brief Reverses bytes in a 16-bit value +/// \param value the 16-bit value to reverse +/// \details ByteReverse calls bswap if available. Otherwise the function +/// performs a 8-bit rotate on the word16. +inline word16 ByteReverse(word16 value) +{ +#if defined(CRYPTOPP_BYTESWAP_AVAILABLE) + return bswap_16(value); +#elif (CRYPTOPP_MSC_VERSION >= 1400) || (defined(CRYPTOPP_MSC_VERSION) && !defined(_DLL)) + return _byteswap_ushort(value); +#else + return rotlFixed(value, 8U); +#endif +} + +/// \brief Reverses bytes in a 32-bit value +/// \param value the 32-bit value to reverse +/// \details ByteReverse calls bswap if available. Otherwise the function uses +/// a combination of rotates on the word32. +inline word32 ByteReverse(word32 value) +{ +#if defined(CRYPTOPP_BYTESWAP_AVAILABLE) + return bswap_32(value); +#elif defined(CRYPTOPP_ARM_BYTEREV_AVAILABLE) + word32 rvalue; + __asm__ ("rev %0, %1" : "=r" (rvalue) : "r" (value)); + return rvalue; +#elif defined(__GNUC__) && defined(CRYPTOPP_X86_ASM_AVAILABLE) + __asm__ ("bswap %0" : "=r" (value) : "0" (value)); + return value; +#elif defined(__MWERKS__) && TARGET_CPU_PPC + return (word32)__lwbrx(&value,0); +#elif (CRYPTOPP_MSC_VERSION >= 1400) || (defined(CRYPTOPP_MSC_VERSION) && !defined(_DLL)) + return _byteswap_ulong(value); +#elif CRYPTOPP_FAST_ROTATE(32) && !defined(__xlC__) + // 5 instructions with rotate instruction, 9 without + return (rotrFixed(value, 8U) & 0xff00ff00) | (rotlFixed(value, 8U) & 0x00ff00ff); +#else + // 6 instructions with rotate instruction, 8 without + value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); + return rotlFixed(value, 16U); +#endif +} + +/// \brief Reverses bytes in a 64-bit value +/// \param value the 64-bit value to reverse +/// \details ByteReverse calls bswap if available. Otherwise the function uses +/// a combination of rotates on the word64. +inline word64 ByteReverse(word64 value) +{ +#if defined(CRYPTOPP_BYTESWAP_AVAILABLE) + return bswap_64(value); +#elif defined(__GNUC__) && defined(CRYPTOPP_X86_ASM_AVAILABLE) && defined(__x86_64__) + __asm__ ("bswap %0" : "=r" (value) : "0" (value)); + return value; +#elif (CRYPTOPP_MSC_VERSION >= 1400) || (defined(CRYPTOPP_MSC_VERSION) && !defined(_DLL)) + return _byteswap_uint64(value); +#elif CRYPTOPP_BOOL_SLOW_WORD64 + return (word64(ByteReverse(word32(value))) << 32) | ByteReverse(word32(value>>32)); +#else + value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | ((value & W64LIT(0x00FF00FF00FF00FF)) << 8); + value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | ((value & W64LIT(0x0000FFFF0000FFFF)) << 16); + return rotlFixed(value, 32U); +#endif +} + +#if defined(CRYPTOPP_WORD128_AVAILABLE) +/// \brief Reverses bytes in a 128-bit value +/// \param value the 128-bit value to reverse +/// \details ByteReverse calls bswap if available. Otherwise the function uses +/// a combination of rotates on the word128. +/// \note word128 is available on some 64-bit platforms when the compiler supports it. +/// \since Crypto++ 8.7 +inline word128 ByteReverse(word128 value) +{ + // TODO: speed this up + return (word128(ByteReverse(word64(value))) << 64) | ByteReverse(word64(value>>64)); +} +#endif + +/// \brief Reverses bits in a 8-bit value +/// \param value the 8-bit value to reverse +/// \details BitReverse performs a combination of shifts on the byte. +inline byte BitReverse(byte value) +{ + value = byte((value & 0xAA) >> 1) | byte((value & 0x55) << 1); + value = byte((value & 0xCC) >> 2) | byte((value & 0x33) << 2); + return rotlFixed(value, 4U); +} + +/// \brief Reverses bits in a 16-bit value +/// \param value the 16-bit value to reverse +/// \details BitReverse performs a combination of shifts on the word16. +inline word16 BitReverse(word16 value) +{ +#if defined(CRYPTOPP_ARM_BITREV_AVAILABLE) + // 4 instructions on ARM. + word32 rvalue; + __asm__ ("rbit %0, %1" : "=r" (rvalue) : "r" (value)); + return word16(rvalue >> 16); +#else + // 15 instructions on ARM. + value = word16((value & 0xAAAA) >> 1) | word16((value & 0x5555) << 1); + value = word16((value & 0xCCCC) >> 2) | word16((value & 0x3333) << 2); + value = word16((value & 0xF0F0) >> 4) | word16((value & 0x0F0F) << 4); + return ByteReverse(value); +#endif +} + +/// \brief Reverses bits in a 32-bit value +/// \param value the 32-bit value to reverse +/// \details BitReverse performs a combination of shifts on the word32. +inline word32 BitReverse(word32 value) +{ +#if defined(CRYPTOPP_ARM_BITREV_AVAILABLE) + // 2 instructions on ARM. + word32 rvalue; + __asm__ ("rbit %0, %1" : "=r" (rvalue) : "r" (value)); + return rvalue; +#else + // 19 instructions on ARM. + value = word32((value & 0xAAAAAAAA) >> 1) | word32((value & 0x55555555) << 1); + value = word32((value & 0xCCCCCCCC) >> 2) | word32((value & 0x33333333) << 2); + value = word32((value & 0xF0F0F0F0) >> 4) | word32((value & 0x0F0F0F0F) << 4); + return ByteReverse(value); +#endif +} + +/// \brief Reverses bits in a 64-bit value +/// \param value the 64-bit value to reverse +/// \details BitReverse performs a combination of shifts on the word64. +inline word64 BitReverse(word64 value) +{ +#if CRYPTOPP_BOOL_SLOW_WORD64 + return (word64(BitReverse(word32(value))) << 32) | BitReverse(word32(value>>32)); +#else + value = word64((value & W64LIT(0xAAAAAAAAAAAAAAAA)) >> 1) | word64((value & W64LIT(0x5555555555555555)) << 1); + value = word64((value & W64LIT(0xCCCCCCCCCCCCCCCC)) >> 2) | word64((value & W64LIT(0x3333333333333333)) << 2); + value = word64((value & W64LIT(0xF0F0F0F0F0F0F0F0)) >> 4) | word64((value & W64LIT(0x0F0F0F0F0F0F0F0F)) << 4); + return ByteReverse(value); +#endif +} + +/// \brief Reverses bits in a value +/// \param value the value to reverse +/// \details The template overload of BitReverse operates on signed and unsigned values. +/// Internally the size of T is checked, and then value is cast to a byte, +/// word16, word32 or word64. After the cast, the appropriate BitReverse +/// overload is called. +/// \note word128 is available on some 64-bit platforms when the compiler supports it. +/// \since Crypto++ 1.0, word128 since Crypto++ 8.7 +template +inline T BitReverse(T value) +{ + if (sizeof(T) == 1) + return (T)BitReverse((byte)value); + else if (sizeof(T) == 2) + return (T)BitReverse((word16)value); + else if (sizeof(T) == 4) + return (T)BitReverse((word32)value); + else if (sizeof(T) == 8) + return (T)BitReverse((word64)value); +#if defined(CRYPTOPP_WORD128_AVAILABLE) + else if (sizeof(T) == 16) + return (T)BitReverse((word128)value); +#endif + else + { + CRYPTOPP_ASSERT(0); + return (T)BitReverse((word64)value); + } +} + +/// \brief Reverses bytes in a value depending upon endianness +/// \tparam T the class or type +/// \param order the ByteOrder of the data +/// \param value the value to conditionally reverse +/// \details Internally, the ConditionalByteReverse calls NativeByteOrderIs. +/// If order matches native byte order, then the original value is returned. +/// If not, then ByteReverse is called on the value before returning to the caller. +template +inline T ConditionalByteReverse(ByteOrder order, T value) +{ + return NativeByteOrderIs(order) ? value : ByteReverse(value); +} + +/// \brief Reverses bytes in an element from an array of elements +/// \tparam T the class or type +/// \param out the output array of elements +/// \param in the input array of elements +/// \param byteCount the total number of bytes in the array +/// \details Internally, ByteReverse visits each element in the in array +/// calls ByteReverse on it, and writes the result to out. +/// \details ByteReverse does not process tail byes, or bytes that are +/// not part of a full element. If T is int (and int is 4 bytes), then +/// byteCount = 10 means only the first 2 elements or 8 bytes are +/// reversed. +/// \details The following program should help illustrate the behavior. +///
vector v1, v2;
+///
+/// v1.push_back(1);
+/// v1.push_back(2);
+/// v1.push_back(3);
+/// v1.push_back(4);
+///
+/// v2.resize(v1.size());
+/// ByteReverse(&v2[0], &v1[0], 16);
+///
+/// cout << "V1: ";
+/// for(unsigned int i = 0; i < v1.size(); i++)
+///   cout << std::hex << v1[i] << " ";
+/// cout << endl;
+///
+/// cout << "V2: ";
+/// for(unsigned int i = 0; i < v2.size(); i++)
+///   cout << std::hex << v2[i] << " ";
+/// cout << endl;
+/// The program above results in the following output. +///
V1: 00000001 00000002 00000003 00000004
+/// V2: 01000000 02000000 03000000 04000000
+/// \sa ConditionalByteReverse +template +void ByteReverse(T *out, const T *in, size_t byteCount) +{ + // Alignment check due to Issues 690 + CRYPTOPP_ASSERT(byteCount % sizeof(T) == 0); + CRYPTOPP_ASSERT(IsAligned(in)); + CRYPTOPP_ASSERT(IsAligned(out)); + + size_t count = byteCount/sizeof(T); + for (size_t i=0; ibyteCount = 10 means only the first 2 elements or 8 bytes are +/// reversed. +/// \sa ByteReverse +template +inline void ConditionalByteReverse(ByteOrder order, T *out, const T *in, size_t byteCount) +{ + if (!NativeByteOrderIs(order)) + ByteReverse(out, in, byteCount); + else if (in != out) + memcpy_s(out, byteCount, in, byteCount); +} + +/// \brief Copy bytes in a buffer to an array of elements in big-endian order +/// \tparam T the class or type +/// \param order the ByteOrder of the data +/// \param out the output array of elements +/// \param outlen the byte count of the array +/// \param in the input array of elements +/// \param inlen the byte count of the array +template +inline void GetUserKey(ByteOrder order, T *out, size_t outlen, const byte *in, size_t inlen) +{ + const size_t U = sizeof(T); + CRYPTOPP_ASSERT(inlen <= outlen*U); + memcpy_s(out, outlen*U, in, inlen); + memset_z((byte *)out+inlen, 0, outlen*U-inlen); + ConditionalByteReverse(order, out, out, RoundUpToMultipleOf(inlen, U)); +} + +/// \brief Retrieve a byte from an unaligned buffer +/// \param order the ByteOrder of the data +/// \param block an unaligned buffer +/// \param unused dummy parameter +/// \return byte value +/// \details UnalignedGetWordNonTemplate accesses an unaligned buffer and returns a byte value. +/// \since Crypto++ 1.0 +inline byte UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const byte *unused) +{ + CRYPTOPP_UNUSED(order); CRYPTOPP_UNUSED(unused); + return block[0]; +} + +/// \brief Retrieve a word16 from an unaligned buffer +/// \param order the ByteOrder of the data +/// \param block an unaligned buffer +/// \param unused dummy parameter +/// \return byte value +/// \details UnalignedGetWordNonTemplate accesses an unaligned buffer and returns a word16 value. +/// \since Crypto++ 1.0 +inline word16 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const word16 *unused) +{ + CRYPTOPP_UNUSED(unused); + return (order == BIG_ENDIAN_ORDER) + ? block[1] | (block[0] << 8) + : block[0] | (block[1] << 8); +} + +/// \brief Retrieve a word32 from an unaligned buffer +/// \param order the ByteOrder of the data +/// \param block an unaligned buffer +/// \param unused dummy parameter +/// \return byte value +/// \details UnalignedGetWordNonTemplate accesses an unaligned buffer and returns a word32 value. +/// \since Crypto++ 1.0 +inline word32 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const word32 *unused) +{ + CRYPTOPP_UNUSED(unused); + return (order == BIG_ENDIAN_ORDER) + ? word32(block[3]) | (word32(block[2]) << 8) | (word32(block[1]) << 16) | (word32(block[0]) << 24) + : word32(block[0]) | (word32(block[1]) << 8) | (word32(block[2]) << 16) | (word32(block[3]) << 24); +} + +/// \brief Retrieve a word64 from an unaligned buffer +/// \param order the ByteOrder of the data +/// \param block an unaligned buffer +/// \param unused dummy parameter +/// \return byte value +/// \details UnalignedGetWordNonTemplate accesses an unaligned buffer and returns a word64 value. +/// \since Crypto++ 1.0 +inline word64 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const word64 *unused) +{ + CRYPTOPP_UNUSED(unused); + return (order == BIG_ENDIAN_ORDER) + ? + (word64(block[7]) | + (word64(block[6]) << 8) | + (word64(block[5]) << 16) | + (word64(block[4]) << 24) | + (word64(block[3]) << 32) | + (word64(block[2]) << 40) | + (word64(block[1]) << 48) | + (word64(block[0]) << 56)) + : + (word64(block[0]) | + (word64(block[1]) << 8) | + (word64(block[2]) << 16) | + (word64(block[3]) << 24) | + (word64(block[4]) << 32) | + (word64(block[5]) << 40) | + (word64(block[6]) << 48) | + (word64(block[7]) << 56)); +} + +#if defined(CRYPTOPP_WORD128_AVAILABLE) +/// \brief Retrieve a word128 from an unaligned buffer +/// \param order the ByteOrder of the data +/// \param block an unaligned buffer +/// \param unused dummy parameter +/// \return byte value +/// \details UnalignedGetWordNonTemplate accesses an unaligned buffer and returns a word128 value. +/// \note word128 is available on some 64-bit platforms when the compiler supports it. +/// \since Crypto++ 8.7 +inline word128 UnalignedGetWordNonTemplate(ByteOrder order, const byte *block, const word128 *unused) +{ + CRYPTOPP_UNUSED(unused); + return (order == BIG_ENDIAN_ORDER) + ? + (word128(block[15]) | + (word128(block[14]) << 8) | + (word128(block[13]) << 16) | + (word128(block[12]) << 24) | + (word128(block[11]) << 32) | + (word128(block[10]) << 40) | + (word128(block[ 9]) << 48) | + (word128(block[ 8]) << 56) | + (word128(block[ 7]) << 64) | + (word128(block[ 6]) << 72) | + (word128(block[ 5]) << 80) | + (word128(block[ 4]) << 88) | + (word128(block[ 3]) << 96) | + (word128(block[ 2]) << 104) | + (word128(block[ 1]) << 112) | + (word128(block[ 0]) << 120)) + : + (word128(block[ 0]) | + (word128(block[ 1]) << 8) | + (word128(block[ 2]) << 16) | + (word128(block[ 3]) << 24) | + (word128(block[ 4]) << 32) | + (word128(block[ 5]) << 40) | + (word128(block[ 6]) << 48) | + (word128(block[ 7]) << 56) | + (word128(block[ 8]) << 64) | + (word128(block[ 9]) << 72) | + (word128(block[10]) << 80) | + (word128(block[11]) << 88) | + (word128(block[12]) << 96) | + (word128(block[13]) << 104) | + (word128(block[14]) << 112) | + (word128(block[15]) << 120)); +} +#endif + +/// \brief Write a byte to an unaligned buffer +/// \param order the ByteOrder of the data +/// \param block an unaligned output buffer +/// \param value byte value +/// \param xorBlock optional unaligned xor buffer +/// \details UnalignedbyteNonTemplate writes a byte value to an unaligned buffer. +/// \since Crypto++ 1.0 +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, byte value, const byte *xorBlock) +{ + CRYPTOPP_UNUSED(order); + block[0] = static_cast(xorBlock ? (value ^ xorBlock[0]) : value); +} + +/// \brief Write a word16 to an unaligned buffer +/// \param order the ByteOrder of the data +/// \param block an unaligned output buffer +/// \param value word16 value +/// \param xorBlock optional unaligned xor buffer +/// \details UnalignedbyteNonTemplate writes a word16 value to an unaligned buffer. +/// \since Crypto++ 1.0 +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, word16 value, const byte *xorBlock) +{ + if (order == BIG_ENDIAN_ORDER) + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + } + else + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + } + } +} + +/// \brief Write a word32 to an unaligned buffer +/// \param order the ByteOrder of the data +/// \param block an unaligned output buffer +/// \param value word32 value +/// \param xorBlock optional unaligned xor buffer +/// \details UnalignedbyteNonTemplate writes a word32 value to an unaligned buffer. +/// \since Crypto++ 1.0 +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, word32 value, const byte *xorBlock) +{ + if (order == BIG_ENDIAN_ORDER) + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + } + else + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + } + } +} + +/// \brief Write a word64 to an unaligned buffer +/// \param order the ByteOrder of the data +/// \param block an unaligned output buffer +/// \param value word64 value +/// \param xorBlock optional unaligned xor buffer +/// \details UnalignedbyteNonTemplate writes a word64 value to an unaligned buffer. +/// \since Crypto++ 1.0 +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, word64 value, const byte *xorBlock) +{ + if (order == BIG_ENDIAN_ORDER) + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[4] = xorBlock[4] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[5] = xorBlock[5] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[6] = xorBlock[6] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[7] = xorBlock[7] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[4] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[5] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[6] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[7] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + } + else + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[4] = xorBlock[4] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[5] = xorBlock[5] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[6] = xorBlock[6] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[7] = xorBlock[7] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[4] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[5] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[6] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[7] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + } + } +} + +#if defined(CRYPTOPP_WORD128_AVAILABLE) +/// \brief Write a word128 to an unaligned buffer +/// \param order the ByteOrder of the data +/// \param block an unaligned output buffer +/// \param value word128 value +/// \param xorBlock optional unaligned xor buffer +/// \details UnalignedbyteNonTemplate writes a word128 value to an unaligned buffer. +/// \note word128 is available on some 64-bit platforms when the compiler supports it. +/// \since Crypto++ 8.7 +inline void UnalignedbyteNonTemplate(ByteOrder order, byte *block, word128 value, const byte *xorBlock) +{ + if (order == BIG_ENDIAN_ORDER) + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 15); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 14); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 13); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 12); + block[4] = xorBlock[4] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 11); + block[5] = xorBlock[5] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 10); + block[6] = xorBlock[6] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 9); + block[7] = xorBlock[7] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 8); + + block[ 8] = xorBlock[ 8] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + block[ 9] = xorBlock[ 9] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[10] = xorBlock[10] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[11] = xorBlock[11] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[12] = xorBlock[12] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[13] = xorBlock[13] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[14] = xorBlock[14] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[15] = xorBlock[15] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 15); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 14); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 13); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 12); + block[4] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 11); + block[5] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 10); + block[6] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 9); + block[7] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 8); + + block[ 8] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + block[ 9] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[10] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[11] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[12] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[13] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[14] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[15] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + } + } + else + { + if (xorBlock) + { + block[0] = xorBlock[0] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = xorBlock[1] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = xorBlock[2] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = xorBlock[3] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[4] = xorBlock[4] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[5] = xorBlock[5] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[6] = xorBlock[6] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[7] = xorBlock[7] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + + block[ 8] = xorBlock[ 8] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 8); + block[ 9] = xorBlock[ 9] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 9); + block[10] = xorBlock[10] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 10); + block[11] = xorBlock[11] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 11); + block[12] = xorBlock[12] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 12); + block[13] = xorBlock[13] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 13); + block[14] = xorBlock[14] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 14); + block[15] = xorBlock[15] ^ CRYPTOPP_GET_BYTE_AS_BYTE(value, 15); + } + else + { + block[0] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 0); + block[1] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 1); + block[2] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 2); + block[3] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 3); + block[4] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 4); + block[5] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 5); + block[6] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 6); + block[7] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 7); + + block[ 8] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 8); + block[ 9] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 9); + block[10] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 10); + block[11] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 11); + block[12] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 12); + block[13] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 13); + block[14] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 14); + block[15] = CRYPTOPP_GET_BYTE_AS_BYTE(value, 15); + } + } +} +#endif + +/// \brief Access a block of memory +/// \tparam T class or type +/// \param assumeAligned flag indicating alignment +/// \param order the ByteOrder of the data +/// \param block the byte buffer to be processed +/// \return the word in the specified byte order +/// \details GetWord() provides alternate read access to a block of memory. The flag assumeAligned indicates +/// if the memory block is aligned for class or type T. The enumeration ByteOrder is BIG_ENDIAN_ORDER or +/// LITTLE_ENDIAN_ORDER. +/// \details An example of reading two word32 values from a block of memory is shown below. w +/// will be 0x03020100. +///
+///   word32 w;
+///   byte buffer[4] = {0,1,2,3};
+///   w = GetWord(false, LITTLE_ENDIAN_ORDER, buffer);
+/// 
+template +inline T GetWord(bool assumeAligned, ByteOrder order, const byte *block) +{ + CRYPTOPP_UNUSED(assumeAligned); + + T temp = 0; + if (block != NULLPTR) {std::memcpy(&temp, block, sizeof(T));} + return ConditionalByteReverse(order, temp); +} + +/// \brief Access a block of memory +/// \tparam T class or type +/// \param assumeAligned flag indicating alignment +/// \param order the ByteOrder of the data +/// \param result the word in the specified byte order +/// \param block the byte buffer to be processed +/// \details GetWord() provides alternate read access to a block of memory. The flag assumeAligned indicates +/// if the memory block is aligned for class or type T. The enumeration ByteOrder is BIG_ENDIAN_ORDER or +/// LITTLE_ENDIAN_ORDER. +/// \details An example of reading two word32 values from a block of memory is shown below. w +/// will be 0x03020100. +///
+///   word32 w;
+///   byte buffer[4] = {0,1,2,3};
+///   w = GetWord(false, LITTLE_ENDIAN_ORDER, buffer);
+/// 
+template +inline void GetWord(bool assumeAligned, ByteOrder order, T &result, const byte *block) +{ + result = GetWord(assumeAligned, order, block); +} + +/// \brief Access a block of memory +/// \tparam T class or type +/// \param assumeAligned flag indicating alignment +/// \param order the ByteOrder of the data +/// \param block the destination byte buffer +/// \param value the word in the specified byte order +/// \param xorBlock an optional byte buffer to xor +/// \details PutWord() provides alternate write access to a block of memory. The flag assumeAligned indicates +/// if the memory block is aligned for class or type T. The enumeration ByteOrder is BIG_ENDIAN_ORDER or +/// LITTLE_ENDIAN_ORDER. +template +inline void PutWord(bool assumeAligned, ByteOrder order, byte *block, T value, const byte *xorBlock = NULLPTR) +{ + CRYPTOPP_UNUSED(assumeAligned); + + T t1, t2; + t1 = ConditionalByteReverse(order, value); + if (xorBlock != NULLPTR) {std::memcpy(&t2, xorBlock, sizeof(T)); t1 ^= t2;} + if (block != NULLPTR) {std::memcpy(block, &t1, sizeof(T));} +} + +/// \brief Access a block of memory +/// \tparam T class or type +/// \tparam B enumeration indicating endianness +/// \tparam A flag indicating alignment +/// \details GetBlock() provides alternate read access to a block of memory. The enumeration B is +/// BigEndian or LittleEndian. The flag A indicates if the memory block is aligned for class or type T. +/// Repeatedly applying operator() results in advancing in the block of memory. +/// \details An example of reading two word32 values from a block of memory is shown below. w1 +/// will be 0x03020100 and w1 will be 0x07060504. +///
+///   word32 w1, w2;
+///   byte buffer[8] = {0,1,2,3,4,5,6,7};
+///   GetBlock block(buffer);
+///   block(w1)(w2);
+/// 
+template +class GetBlock +{ +public: + /// \brief Construct a GetBlock + /// \param block the memory block + GetBlock(const void *block) + : m_block((const byte *)block) {} + + /// \brief Access a block of memory + /// \tparam U class or type + /// \param x the value to read + /// \return pointer to the remainder of the block after reading x + template + inline GetBlock & operator()(U &x) + { + CRYPTOPP_COMPILE_ASSERT(sizeof(U) >= sizeof(T)); + x = GetWord(A, B::ToEnum(), m_block); + m_block += sizeof(T); + return *this; + } + +private: + const byte *m_block; +}; + +/// \brief Access a block of memory +/// \tparam T class or type +/// \tparam B enumeration indicating endianness +/// \tparam A flag indicating alignment +/// \details PutBlock() provides alternate write access to a block of memory. The enumeration B is +/// BigEndian or LittleEndian. The flag A indicates if the memory block is aligned for class or type T. +/// Repeatedly applying operator() results in advancing in the block of memory. +/// \details An example of writing two word32 values from a block of memory is shown below. After the code +/// executes, the byte buffer will be {0,1,2,3,4,5,6,7}. +///
+///   word32 w1=0x03020100, w2=0x07060504;
+///   byte buffer[8];
+///   PutBlock block(NULLPTR, buffer);
+///   block(w1)(w2);
+/// 
+template +class PutBlock +{ +public: + /// \brief Construct a PutBlock + /// \param block the memory block + /// \param xorBlock optional mask + PutBlock(const void *xorBlock, void *block) + : m_xorBlock((const byte *)xorBlock), m_block((byte *)block) {} + + /// \brief Access a block of memory + /// \tparam U class or type + /// \param x the value to write + /// \return pointer to the remainder of the block after writing x + template + inline PutBlock & operator()(U x) + { + PutWord(A, B::ToEnum(), m_block, (T)x, m_xorBlock); + m_block += sizeof(T); + if (m_xorBlock) + m_xorBlock += sizeof(T); + return *this; + } + +private: + const byte *m_xorBlock; + byte *m_block; +}; + +/// \brief Access a block of memory +/// \tparam T class or type +/// \tparam B enumeration indicating endianness +/// \tparam GA flag indicating alignment for the Get operation +/// \tparam PA flag indicating alignment for the Put operation +/// \details GetBlock() provides alternate write access to a block of memory. The enumeration B is +/// BigEndian or LittleEndian. The flag A indicates if the memory block is aligned for class or type T. +/// \sa GetBlock() and PutBlock(). +template +struct BlockGetAndPut +{ + // function needed because of C++ grammatical ambiguity between expression-statements and declarations + static inline GetBlock Get(const void *block) {return GetBlock(block);} + typedef PutBlock Put; +}; + +/// \brief Convert a word to a string +/// \tparam T class or type +/// \param value the word to convert +/// \param order byte order +/// \return a string representing the value of the word +template +std::string WordToString(T value, ByteOrder order = BIG_ENDIAN_ORDER) +{ + if (!NativeByteOrderIs(order)) + value = ByteReverse(value); + + return std::string((char *)&value, sizeof(value)); +} + +/// \brief Convert a string to a word +/// \tparam T class or type +/// \param str the string to convert +/// \param order byte order +/// \return a word representing the value of the string +template +T StringToWord(const std::string &str, ByteOrder order = BIG_ENDIAN_ORDER) +{ + T value = 0; + memcpy_s(&value, sizeof(value), str.data(), UnsignedMin(str.size(), sizeof(value))); + return NativeByteOrderIs(order) ? value : ByteReverse(value); +} + +// ************** help remove warning on g++ *************** + +/// \brief Safely shift values when undefined behavior could occur +/// \tparam overflow boolean flag indicating if overflow is present +/// \details SafeShifter safely shifts values when undefined behavior could occur under C/C++ rules. +/// The class behaves much like a saturating arithmetic class, clamping values rather than allowing +/// the compiler to remove undefined behavior. +/// \sa SafeShifter, SafeShifter +template struct SafeShifter; + +/// \brief Shifts a value in the presence of overflow +/// \details the true template parameter indicates overflow would occur. +/// In this case, SafeShifter clamps the value and returns 0. +template<> struct SafeShifter +{ + /// \brief Right shifts a value that overflows + /// \tparam T class or type + /// \return 0 + /// \details Since overflow == true, the value 0 is always returned. + /// \sa SafeLeftShift + template + static inline T RightShift(T value, unsigned int bits) + { + CRYPTOPP_UNUSED(value); CRYPTOPP_UNUSED(bits); + return 0; + } + + /// \brief Left shifts a value that overflows + /// \tparam T class or type + /// \return 0 + /// \details Since overflow == true, the value 0 is always returned. + /// \sa SafeRightShift + template + static inline T LeftShift(T value, unsigned int bits) + { + CRYPTOPP_UNUSED(value); CRYPTOPP_UNUSED(bits); + return 0; + } +}; + +/// \brief Shifts a value in the absence of overflow +/// \details the false template parameter indicates overflow would not occur. +/// In this case, SafeShifter returns the shfted value. +template<> struct SafeShifter +{ + /// \brief Right shifts a value that does not overflow + /// \tparam T class or type + /// \return the shifted value + /// \details Since overflow == false, the shifted value is returned. + /// \sa SafeLeftShift + template + static inline T RightShift(T value, unsigned int bits) + { + return value >> bits; + } + + /// \brief Left shifts a value that does not overflow + /// \tparam T class or type + /// \return the shifted value + /// \details Since overflow == false, the shifted value is returned. + /// \sa SafeRightShift + template + static inline T LeftShift(T value, unsigned int bits) + { + return value << bits; + } +}; + +/// \brief Safely right shift values when undefined behavior could occur +/// \tparam bits the number of bit positions to shift the value +/// \tparam T class or type +/// \param value the value to right shift +/// \result the shifted value or 0 +/// \details SafeRightShift safely shifts the value to the right when undefined behavior +/// could occur under C/C++ rules. SafeRightShift will return the shifted value or 0 +/// if undefined behavior would occur. +template +inline T SafeRightShift(T value) +{ + return SafeShifter<(bits>=(8*sizeof(T)))>::RightShift(value, bits); +} + +/// \brief Safely left shift values when undefined behavior could occur +/// \tparam bits the number of bit positions to shift the value +/// \tparam T class or type +/// \param value the value to left shift +/// \result the shifted value or 0 +/// \details SafeLeftShift safely shifts the value to the left when undefined behavior +/// could occur under C/C++ rules. SafeLeftShift will return the shifted value or 0 +/// if undefined behavior would occur. +template +inline T SafeLeftShift(T value) +{ + return SafeShifter<(bits>=(8*sizeof(T)))>::LeftShift(value, bits); +} + +/// \brief Finds first element not in a range +/// \tparam InputIt Input iterator type +/// \tparam T class or type +/// \param first iterator to first element +/// \param last iterator to last element +/// \param value the value used as a predicate +/// \return iterator to the first element in the range that is not value +template +inline InputIt FindIfNot(InputIt first, InputIt last, const T &value) { +#ifdef CRYPTOPP_CXX11_LAMBDA + return std::find_if(first, last, [&value](const T &o) { + return value!=o; + }); +#else + return std::find_if(first, last, std::bind2nd(std::not_equal_to(), value)); +#endif +} + +// ************** use one buffer for multiple data members *************** + +#define CRYPTOPP_BLOCK_1(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+0);} size_t SS1() {return sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_2(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS1());} size_t SS2() {return SS1()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_3(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS2());} size_t SS3() {return SS2()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_4(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS3());} size_t SS4() {return SS3()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_5(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS4());} size_t SS5() {return SS4()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_6(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS5());} size_t SS6() {return SS5()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_7(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS6());} size_t SS7() {return SS6()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCK_8(n, t, s) t* m_##n() {return (t *)(void *)(m_aggregate+SS7());} size_t SS8() {return SS7()+sizeof(t)*(s);} size_t m_##n##Size() {return (s);} +#define CRYPTOPP_BLOCKS_END(i) size_t SST() {return SS##i();} void AllocateBlocks() {m_aggregate.New(SST());} AlignedSecByteBlock m_aggregate; + +NAMESPACE_END + +#if (CRYPTOPP_MSC_VERSION) +# pragma warning(pop) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/modarith.h b/third_party/cryptoppwin/include/cryptopp/modarith.h new file mode 100644 index 00000000..408f4caf --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/modarith.h @@ -0,0 +1,344 @@ +// modarith.h - originally written and placed in the public domain by Wei Dai + +/// \file modarith.h +/// \brief Class file for performing modular arithmetic. + +#ifndef CRYPTOPP_MODARITH_H +#define CRYPTOPP_MODARITH_H + +// implementations are in integer.cpp + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "secblock.h" +#include "misc.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractGroup; +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractRing; +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractEuclideanDomain; + +/// \brief Ring of congruence classes modulo n +/// \details This implementation represents each congruence class as +/// the smallest non-negative integer in that class. +/// \details const Element& returned by member functions are +/// references to internal data members. Since each object may have +/// only one such data member for holding results, you should use the +/// class like this: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+/// The following code will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// \details If a ModularArithmetic() is copied or assigned the modulus +/// is copied, but not the internal data members. The internal data +/// members are undefined after copy or assignment. +/// \sa Integer on the +/// Crypto++ wiki. +class CRYPTOPP_DLL ModularArithmetic : public AbstractRing +{ +public: + + typedef int RandomizationParameter; + typedef Integer Element; + + virtual ~ModularArithmetic() {} + + /// \brief Construct a ModularArithmetic + /// \param modulus congruence class modulus + ModularArithmetic(const Integer &modulus = Integer::One()) + : m_modulus(modulus), m_result(static_cast(0), modulus.reg.size()) {} + + /// \brief Copy construct a ModularArithmetic + /// \param ma other ModularArithmetic + ModularArithmetic(const ModularArithmetic &ma) + : AbstractRing(ma), m_modulus(ma.m_modulus), m_result(static_cast(0), m_modulus.reg.size()) {} + + /// \brief Assign a ModularArithmetic + /// \param ma other ModularArithmetic + ModularArithmetic& operator=(const ModularArithmetic &ma) { + if (this != &ma) + { + m_modulus = ma.m_modulus; + m_result = Integer(static_cast(0), m_modulus.reg.size()); + } + return *this; + } + + /// \brief Construct a ModularArithmetic + /// \param bt BER encoded ModularArithmetic + ModularArithmetic(BufferedTransformation &bt); // construct from BER encoded parameters + + /// \brief Clone a ModularArithmetic + /// \return pointer to a new ModularArithmetic + /// \details Clone effectively copy constructs a new ModularArithmetic. The caller is + /// responsible for deleting the pointer returned from this method. + virtual ModularArithmetic * Clone() const {return new ModularArithmetic(*this);} + + /// \brief Encodes in DER format + /// \param bt BufferedTransformation object + void DEREncode(BufferedTransformation &bt) const; + + /// \brief Encodes element in DER format + /// \param out BufferedTransformation object + /// \param a Element to encode + void DEREncodeElement(BufferedTransformation &out, const Element &a) const; + + /// \brief Decodes element in DER format + /// \param in BufferedTransformation object + /// \param a Element to decode + void BERDecodeElement(BufferedTransformation &in, Element &a) const; + + /// \brief Retrieves the modulus + /// \return the modulus + const Integer& GetModulus() const {return m_modulus;} + + /// \brief Sets the modulus + /// \param newModulus the new modulus + void SetModulus(const Integer &newModulus) + {m_modulus = newModulus; m_result.reg.resize(m_modulus.reg.size());} + + /// \brief Retrieves the representation + /// \return true if the if the modulus is in Montgomery form for multiplication, false otherwise + virtual bool IsMontgomeryRepresentation() const {return false;} + + /// \brief Reduces an element in the congruence class + /// \param a element to convert + /// \return the reduced element + /// \details ConvertIn is useful for derived classes, like MontgomeryRepresentation, which + /// must convert between representations. + virtual Integer ConvertIn(const Integer &a) const + {return a%m_modulus;} + + /// \brief Reduces an element in the congruence class + /// \param a element to convert + /// \return the reduced element + /// \details ConvertOut is useful for derived classes, like MontgomeryRepresentation, which + /// must convert between representations. + virtual Integer ConvertOut(const Integer &a) const + {return a;} + + /// \brief Divides an element by 2 + /// \param a element to convert + const Integer& Half(const Integer &a) const; + + /// \brief Compare two elements for equality + /// \param a first element + /// \param b second element + /// \return true if the elements are equal, false otherwise + /// \details Equal() tests the elements for equality using a==b + bool Equal(const Integer &a, const Integer &b) const + {return a==b;} + + /// \brief Provides the Identity element + /// \return the Identity element + const Integer& Identity() const + {return Integer::Zero();} + + /// \brief Adds elements in the ring + /// \param a first element + /// \param b second element + /// \return the sum of a and b + const Integer& Add(const Integer &a, const Integer &b) const; + + /// \brief TODO + /// \param a first element + /// \param b second element + /// \return TODO + Integer& Accumulate(Integer &a, const Integer &b) const; + + /// \brief Inverts the element in the ring + /// \param a first element + /// \return the inverse of the element + const Integer& Inverse(const Integer &a) const; + + /// \brief Subtracts elements in the ring + /// \param a first element + /// \param b second element + /// \return the difference of a and b. The element a must provide a Subtract member function. + const Integer& Subtract(const Integer &a, const Integer &b) const; + + /// \brief TODO + /// \param a first element + /// \param b second element + /// \return TODO + Integer& Reduce(Integer &a, const Integer &b) const; + + /// \brief Doubles an element in the ring + /// \param a the element + /// \return the element doubled + /// \details Double returns Add(a, a). The element a must provide an Add member function. + const Integer& Double(const Integer &a) const + {return Add(a, a);} + + /// \brief Retrieves the multiplicative identity + /// \return the multiplicative identity + /// \details the base class implementations returns 1. + const Integer& MultiplicativeIdentity() const + {return Integer::One();} + + /// \brief Multiplies elements in the ring + /// \param a the multiplicand + /// \param b the multiplier + /// \return the product of a and b + /// \details Multiply returns a*b\%n. + const Integer& Multiply(const Integer &a, const Integer &b) const + {return m_result1 = a*b%m_modulus;} + + /// \brief Square an element in the ring + /// \param a the element + /// \return the element squared + /// \details Square returns a*a\%n. The element a must provide a Square member function. + const Integer& Square(const Integer &a) const + {return m_result1 = a.Squared()%m_modulus;} + + /// \brief Determines whether an element is a unit in the ring + /// \param a the element + /// \return true if the element is a unit after reduction, false otherwise. + bool IsUnit(const Integer &a) const + {return Integer::Gcd(a, m_modulus).IsUnit();} + + /// \brief Calculate the multiplicative inverse of an element in the ring + /// \param a the element + /// \details MultiplicativeInverse returns a-1\%n. The element a must + /// provide a InverseMod member function. + const Integer& MultiplicativeInverse(const Integer &a) const + {return m_result1 = a.InverseMod(m_modulus);} + + /// \brief Divides elements in the ring + /// \param a the dividend + /// \param b the divisor + /// \return the quotient + /// \details Divide returns a*b-1\%n. + const Integer& Divide(const Integer &a, const Integer &b) const + {return Multiply(a, MultiplicativeInverse(b));} + + /// \brief TODO + /// \param x first element + /// \param e1 first exponent + /// \param y second element + /// \param e2 second exponent + /// \return TODO + Integer CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const; + + /// \brief Exponentiates a base to multiple exponents in the ring + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the + /// result at the respective position in the results array. + /// \details SimultaneousExponentiate() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const; + + /// \brief Provides the maximum bit size of an element in the ring + /// \return maximum bit size of an element + unsigned int MaxElementBitLength() const + {return (m_modulus-1).BitCount();} + + /// \brief Provides the maximum byte size of an element in the ring + /// \return maximum byte size of an element + unsigned int MaxElementByteLength() const + {return (m_modulus-1).ByteCount();} + + /// \brief Provides a random element in the ring + /// \param rng RandomNumberGenerator used to generate material + /// \param ignore_for_now unused + /// \return a random element that is uniformly distributed + /// \details RandomElement constructs a new element in the range [0,n-1], inclusive. + /// The element's class must provide a constructor with the signature Element(RandomNumberGenerator rng, + /// Element min, Element max). + Element RandomElement(RandomNumberGenerator &rng, const RandomizationParameter &ignore_for_now = 0) const + // left RandomizationParameter arg as ref in case RandomizationParameter becomes a more complicated struct + { + CRYPTOPP_UNUSED(ignore_for_now); + return Element(rng, Integer::Zero(), m_modulus - Integer::One()) ; + } + + /// \brief Compares two ModularArithmetic for equality + /// \param rhs other ModularArithmetic + /// \return true if this is equal to the other, false otherwise + /// \details The operator tests for equality using this.m_modulus == rhs.m_modulus. + bool operator==(const ModularArithmetic &rhs) const + {return m_modulus == rhs.m_modulus;} + + static const RandomizationParameter DefaultRandomizationParameter; + +private: + // TODO: Clang on OS X needs a real operator=. + // Squash warning on missing assignment operator. + // ModularArithmetic& operator=(const ModularArithmetic &ma); + +protected: + Integer m_modulus; + mutable Integer m_result, m_result1; +}; + +// const ModularArithmetic::RandomizationParameter ModularArithmetic::DefaultRandomizationParameter = 0 ; + +/// \brief Performs modular arithmetic in Montgomery representation for increased speed +/// \details The Montgomery representation represents each congruence class [a] as +/// a*r\%n, where r is a convenient power of 2. +/// \details const Element& returned by member functions are references to +/// internal data members. Since each object may have only one such data member for holding +/// results, the following code will produce incorrect results: +///
    abcd = group.Add(group.Add(a,b), group.Add(c,d));
+/// But this should be fine: +///
    abcd = group.Add(a, group.Add(b, group.Add(c,d));
+class CRYPTOPP_DLL MontgomeryRepresentation : public ModularArithmetic +{ +public: + virtual ~MontgomeryRepresentation() {} + + /// \brief Construct a MontgomeryRepresentation + /// \param modulus congruence class modulus + /// \note The modulus must be odd. + MontgomeryRepresentation(const Integer &modulus); + + /// \brief Clone a MontgomeryRepresentation + /// \return pointer to a new MontgomeryRepresentation + /// \details Clone effectively copy constructs a new MontgomeryRepresentation. The caller is + /// responsible for deleting the pointer returned from this method. + virtual ModularArithmetic * Clone() const {return new MontgomeryRepresentation(*this);} + + bool IsMontgomeryRepresentation() const {return true;} + + Integer ConvertIn(const Integer &a) const + {return (a<<(WORD_BITS*m_modulus.reg.size()))%m_modulus;} + + Integer ConvertOut(const Integer &a) const; + + const Integer& MultiplicativeIdentity() const + {return m_result1 = Integer::Power2(WORD_BITS*m_modulus.reg.size())%m_modulus;} + + const Integer& Multiply(const Integer &a, const Integer &b) const; + + const Integer& Square(const Integer &a) const; + + const Integer& MultiplicativeInverse(const Integer &a) const; + + Integer CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const + {return AbstractRing::CascadeExponentiate(x, e1, y, e2);} + + void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const + {AbstractRing::SimultaneousExponentiate(results, base, exponents, exponentsCount);} + +private: + Integer m_u; + mutable IntegerSecBlock m_workspace; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/modes.h b/third_party/cryptoppwin/include/cryptopp/modes.h new file mode 100644 index 00000000..24126980 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/modes.h @@ -0,0 +1,609 @@ +// modes.h - originally written and placed in the public domain by Wei Dai + +/// \file modes.h +/// \brief Classes for block cipher modes of operation + +#ifndef CRYPTOPP_MODES_H +#define CRYPTOPP_MODES_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" +#include "strciphr.h" +#include "argnames.h" +#include "algparam.h" + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6011 6386 28193) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Block cipher mode of operation information +/// \details Each class derived from this one defines two types, Encryption and Decryption, +/// both of which implement the SymmetricCipher interface. +/// For each mode there are two classes, one of which is a template class, +/// and the other one has a name that ends in "_ExternalCipher". +/// The "external cipher" mode objects hold a reference to the underlying block cipher, +/// instead of holding an instance of it. The reference must be passed in to the constructor. +/// For the "cipher holder" classes, the CIPHER template parameter should be a class +/// derived from BlockCipherDocumentation, for example DES or AES. +/// \details See NIST SP 800-38A for definitions of these modes. See +/// AuthenticatedSymmetricCipherDocumentation for authenticated encryption modes. +struct CipherModeDocumentation : public SymmetricCipherDocumentation +{ +}; + +/// \brief Block cipher mode of operation information +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CipherModeBase : public SymmetricCipher +{ +public: + virtual ~CipherModeBase() {} + + // Algorithm class + std::string AlgorithmProvider() const { + return m_cipher != NULLPTR ? m_cipher->AlgorithmProvider() : "C++"; + } + + /// \brief Returns smallest valid key length + /// \return the minimum key length, in bytes + size_t MinKeyLength() const {return m_cipher->MinKeyLength();} + + /// \brief Returns largest valid key length + /// \return the maximum key length, in bytes + size_t MaxKeyLength() const {return m_cipher->MaxKeyLength();} + + /// \brief Returns default key length + /// \return the default key length, in bytes + size_t DefaultKeyLength() const {return m_cipher->DefaultKeyLength();} + + /// \brief Returns a valid key length for the algorithm + /// \param keylength the size of the key, in bytes + /// \return the valid key length, in bytes + /// \details keylength is provided in bytes, not bits. If keylength is less than MIN_KEYLENGTH, + /// then the function returns MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, + /// then the function returns MAX_KEYLENGTH. if If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns a \a lower multiple of + /// KEYLENGTH_MULTIPLE. + size_t GetValidKeyLength(size_t keylength) const {return m_cipher->GetValidKeyLength(keylength);} + + /// \brief Returns whether keylength is a valid key length + /// \param keylength the requested keylength + /// \return true if keylength is valid, false otherwise + /// \details Internally the function calls GetValidKeyLength() + bool IsValidKeyLength(size_t keylength) const {return m_cipher->IsValidKeyLength(keylength);} + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const {return m_cipher->OptimalDataAlignment();} + + /// \brief Returns length of the IV accepted by this object + /// \return the size of an IV, in bytes + /// \throw NotImplemented() if the object does not support resynchronization + /// \details The default implementation throws NotImplemented + unsigned int IVSize() const {return BlockSize();} + + /// \brief Minimal requirement for secure IVs + /// \return the secure IV requirement of the algorithm + virtual IV_Requirement IVRequirement() const =0; + + /// \brief Set external block cipher + /// \param cipher An external block cipher + /// \details The cipher should be keyed. + void SetCipher(BlockCipher &cipher) + { + this->ThrowIfResynchronizable(); + this->m_cipher = &cipher; + this->ResizeBuffers(); + } + + /// \brief Set external block cipher and IV + /// \param cipher An external block cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param feedbackSize the feedback size, in bytes + /// \details The cipher should be keyed. + void SetCipherWithIV(BlockCipher &cipher, const byte *iv, int feedbackSize = 0) + { + this->ThrowIfInvalidIV(iv); + this->m_cipher = &cipher; + this->ResizeBuffers(); + this->SetFeedbackSize(feedbackSize); + if (this->IsResynchronizable()) + this->Resynchronize(iv); + } + +protected: + CipherModeBase() : m_cipher(NULLPTR) {} + inline unsigned int BlockSize() const + { + CRYPTOPP_ASSERT(m_register.size() > 0); + return static_cast(m_register.size()); + } + virtual void SetFeedbackSize(unsigned int feedbackSize) + { + if (!(feedbackSize == 0 || feedbackSize == BlockSize())) + throw InvalidArgument("CipherModeBase: feedback size cannot be specified for this cipher mode"); + } + + virtual void ResizeBuffers(); + + BlockCipher *m_cipher; + SecByteBlock m_register; +}; + +/// \brief Block cipher mode of operation common operations +/// \tparam POLICY_INTERFACE common operations +template +class CRYPTOPP_NO_VTABLE ModePolicyCommonTemplate : public CipherModeBase, public POLICY_INTERFACE +{ + unsigned int GetAlignment() const {return m_cipher->OptimalDataAlignment();} + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); +}; + +template +void ModePolicyCommonTemplate::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) +{ + m_cipher->SetKey(key, length, params); + ResizeBuffers(); + int feedbackSize = params.GetIntValueWithDefault(Name::FeedbackSize(), 0); + SetFeedbackSize(feedbackSize); +} + +/// \brief CFB block cipher mode of operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CFB_ModePolicy : public ModePolicyCommonTemplate +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "CFB";} + + virtual ~CFB_ModePolicy() {} + CFB_ModePolicy() : m_feedbackSize(0) {} + IV_Requirement IVRequirement() const {return RANDOM_IV;} + +protected: + unsigned int GetBytesPerIteration() const {return m_feedbackSize;} + bool CanIterate() const {return m_feedbackSize == BlockSize();} + void Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount); + void TransformRegister(); + void CipherResynchronize(const byte *iv, size_t length); + void SetFeedbackSize(unsigned int feedbackSize); + void ResizeBuffers(); + byte * GetRegisterBegin(); + + SecByteBlock m_temp; + unsigned int m_feedbackSize; +}; + +/// \brief Initialize a block of memory +/// \param dest the destination block of memory +/// \param dsize the size of the destination block, in bytes +/// \param src the source block of memory +/// \param ssize the size of the source block, in bytes +/// \details CopyOrZero copies ssize bytes from source to destination if +/// src is not NULL. If src is NULL then dest is zero'd. Bounds are not +/// checked at runtime. Debug builds assert if ssize exceeds dsize. +inline void CopyOrZero(void *dest, size_t dsize, const void *src, size_t ssize) +{ + CRYPTOPP_ASSERT(dest); + CRYPTOPP_ASSERT(dsize >= ssize); + + if (src != NULLPTR) + memcpy_s(dest, dsize, src, ssize); + else + std::memset(dest, 0, dsize); +} + +/// \brief OFB block cipher mode of operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE OFB_ModePolicy : public ModePolicyCommonTemplate +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "OFB";} + + bool CipherIsRandomAccess() const {return false;} + IV_Requirement IVRequirement() const {return UNIQUE_IV;} + +protected: + unsigned int GetBytesPerIteration() const {return BlockSize();} + unsigned int GetIterationsToBuffer() const {return m_cipher->OptimalNumberOfParallelBlocks();} + void WriteKeystream(byte *keystreamBuffer, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); +}; + +/// \brief CTR block cipher mode of operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CTR_ModePolicy : public ModePolicyCommonTemplate +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "CTR";} + + virtual ~CTR_ModePolicy() {} + bool CipherIsRandomAccess() const {return true;} + IV_Requirement IVRequirement() const {return RANDOM_IV;} + +protected: + virtual void IncrementCounterBy256(); + unsigned int GetAlignment() const {return m_cipher->OptimalDataAlignment();} + unsigned int GetBytesPerIteration() const {return BlockSize();} + unsigned int GetIterationsToBuffer() const {return m_cipher->OptimalNumberOfParallelBlocks();} + void WriteKeystream(byte *buffer, size_t iterationCount) + {OperateKeystream(WRITE_KEYSTREAM, buffer, NULLPTR, iterationCount);} + bool CanOperateKeystream() const {return true;} + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + void SeekToIteration(lword iterationCount); + + // adv_simd.h increments the counter + mutable SecByteBlock m_counterArray; +}; + +/// \brief Block cipher mode of operation default implementation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE BlockOrientedCipherModeBase : public CipherModeBase +{ +public: + virtual ~BlockOrientedCipherModeBase() {} + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + unsigned int MandatoryBlockSize() const {return BlockSize();} + bool IsRandomAccess() const {return false;} + bool IsSelfInverting() const {return false;} + bool IsForwardTransformation() const + {return m_cipher->IsForwardTransformation();} + void Resynchronize(const byte *iv, int length=-1) + {memcpy_s(m_register, m_register.size(), iv, ThrowIfInvalidIVLength(length));} + +protected: + bool RequireAlignedInput() const {return true;} + virtual void ResizeBuffers(); + + SecByteBlock m_buffer; +}; + +/// \brief ECB block cipher mode of operation default implementation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE ECB_OneWay : public BlockOrientedCipherModeBase +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECB";} + + void SetKey(const byte *key, size_t length, const NameValuePairs ¶ms = g_nullNameValuePairs) + {m_cipher->SetKey(key, length, params); BlockOrientedCipherModeBase::ResizeBuffers();} + IV_Requirement IVRequirement() const {return NOT_RESYNCHRONIZABLE;} + unsigned int OptimalBlockSize() const {return static_cast(BlockSize() * m_cipher->OptimalNumberOfParallelBlocks());} + void ProcessData(byte *outString, const byte *inString, size_t length); +}; + +/// \brief CBC block cipher mode of operation default implementation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_ModeBase : public BlockOrientedCipherModeBase +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "CBC";} + + IV_Requirement IVRequirement() const {return UNPREDICTABLE_RANDOM_IV;} + bool RequireAlignedInput() const {return false;} + unsigned int MinLastBlockSize() const {return 0;} +}; + +/// \brief CBC block cipher mode of operation encryption operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_Encryption : public CBC_ModeBase +{ +public: + void ProcessData(byte *outString, const byte *inString, size_t length); +}; + +/// \brief CBC-CTS block cipher mode of operation encryption operation +/// \since Crypto++ 3.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_CTS_Encryption : public CBC_Encryption +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "CBC/CTS";} + + void SetStolenIV(byte *iv) {m_stolenIV = iv;} + unsigned int MinLastBlockSize() const {return BlockSize()+1;} + size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); + +protected: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) + { + CBC_Encryption::UncheckedSetKey(key, length, params); + m_stolenIV = params.GetValueWithDefault(Name::StolenIV(), static_cast(NULLPTR)); + } + + byte *m_stolenIV; +}; + +/// \brief CBC block cipher mode of operation decryption operation +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_Decryption : public CBC_ModeBase +{ +public: + virtual ~CBC_Decryption() {} + void ProcessData(byte *outString, const byte *inString, size_t length); + +protected: + virtual void ResizeBuffers(); + + SecByteBlock m_temp; +}; + +/// \brief CBC-CTS block cipher mode of operation decryption operation +/// \since Crypto++ 3.0 +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_CTS_Decryption : public CBC_Decryption +{ +public: + unsigned int MinLastBlockSize() const {return BlockSize()+1;} + size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); +}; + +/// \brief Block cipher mode of operation aggregate +template +class CipherModeFinalTemplate_CipherHolder : protected ObjectHolder, public AlgorithmImpl > +{ +public: + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like \a AES or \a AES/GCM. Some algorithms + /// do not have standard names yet. For example, there is no standard algorithm name for + /// Shoup's ECIES. + static std::string CRYPTOPP_API StaticAlgorithmName() + {return CIPHER::StaticAlgorithmName() + "/" + BASE::StaticAlgorithmName();} + + /// \brief Construct a CipherModeFinalTemplate + CipherModeFinalTemplate_CipherHolder() + { + this->m_cipher = &this->m_object; + this->ResizeBuffers(); + } + + /// \brief Construct a CipherModeFinalTemplate + /// \param key a byte array used to key the cipher + /// \param length size of the key in bytes + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + CipherModeFinalTemplate_CipherHolder(const byte *key, size_t length) + { + this->m_cipher = &this->m_object; + this->SetKey(key, length); + } + + /// \brief Construct a CipherModeFinalTemplate + /// \param key a byte array used to key the cipher + /// \param length size of the key in bytes + /// \param iv a byte array used to resynchronize the cipher + /// \details key must be at least DEFAULT_KEYLENGTH in length. iv must be IVSize() or + /// BLOCKSIZE in length. Internally, the function calls SimpleKeyingInterface::SetKey. + CipherModeFinalTemplate_CipherHolder(const byte *key, size_t length, const byte *iv) + { + this->m_cipher = &this->m_object; + this->SetKey(key, length, MakeParameters(Name::IV(), ConstByteArrayParameter(iv, this->m_cipher->BlockSize()))); + } + + /// \brief Construct a CipherModeFinalTemplate + /// \param key a byte array used to key the cipher + /// \param length size of the key in bytes + /// \param iv a byte array used to resynchronize the cipher + /// \param feedbackSize the feedback size, in bytes + /// \details key must be at least DEFAULT_KEYLENGTH in length. iv must be IVSize() or + /// BLOCKSIZE in length. Internally, the function calls SimpleKeyingInterface::SetKey. + CipherModeFinalTemplate_CipherHolder(const byte *key, size_t length, const byte *iv, int feedbackSize) + { + this->m_cipher = &this->m_object; + this->SetKey(key, length, MakeParameters(Name::IV(), ConstByteArrayParameter(iv, this->m_cipher->BlockSize()))(Name::FeedbackSize(), feedbackSize)); + } + + // Algorithm class + std::string AlgorithmProvider() const { + return this->m_cipher->AlgorithmProvider(); + } +}; + +/// \tparam BASE CipherModeFinalTemplate_CipherHolder base class +/// \details Base class for external mode cipher combinations +template +class CipherModeFinalTemplate_ExternalCipher : public BASE +{ +public: + /// \brief Construct a default CipherModeFinalTemplate + /// \details The cipher is not keyed. + CipherModeFinalTemplate_ExternalCipher() {} + + /// \brief Construct a CipherModeFinalTemplate + /// \param cipher An external block cipher + /// \details The cipher should be keyed. + CipherModeFinalTemplate_ExternalCipher(BlockCipher &cipher) + {this->SetCipher(cipher);} + + /// \brief Construct a CipherModeFinalTemplate + /// \param cipher An external block cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param feedbackSize the feedback size, in bytes + /// \details The cipher should be keyed. + CipherModeFinalTemplate_ExternalCipher(BlockCipher &cipher, const byte *iv, int feedbackSize = 0) + {this->SetCipherWithIV(cipher, iv, feedbackSize);} + + /// \brief Provides the name of this algorithm + /// \return the standard algorithm name + /// \details The standard algorithm name can be a name like \a AES or \a AES/GCM. Some algorithms + /// do not have standard names yet. For example, there is no standard algorithm name for + /// Shoup's ECIES. + /// \note AlgorithmName is not universally implemented yet + std::string AlgorithmName() const + {return (this->m_cipher ? this->m_cipher->AlgorithmName() + "/" : std::string("")) + BASE::StaticAlgorithmName();} + + // Algorithm class + std::string AlgorithmProvider() const + {return this->m_cipher->AlgorithmProvider();} +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_CipherTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_EncryptionTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_DecryptionTemplate >; + +/// \brief CFB block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct CFB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > Encryption; + typedef CipherModeFinalTemplate_CipherHolder > > > Decryption; +}; + +/// \brief CFB mode, external cipher. +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct CFB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > Encryption; + typedef CipherModeFinalTemplate_ExternalCipher > > > Decryption; +}; + +/// \brief CFB block cipher mode of operation providing FIPS validated cryptography. +/// \details Requires full block plaintext according to FIPS 800-38A +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct CFB_FIPS_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > > Encryption; + typedef CipherModeFinalTemplate_CipherHolder > > > > Decryption; +}; + +/// \brief CFB mode, external cipher, providing FIPS validated cryptography. +/// \details Requires full block plaintext according to FIPS 800-38A +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct CFB_FIPS_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > > Encryption; + typedef CipherModeFinalTemplate_ExternalCipher > > > > Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AdditiveCipherTemplate >; + +/// \brief OFB block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct OFB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > Encryption; + typedef Encryption Decryption; +}; + +/// \brief OFB mode, external cipher. +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct OFB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > Encryption; + typedef Encryption Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AdditiveCipherTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher > > >; + +/// \brief CTR block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct CTR_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > > > Encryption; + typedef Encryption Decryption; +}; + +/// \brief CTR mode, external cipher. +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct CTR_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher > > > Encryption; + typedef Encryption Decryption; +}; + +/// \brief ECB block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct ECB_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder Encryption; + typedef CipherModeFinalTemplate_CipherHolder Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; + +/// \brief ECB mode, external cipher. +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct ECB_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher Encryption; + typedef Encryption Decryption; +}; + +/// \brief CBC block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +template +struct CBC_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder Encryption; + typedef CipherModeFinalTemplate_CipherHolder Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; + +/// \brief CBC mode, external cipher +/// \sa Modes of Operation +/// on the Crypto++ wiki. +struct CBC_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher Encryption; + typedef CipherModeFinalTemplate_ExternalCipher Decryption; +}; + +/// \brief CBC-CTS block cipher mode of operation +/// \sa Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 3.0 +template +struct CBC_CTS_Mode : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder Encryption; + typedef CipherModeFinalTemplate_CipherHolder Decryption; +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; +CRYPTOPP_DLL_TEMPLATE_CLASS CipherModeFinalTemplate_ExternalCipher; + +/// \brief CBC mode with ciphertext stealing, external cipher +/// \sa Modes of Operation +/// on the Crypto++ wiki. +/// \since Crypto++ 3.0 +struct CBC_CTS_Mode_ExternalCipher : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_ExternalCipher Encryption; + typedef CipherModeFinalTemplate_ExternalCipher Decryption; +}; + +NAMESPACE_END + +// Issue 340 +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/modexppc.h b/third_party/cryptoppwin/include/cryptopp/modexppc.h new file mode 100644 index 00000000..cacb0aa6 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/modexppc.h @@ -0,0 +1,48 @@ +#ifndef CRYPTOPP_MODEXPPC_H +#define CRYPTOPP_MODEXPPC_H + +#include "cryptlib.h" +#include "modarith.h" +#include "integer.h" +#include "algebra.h" +#include "eprecomp.h" +#include "smartptr.h" +#include "pubkey.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4231 4275) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_DLL_TEMPLATE_CLASS DL_FixedBasePrecomputationImpl; + +class ModExpPrecomputation : public DL_GroupPrecomputation +{ +public: + virtual ~ModExpPrecomputation() {} + + // DL_GroupPrecomputation + bool NeedConversions() const {return true;} + Element ConvertIn(const Element &v) const {return m_mr->ConvertIn(v);} + virtual Element ConvertOut(const Element &v) const {return m_mr->ConvertOut(v);} + const AbstractGroup & GetGroup() const {return m_mr->MultiplicativeGroup();} + Element BERDecodeElement(BufferedTransformation &bt) const {return Integer(bt);} + void DEREncodeElement(BufferedTransformation &bt, const Element &v) const {v.DEREncode(bt);} + + // non-inherited + void SetModulus(const Integer &v) {m_mr.reset(new MontgomeryRepresentation(v));} + const Integer & GetModulus() const {return m_mr->GetModulus();} + +private: + value_ptr m_mr; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/mqueue.h b/third_party/cryptoppwin/include/cryptopp/mqueue.h new file mode 100644 index 00000000..632ae295 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/mqueue.h @@ -0,0 +1,145 @@ +// mqueue.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Classes for an unlimited queue to store messages + +#ifndef CRYPTOPP_MQUEUE_H +#define CRYPTOPP_MQUEUE_H + +#include "cryptlib.h" +#include "queue.h" +#include "filters.h" +#include "misc.h" + +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Data structure used to store messages +/// \details The queue is implemented with a ByteQueue. +/// \sa MessageQueue +/// on the Crypto++ wiki. +/// \since Crypto++ 2.0 +class CRYPTOPP_DLL MessageQueue : public AutoSignaling +{ +public: + virtual ~MessageQueue() {} + + /// \brief Construct a MessageQueue + /// \param nodeSize the initial node size + MessageQueue(unsigned int nodeSize=256); + + // BufferedTransformation + void IsolatedInitialize(const NameValuePairs ¶meters) + {m_queue.IsolatedInitialize(parameters); m_lengths.assign(1, 0U); m_messageCounts.assign(1, 0U);} + size_t Put2(const byte *begin, size_t length, int messageEnd, bool blocking) + { + CRYPTOPP_UNUSED(blocking); + m_queue.Put(begin, length); + m_lengths.back() += length; + if (messageEnd) + { + m_lengths.push_back(0); + m_messageCounts.back()++; + } + return 0; + } + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush), CRYPTOPP_UNUSED(blocking); return false;} + bool IsolatedMessageSeriesEnd(bool blocking) + {CRYPTOPP_UNUSED(blocking); m_messageCounts.push_back(0); return false;} + + lword MaxRetrievable() const + {return m_lengths.front();} + bool AnyRetrievable() const + {return m_lengths.front() > 0;} + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + lword TotalBytesRetrievable() const + {return m_queue.MaxRetrievable();} + unsigned int NumberOfMessages() const + {return (unsigned int)m_lengths.size()-1;} + bool GetNextMessage(); + + unsigned int NumberOfMessagesInThisSeries() const + {return m_messageCounts[0];} + unsigned int NumberOfMessageSeries() const + {return (unsigned int)m_messageCounts.size()-1;} + + /// \brief Copy messages from this object to another BufferedTransformation. + /// \param target the destination BufferedTransformation + /// \param count the number of messages to copy + /// \param channel the channel on which the transfer should occur + /// \return the number of messages that remain in the copy (i.e., messages not copied) + unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const; + + /// \brief Peek data in the queue + /// \param contiguousSize the size of the data + /// \details Spy() peeks at data at the head of the queue. Spy() does + /// not remove data from the queue. + /// \details The data's size is returned in contiguousSize. + /// Spy() returns the size of the first message in the list. + const byte * Spy(size_t &contiguousSize) const; + + /// \brief Swap contents with another MessageQueue + /// \param rhs the other MessageQueue + void swap(MessageQueue &rhs); + +private: + ByteQueue m_queue; + std::deque m_lengths; + std::deque m_messageCounts; +}; + +/// \brief Filter that checks messages on two channels for equality +class CRYPTOPP_DLL EqualityComparisonFilter : public Unflushable > +{ +public: + /// \brief Different messages were detected + struct MismatchDetected : public Exception + { + /// \brief Construct a MismatchDetected exception + MismatchDetected() : Exception(DATA_INTEGRITY_CHECK_FAILED, "EqualityComparisonFilter: did not receive the same data on two channels") {} + }; + + /// \brief Construct an EqualityComparisonFilter + /// \param attachment an attached transformation + /// \param throwIfNotEqual flag indicating whether the objects throws + /// \param firstChannel string naming the first channel + /// \param secondChannel string naming the second channel + /// \throw MismatchDetected if throwIfNotEqual is true and not equal + /// \details If throwIfNotEqual is false, this filter will output a '\\0' + /// byte when it detects a mismatch, '\\1' otherwise. + EqualityComparisonFilter(BufferedTransformation *attachment=NULLPTR, bool throwIfNotEqual=true, const std::string &firstChannel="0", const std::string &secondChannel="1") + : m_throwIfNotEqual(throwIfNotEqual), m_mismatchDetected(false) + , m_firstChannel(firstChannel), m_secondChannel(secondChannel) + {Detach(attachment);} + + // BufferedTransformation + size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking); + bool ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1, bool blocking=true); + +protected: + unsigned int MapChannel(const std::string &channel) const; + bool HandleMismatchDetected(bool blocking); + +private: + bool m_throwIfNotEqual, m_mismatchDetected; + std::string m_firstChannel, m_secondChannel; + MessageQueue m_q[2]; +}; + +NAMESPACE_END + +#ifndef __BORLANDC__ +NAMESPACE_BEGIN(std) +template<> inline void swap(CryptoPP::MessageQueue &a, CryptoPP::MessageQueue &b) +{ + a.swap(b); +} +NAMESPACE_END +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/mqv.h b/third_party/cryptoppwin/include/cryptopp/mqv.h new file mode 100644 index 00000000..8e25b9cf --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/mqv.h @@ -0,0 +1,268 @@ +// mqv.h - originally written and placed in the public domain by Wei Dai + +/// \file mqv.h +/// \brief Classes for Menezes–Qu–Vanstone (MQV) key agreement +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_MQV_H +#define CRYPTOPP_MQV_H + +#include "cryptlib.h" +#include "gfpcrypt.h" +#include "modarith.h" +#include "integer.h" +#include "algebra.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief MQV domain for performing authenticated key agreement +/// \tparam GROUP_PARAMETERS doamin parameters +/// \tparam COFACTOR_OPTION cofactor option +/// \details GROUP_PARAMETERS parameters include the curve coefcients and the base point. +/// Binary curves use a polynomial to represent its characteristic, while prime curves +/// use a prime number. +/// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain +/// \since Crypto++ 3.0 +template +class MQV_Domain : public AuthenticatedKeyAgreementDomain +{ +public: + typedef GROUP_PARAMETERS GroupParameters; + typedef typename GroupParameters::Element Element; + typedef MQV_Domain Domain; + + /// \brief Construct a MQV domain + MQV_Domain() {} + + /// \brief Construct a MQV domain + /// \param params group parameters and options + MQV_Domain(const GroupParameters ¶ms) + : m_groupParameters(params) {} + + /// \brief Construct a MQV domain + /// \param bt BufferedTransformation with group parameters and options + MQV_Domain(BufferedTransformation &bt) + {m_groupParameters.BERDecode(bt);} + + /// \brief Construct a MQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object. + template + MQV_Domain(T1 v1, T2 v2) + {m_groupParameters.Initialize(v1, v2);} + + /// \brief Construct a MQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object. + template + MQV_Domain(T1 v1, T2 v2, T3 v3) + {m_groupParameters.Initialize(v1, v2, v3);} + + /// \brief Construct a MQV domain + /// \tparam T1 template parameter used as a constructor parameter + /// \tparam T2 template parameter used as a constructor parameter + /// \tparam T3 template parameter used as a constructor parameter + /// \tparam T4 template parameter used as a constructor parameter + /// \param v1 first parameter + /// \param v2 second parameter + /// \param v3 third parameter + /// \param v4 third parameter + /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object. + template + MQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4) + {m_groupParameters.Initialize(v1, v2, v3, v4);} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a const reference + const GroupParameters & GetGroupParameters() const {return m_groupParameters;} + + /// \brief Retrieves the group parameters for this domain + /// \return the group parameters for this domain as a non-const reference + GroupParameters & AccessGroupParameters() {return m_groupParameters;} + + /// \brief Retrieves the crypto parameters for this domain + /// \return the crypto parameters for this domain as a non-const reference + CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();} + + /// \brief Provides the size of the agreed value + /// \return size of agreed value produced in this domain + /// \details The length is calculated using GetEncodedElementSize(false), + /// which means the element is encoded in a non-reversible format. A + /// non-reversible format means its a raw byte array, and it lacks presentation + /// format like an ASN.1 BIT_STRING or OCTET_STRING. + unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + + /// \brief Provides the size of the static private key + /// \return size of static private keys in this domain + /// \details The length is calculated using the byte count of the subgroup order. + unsigned int StaticPrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + + /// \brief Provides the size of the static public key + /// \return size of static public keys in this domain + /// \details The length is calculated using GetEncodedElementSize(true), + /// which means the element is encoded in a reversible format. A reversible + /// format means it has a presentation format, and its an ANS.1 encoded element + /// or point. + unsigned int StaticPublicKeyLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + /// \brief Generate static private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \details The private key is a random scalar used as an exponent in the range + /// [1,MaxExponent()]. + /// \pre COUNTOF(privateKey) == PrivateStaticKeyLength() + void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + } + + /// \brief Generate a static public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \details The public key is an element or point on the curve, and its stored + /// in a revrsible format. A reversible format means it has a presentation + /// format, and its an ANS.1 encoded element or point. + /// \pre COUNTOF(publicKey) == PublicStaticKeyLength() + void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + /// \brief Provides the size of the ephemeral private key + /// \return size of ephemeral private keys in this domain + /// \details An ephemeral private key is a private key and public key. + /// The serialized size is different than a static private key. + unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();} + + /// \brief Provides the size of the ephemeral public key + /// \return size of ephemeral public keys in this domain + /// \details An ephemeral public key is a public key. + /// The serialized size is the same as a static public key. + unsigned int EphemeralPublicKeyLength() const {return StaticPublicKeyLength();} + + /// \brief Generate ephemeral private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer for the generated private key in this domain + /// \pre COUNTOF(privateKey) == EphemeralPrivateKeyLength() + void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(rng, Integer::One(), params.GetMaxExponent()); + x.Encode(privateKey, StaticPrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength()); + } + + /// \brief Generate ephemeral public key from a private key in this domain + /// \param rng a RandomNumberGenerator derived class + /// \param privateKey a byte buffer with the previously generated private key + /// \param publicKey a byte buffer for the generated public key in this domain + /// \pre COUNTOF(publicKey) == EphemeralPublicKeyLength() + void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + std::memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength()); + } + + /// \brief Derive agreed value or shared secret + /// \param agreedValue the shared secret + /// \param staticPrivateKey your long term private key + /// \param ephemeralPrivateKey your ephemeral private key + /// \param staticOtherPublicKey couterparty's long term public key + /// \param ephemeralOtherPublicKey couterparty's ephemeral public key + /// \param validateStaticOtherPublicKey flag indicating validation + /// \return true upon success, false in case of failure + /// \details Agree() performs the authenticated key agreement. Agree() + /// derives a shared secret from your private keys and couterparty's + /// public keys. Each instance or run of the protocol should use a new + /// ephemeral key pair. + /// \details The other's ephemeral public key will always be validated at + /// Level 1 to ensure it is a point on the curve. + /// validateStaticOtherPublicKey determines how thoroughly other's + /// static public key is validated. If you have previously validated the + /// couterparty's static public key, then use + /// validateStaticOtherPublicKey=false to save time. + /// \pre COUNTOF(agreedValue) == AgreedValueLength() + /// \pre COUNTOF(staticPrivateKey) == StaticPrivateKeyLength() + /// \pre COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength() + /// \pre COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength() + /// \pre COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength() + bool Agree(byte *agreedValue, + const byte *staticPrivateKey, const byte *ephemeralPrivateKey, + const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, + bool validateStaticOtherPublicKey=true) const + { + try + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Element WW = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey); + Element VV = params.DecodeElement(ephemeralOtherPublicKey, true); + + Integer s(staticPrivateKey, StaticPrivateKeyLength()); + Integer u(ephemeralPrivateKey, StaticPrivateKeyLength()); + Element V = params.DecodeElement(ephemeralPrivateKey+StaticPrivateKeyLength(), false); + + const Integer &r = params.GetSubgroupOrder(); + Integer h2 = Integer::Power2((r.BitCount()+1)/2); + Integer e = ((h2+params.ConvertElementToInteger(V)%h2)*s+u) % r; + Integer tt = h2 + params.ConvertElementToInteger(VV) % h2; + + if (COFACTOR_OPTION::ToEnum() == NO_COFACTOR_MULTIPLICTION) + { + Element P = params.ExponentiateElement(WW, tt); + P = m_groupParameters.MultiplyElements(P, VV); + Element R[2]; + const Integer e2[2] = {r, e}; + params.SimultaneousExponentiate(R, P, e2, 2); + if (!params.IsIdentity(R[0]) || params.IsIdentity(R[1])) + return false; + params.EncodeElement(false, R[1], agreedValue); + } + else + { + const Integer &k = params.GetCofactor(); + if (COFACTOR_OPTION::ToEnum() == COMPATIBLE_COFACTOR_MULTIPLICTION) + e = ModularArithmetic(r).Divide(e, k); + Element P = m_groupParameters.CascadeExponentiate(VV, k*e, WW, k*(e*tt%r)); + if (params.IsIdentity(P)) + return false; + params.EncodeElement(false, P, agreedValue); + } + } + catch (DL_BadElement &) + { + return false; + } + return true; + } + +private: + DL_GroupParameters & AccessAbstractGroupParameters() {return m_groupParameters;} + const DL_GroupParameters & GetAbstractGroupParameters() const {return m_groupParameters;} + + GroupParameters m_groupParameters; +}; + +/// Menezes-Qu-Vanstone in GF(p) with key validation, AKA MQV +/// \sa MQV, HMQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain +/// \since Crypto++ 3.0 +typedef MQV_Domain MQV; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/naclite.h b/third_party/cryptoppwin/include/cryptopp/naclite.h new file mode 100644 index 00000000..efb542cd --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/naclite.h @@ -0,0 +1,438 @@ +// naclite.h - written and placed in the public domain by Jeffrey Walton +// based on public domain NaCl source code written by +// Daniel J. Bernstein, Bernard van Gastel, Wesley Janssen, +// Tanja Lange, Peter Schwabe and Sjaak Smetsers. + +// The Tweet API was added to the Crypto++ library to cross-validate results. +// We debated over putting it in the Test namespace, but settled for the NaCl +// namespace to segregate it from other parts of the library. + +/// \file naclite.h +/// \brief Crypto++ interface to TweetNaCl library (20140917) +/// \details TweetNaCl is a compact reimplementation of the NaCl library +/// by Daniel J. Bernstein, Bernard van Gastel, Wesley Janssen, Tanja +/// Lange, Peter Schwabe and Sjaak Smetsers. The library is less than +/// 20 KB in size and provides 25 of the NaCl library functions. +/// \details The compact library uses curve25519, XSalsa20, Poly1305 and +/// SHA-512 as default primitives, and includes both x25519 key exchange +/// and ed25519 signatures. The complete list of functions can be found +/// in TweetNaCl: +/// A crypto library in 100 tweets (20140917), Table 1, page 5. +/// \details Crypto++ rejects small order elements using libsodium's +/// blacklist. The TweetNaCl library allowed them but the library predated +/// the attack. If you wish to allow small elements then use the "unchecked" +/// versions of crypto_box_unchecked, crypto_box_open_unchecked and +/// crypto_box_beforenm_unchecked. +/// \details TweetNaCl is well written but not well optimzed. It runs about +/// 10x slower than optimized routines from libsodium. However, the library +/// is still 2x to 4x faster than the algorithms NaCl was designed to replace +/// and allows cross-checking results from an independent implementation. +/// \details The Crypto++ wrapper for TweetNaCl requires OS features. That is, +/// NO_OS_DEPENDENCE cannot be defined. It is due to TweetNaCl's +/// internal function randombytes. Crypto++ used +/// DefaultAutoSeededRNG within randombytes, so OS +/// integration must be enabled. You can use another generator like +/// RDRAND to avoid the restriction. +/// \sa The security +/// impact of a new cryptographic library, TweetNaCl: +/// A crypto library in 100 tweets (20140917), May the Fourth Be With You: +/// A Microarchitectural Side Channel Attack on Several Real-World +/// Applications of Curve25519, libsodium +/// commit afabd7e7386e1194 and RFC 7748, Elliptic Curves for +/// Security, Section 6. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_NACL_H +#define CRYPTOPP_NACL_H + +#include "config.h" +#include "stdcpp.h" + +#if defined(NO_OS_DEPENDENCE) || !defined(OS_RNG_AVAILABLE) +# define CRYPTOPP_DISABLE_NACL 1 +#endif + +#ifndef CRYPTOPP_DISABLE_NACL + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(NaCl) + +/// \brief Hash size in bytes +/// \sa NaCl crypto_hash documentation +CRYPTOPP_CONSTANT(crypto_hash_BYTES = 64); + +/// \brief Key size in bytes +/// \sa NaCl crypto_stream documentation +CRYPTOPP_CONSTANT(crypto_stream_KEYBYTES = 32); +/// \brief Nonce size in bytes +/// \sa NaCl crypto_stream documentation +CRYPTOPP_CONSTANT(crypto_stream_NONCEBYTES = 24); + +/// \brief Key size in bytes +/// \sa NaCl crypto_auth documentation +CRYPTOPP_CONSTANT(crypto_auth_KEYBYTES = 32); +/// \brief Tag size in bytes +/// \sa NaCl crypto_auth documentation +CRYPTOPP_CONSTANT(crypto_auth_BYTES = 16); + +/// \brief Key size in bytes +/// \sa NaCl crypto_onetimeauth documentation +CRYPTOPP_CONSTANT(crypto_onetimeauth_KEYBYTES = 32); +/// \brief Tag size in bytes +/// \sa NaCl crypto_onetimeauth documentation +CRYPTOPP_CONSTANT(crypto_onetimeauth_BYTES = 16); + +/// \brief Key size in bytes +/// \sa NaCl crypto_secretbox documentation +CRYPTOPP_CONSTANT(crypto_secretbox_KEYBYTES = 32); +/// \brief Nonce size in bytes +/// \sa NaCl crypto_secretbox documentation +CRYPTOPP_CONSTANT(crypto_secretbox_NONCEBYTES = 24); +/// \brief Zero-padded message prefix in bytes +/// \sa NaCl crypto_secretbox documentation +CRYPTOPP_CONSTANT(crypto_secretbox_ZEROBYTES = 32); +/// \brief Zero-padded message prefix in bytes +/// \sa NaCl crypto_secretbox documentation +CRYPTOPP_CONSTANT(crypto_secretbox_BOXZEROBYTES = 16); + +/// \brief Private key size in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_SECRETKEYBYTES = 32); +/// \brief Public key size in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_PUBLICKEYBYTES = 32); +/// \brief Nonce size in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_NONCEBYTES = 24); +/// \brief Message 0-byte prefix in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_ZEROBYTES = 32); +/// \brief Open box 0-byte prefix in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_BOXZEROBYTES = 16); +/// \brief Precomputation 0-byte prefix in bytes in bytes +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_BEFORENMBYTES = 32); +/// \brief MAC size in bytes +/// \details crypto_box_MACBYTES was missing from tweetnacl.h. Its is defined as +/// crypto_box_curve25519xsalsa20poly1305_MACBYTES, which is defined as 16U. +/// \sa NaCl crypto_box documentation +CRYPTOPP_CONSTANT(crypto_box_MACBYTES = 16); + +/// \brief Private key size in bytes +/// \sa NaCl crypto_sign documentation +CRYPTOPP_CONSTANT(crypto_sign_SECRETKEYBYTES = 64); +/// \brief Public key size in bytes +/// \sa NaCl crypto_sign documentation +CRYPTOPP_CONSTANT(crypto_sign_PUBLICKEYBYTES = 32); +/// \brief Seed size in bytes +/// \sa NaCl crypto_sign documentation +CRYPTOPP_CONSTANT(crypto_sign_SEEDBYTES = 32); +/// \brief Signature size in bytes +/// \sa NaCl crypto_sign documentation +CRYPTOPP_CONSTANT(crypto_sign_BYTES = 64); + +/// \brief Group element size in bytes +/// \sa NaCl crypto_scalarmult documentation +CRYPTOPP_CONSTANT(crypto_scalarmult_BYTES = 32); +/// \brief Integer size in bytes +/// \sa NaCl crypto_scalarmult documentation +CRYPTOPP_CONSTANT(crypto_scalarmult_SCALARBYTES = 32); + +/// \brief Encrypt and authenticate a message +/// \param c output byte buffer +/// \param m input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box() uses crypto_box_curve25519xsalsa20poly1305 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box(byte *c,const byte *m,word64 d,const byte *n,const byte *y,const byte *x); + +/// \brief Verify and decrypt a message +/// \param m output byte buffer +/// \param c input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box_open() uses crypto_box_curve25519xsalsa20poly1305 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_open(byte *m,const byte *c,word64 d,const byte *n,const byte *y,const byte *x); + +/// \brief Generate a keypair for encryption +/// \param y public key byte buffer +/// \param x private key byte buffer +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_keypair(byte *y,byte *x); + +/// \brief Encrypt and authenticate a message +/// \param k shared secret byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box_beforenm() performs message-independent precomputation to derive the key. +/// Once the key is derived multiple calls to crypto_box_afternm() can be made to process the message. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_beforenm(byte *k,const byte *y,const byte *x); + +/// \brief Encrypt and authenticate a message +/// \param m output byte buffer +/// \param c input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param k shared secret byte buffer +/// \details crypto_box_afternm() performs message-dependent computation using the derived the key. +/// Once the key is derived using crypto_box_beforenm() multiple calls to crypto_box_afternm() +/// can be made to process the message. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_afternm(byte *c,const byte *m,word64 d,const byte *n,const byte *k); + +/// \brief Verify and decrypt a message +/// \param m output byte buffer +/// \param c input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param k shared secret byte buffer +/// \details crypto_box_afternm() performs message-dependent computation using the derived the key. +/// Once the key is derived using crypto_box_beforenm() multiple calls to crypto_box_open_afternm() +/// can be made to process the message. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_box documentation +/// \since Crypto++ 6.0 +int crypto_box_open_afternm(byte *m,const byte *c,word64 d,const byte *n,const byte *k); + +/// \brief Encrypt and authenticate a message +/// \param c output byte buffer +/// \param m input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box() uses crypto_box_curve25519xsalsa20poly1305. +/// \details This version of crypto_box() does not check for small order elements. It can be unsafe +/// but it exists for backwards compatibility with downlevel clients. Without the compatibility +/// interop with early versions of NaCl, libsodium and other libraries does not exist. The +/// downlevel interop may also be needed of cryptocurrencies like Bitcoin, Ethereum, Monero +/// and Zcash. +/// \return 0 on success, non-0 otherwise +/// \warning This version of crypto_box() does not check for small order elements. It should not +/// be used in new software. +/// \sa NaCl crypto_box documentation, +/// May the Fourth Be With You: A Microarchitectural +/// Side Channel Attack on Several Real-World Applications of Curve25519, +/// libsodium commit +/// afabd7e7386e1194. +/// \since Crypto++ 6.0 +int crypto_box_unchecked(byte *c,const byte *m,word64 d,const byte *n,const byte *y,const byte *x); + +/// \brief Verify and decrypt a message +/// \param m output byte buffer +/// \param c input byte buffer +/// \param d size of the input byte buffer +/// \param n nonce byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box_open() uses crypto_box_curve25519xsalsa20poly1305. +/// \details This version of crypto_box_open() does not check for small order elements. It can be unsafe +/// but it exists for backwards compatibility with downlevel clients. Without the compatibility +/// interop with early versions of NaCl, libsodium and other libraries does not exist. The +/// downlevel interop may also be needed of cryptocurrencies like Bitcoin, Ethereum, Monero +/// and Zcash. +/// \return 0 on success, non-0 otherwise +/// \warning This version of crypto_box_open() does not check for small order elements. It should not +/// be used in new software. +/// \sa NaCl crypto_box documentation, +/// May the Fourth Be With You: A Microarchitectural +/// Side Channel Attack on Several Real-World Applications of Curve25519, +/// libsodium commit +/// afabd7e7386e1194. +/// \since Crypto++ 6.0 +int crypto_box_open_unchecked(byte *m,const byte *c,word64 d,const byte *n,const byte *y,const byte *x); + +/// \brief Encrypt and authenticate a message +/// \param k shared secret byte buffer +/// \param y other's public key +/// \param x private key +/// \details crypto_box_beforenm() performs message-independent precomputation to derive the key. +/// Once the key is derived multiple calls to crypto_box_afternm() can be made to process the message. +/// \details This version of crypto_box_beforenm() does not check for small order elements. It can be unsafe +/// but it exists for backwards compatibility with downlevel clients. Without the compatibility +/// interop with early versions of NaCl, libsodium and other libraries does not exist. The +/// downlevel interop may also be needed of cryptocurrencies like Bitcoin, Ethereum, Monero +/// and Zcash. +/// \return 0 on success, non-0 otherwise +/// \warning This version of crypto_box_beforenm() does not check for small order elements. It should not +/// be used in new software. +/// \sa NaCl crypto_box documentation, +/// May the Fourth Be With You: A Microarchitectural +/// Side Channel Attack on Several Real-World Applications of Curve25519, +/// libsodium commit +/// afabd7e7386e1194. +/// \since Crypto++ 6.0 +int crypto_box_beforenm_unchecked(byte *k,const byte *y,const byte *x); + +/// \brief TODO +int crypto_core_salsa20(byte *out,const byte *in,const byte *k,const byte *c); + +/// \brief TODO +/// \return 0 on success, non-0 otherwise +/// \since Crypto++ 6.0 +int crypto_core_hsalsa20(byte *out,const byte *in,const byte *k,const byte *c); + +/// \brief Hash multiple blocks +/// \details crypto_hashblocks() uses crypto_hashblocks_sha512. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_hash documentation +/// \since Crypto++ 6.0 +int crypto_hashblocks(byte *x,const byte *m,word64 n); + +/// \brief Hash a message +/// \details crypto_hash() uses crypto_hash_sha512. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_hash documentation +/// \since Crypto++ 6.0 +int crypto_hash(byte *out,const byte *m,word64 n); + +/// \brief Create an authentication tag for a message +/// \details crypto_onetimeauth() uses crypto_onetimeauth_poly1305. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_onetimeauth documentation +/// \since Crypto++ 6.0 +int crypto_onetimeauth(byte *out,const byte *m,word64 n,const byte *k); + +/// \brief Verify an authentication tag on a message +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_onetimeauth documentation +/// \since Crypto++ 6.0 +int crypto_onetimeauth_verify(const byte *h,const byte *m,word64 n,const byte *k); + +/// \brief Scalar multiplication of a point +/// \details crypto_scalarmult() uses crypto_scalarmult_curve25519 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_scalarmult documentation +/// \since Crypto++ 6.0 +int crypto_scalarmult(byte *q,const byte *n,const byte *p); + +/// \brief Scalar multiplication of base point +/// \details crypto_scalarmult_base() uses crypto_scalarmult_curve25519 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_scalarmult documentation +/// \since Crypto++ 6.0 +int crypto_scalarmult_base(byte *q,const byte *n); + +/// \brief Encrypt and authenticate a message +/// \details crypto_secretbox() uses a symmetric key to encrypt and authenticate a message. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_secretbox documentation +/// \since Crypto++ 6.0 +int crypto_secretbox(byte *c,const byte *m,word64 d,const byte *n,const byte *k); + +/// \brief Verify and decrypt a message +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_secretbox documentation +/// \since Crypto++ 6.0 +int crypto_secretbox_open(byte *m,const byte *c,word64 d,const byte *n,const byte *k); + +/// \brief Sign a message +/// \param sm output byte buffer +/// \param smlen size of the output byte buffer +/// \param m input byte buffer +/// \param n size of the input byte buffer +/// \param sk private key +/// \details crypto_sign() uses crypto_sign_ed25519. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_sign documentation +/// \since Crypto++ 6.0 +int crypto_sign(byte *sm,word64 *smlen,const byte *m,word64 n,const byte *sk); + +/// \brief Verify a message +/// \param m output byte buffer +/// \param mlen size of the output byte buffer +/// \param sm input byte buffer +/// \param n size of the input byte buffer +/// \param pk public key +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_sign documentation +/// \since Crypto++ 6.0 +int crypto_sign_open(byte *m,word64 *mlen,const byte *sm,word64 n,const byte *pk); + +/// \brief Generate a keypair for signing +/// \param pk public key byte buffer +/// \param sk private key byte buffer +/// \details crypto_sign_keypair() creates an ed25519 keypair. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_sign documentation +/// \since Crypto++ 6.0 +int crypto_sign_keypair(byte *pk, byte *sk); + +/// \brief Calculate a public key from a secret key +/// \param pk public key byte buffer +/// \param sk private key byte buffer +/// \details crypto_sign_sk2pk() creates an ed25519 public key from an existing +/// 32-byte secret key. The function does not backfill the tail bytes of the +/// secret key with the calculated public key. +/// \details crypto_sign_sk2pk() is not part of libsodium or Tweet API. It was +/// added for interop with some anonymous routing protocols. +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_sign documentation +/// \since Crypto++ 8.0 +int crypto_sign_sk2pk(byte *pk, const byte *sk); + +/// \brief Produce a keystream using XSalsa20 +/// \details crypto_stream() uses crypto_stream_xsalsa20 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_stream documentation +/// \since Crypto++ 6.0 +int crypto_stream(byte *c,word64 d,const byte *n,const byte *k); + +/// \brief Encrypt a message using XSalsa20 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_stream documentation +/// \since Crypto++ 6.0 +int crypto_stream_xor(byte *c,const byte *m,word64 d,const byte *n,const byte *k); + +/// \brief Produce a keystream using Salsa20 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_stream documentation +/// \since Crypto++ 6.0 +int crypto_stream_salsa20(byte *c,word64 d,const byte *n,const byte *k); + +/// \brief Encrypt a message using Salsa20 +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_stream documentation +/// \since Crypto++ 6.0 +int crypto_stream_salsa20_xor(byte *c,const byte *m,word64 b,const byte *n,const byte *k); + +/// \brief Compare 16-byte buffers +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_verify documentation +/// \since Crypto++ 6.0 +int crypto_verify_16(const byte *x,const byte *y); + +/// \brief Compare 32-byte buffers +/// \return 0 on success, non-0 otherwise +/// \sa NaCl crypto_verify documentation +/// \since Crypto++ 6.0 +int crypto_verify_32(const byte *x,const byte *y); + +NAMESPACE_END // CryptoPP +NAMESPACE_END // NaCl + +#endif // CRYPTOPP_DISABLE_NACL +#endif // CRYPTOPP_NACL_H diff --git a/third_party/cryptoppwin/include/cryptopp/nbtheory.h b/third_party/cryptoppwin/include/cryptopp/nbtheory.h new file mode 100644 index 00000000..a494110d --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/nbtheory.h @@ -0,0 +1,320 @@ +// nbtheory.h - originally written and placed in the public domain by Wei Dai + +/// \file nbtheory.h +/// \brief Classes and functions for number theoretic operations + +#ifndef CRYPTOPP_NBTHEORY_H +#define CRYPTOPP_NBTHEORY_H + +#include "cryptlib.h" +#include "integer.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief The Small Prime table +/// \param size number of elements in the table +/// \return prime table with /p size elements +/// \details GetPrimeTable() obtains pointer to small prime table and provides the size of the table. +/// /p size is an out parameter. +CRYPTOPP_DLL const word16 * CRYPTOPP_API GetPrimeTable(unsigned int &size); + +// ************ primality testing **************** + +/// \brief Generates a provable prime +/// \param rng a RandomNumberGenerator to produce random material +/// \param bits the number of bits in the prime number +/// \return Integer() meeting Maurer's tests for primality +CRYPTOPP_DLL Integer CRYPTOPP_API MaurerProvablePrime(RandomNumberGenerator &rng, unsigned int bits); + +/// \brief Generates a provable prime +/// \param rng a RandomNumberGenerator to produce random material +/// \param bits the number of bits in the prime number +/// \return Integer() meeting Mihailescu's tests for primality +/// \details Mihailescu's methods performs a search using algorithmic progressions. +CRYPTOPP_DLL Integer CRYPTOPP_API MihailescuProvablePrime(RandomNumberGenerator &rng, unsigned int bits); + +/// \brief Tests whether a number is a small prime +/// \param p a candidate prime to test +/// \return true if p is a small prime, false otherwise +/// \details Internally, the library maintains a table of the first 32719 prime numbers +/// in sorted order. IsSmallPrime searches the table and returns true if p is +/// in the table. +CRYPTOPP_DLL bool CRYPTOPP_API IsSmallPrime(const Integer &p); + +/// \brief Tests whether a number is divisible by a small prime +/// \return true if p is divisible by some prime less than bound. +/// \details TrialDivision() returns true if p is divisible by some prime less +/// than bound. bound should not be greater than the largest entry in the +/// prime table, which is 32719. +CRYPTOPP_DLL bool CRYPTOPP_API TrialDivision(const Integer &p, unsigned bound); + +/// \brief Tests whether a number is divisible by a small prime +/// \return true if p is NOT divisible by small primes. +/// \details SmallDivisorsTest() returns true if p is NOT divisible by some +/// prime less than 32719. +CRYPTOPP_DLL bool CRYPTOPP_API SmallDivisorsTest(const Integer &p); + +/// \brief Determine if a number is probably prime +/// \param n the number to test +/// \param b the base to exponentiate +/// \return true if the number n is probably prime, false otherwise. +/// \details IsFermatProbablePrime raises b to the n-1 power and checks if +/// the result is congruent to 1 modulo n. +/// \details These is no reason to use IsFermatProbablePrime, use IsStrongProbablePrime or +/// IsStrongLucasProbablePrime instead. +/// \sa IsStrongProbablePrime, IsStrongLucasProbablePrime +CRYPTOPP_DLL bool CRYPTOPP_API IsFermatProbablePrime(const Integer &n, const Integer &b); + +/// \brief Determine if a number is probably prime +/// \param n the number to test +/// \return true if the number n is probably prime, false otherwise. +/// \details These is no reason to use IsLucasProbablePrime, use IsStrongProbablePrime or +/// IsStrongLucasProbablePrime instead. +/// \sa IsStrongProbablePrime, IsStrongLucasProbablePrime +CRYPTOPP_DLL bool CRYPTOPP_API IsLucasProbablePrime(const Integer &n); + +/// \brief Determine if a number is probably prime +/// \param n the number to test +/// \param b the base to exponentiate +/// \return true if the number n is probably prime, false otherwise. +CRYPTOPP_DLL bool CRYPTOPP_API IsStrongProbablePrime(const Integer &n, const Integer &b); + +/// \brief Determine if a number is probably prime +/// \param n the number to test +/// \return true if the number n is probably prime, false otherwise. +CRYPTOPP_DLL bool CRYPTOPP_API IsStrongLucasProbablePrime(const Integer &n); + +/// \brief Determine if a number is probably prime +/// \param rng a RandomNumberGenerator to produce random material +/// \param n the number to test +/// \param rounds the number of tests to perform +/// \details This is the Rabin-Miller primality test, i.e. repeating the strong probable prime +/// test for several rounds with random bases +/// \sa Trial divisions before +/// Miller-Rabin checks? on Crypto Stack Exchange +CRYPTOPP_DLL bool CRYPTOPP_API RabinMillerTest(RandomNumberGenerator &rng, const Integer &n, unsigned int rounds); + +/// \brief Verifies a number is probably prime +/// \param p a candidate prime to test +/// \return true if p is a probable prime, false otherwise +/// \details IsPrime() is suitable for testing candidate primes when creating them. Internally, +/// IsPrime() utilizes SmallDivisorsTest(), IsStrongProbablePrime() and IsStrongLucasProbablePrime(). +CRYPTOPP_DLL bool CRYPTOPP_API IsPrime(const Integer &p); + +/// \brief Verifies a number is probably prime +/// \param rng a RandomNumberGenerator for randomized testing +/// \param p a candidate prime to test +/// \param level the level of thoroughness of testing +/// \return true if p is a strong probable prime, false otherwise +/// \details VerifyPrime() is suitable for testing candidate primes created by others. Internally, +/// VerifyPrime() utilizes IsPrime() and one-round RabinMillerTest(). If the candidate passes and +/// level is greater than 1, then 10 round RabinMillerTest() primality testing is performed. +CRYPTOPP_DLL bool CRYPTOPP_API VerifyPrime(RandomNumberGenerator &rng, const Integer &p, unsigned int level = 1); + +/// \brief Application callback to signal suitability of a cabdidate prime +class CRYPTOPP_DLL PrimeSelector +{ +public: + virtual ~PrimeSelector() {} + const PrimeSelector *GetSelectorPointer() const {return this;} + virtual bool IsAcceptable(const Integer &candidate) const =0; +}; + +/// \brief Finds a random prime of special form +/// \param p an Integer reference to receive the prime +/// \param max the maximum value +/// \param equiv the equivalence class based on the parameter mod +/// \param mod the modulus used to reduce the equivalence class +/// \param pSelector pointer to a PrimeSelector function for the application to signal suitability +/// \return true if and only if FirstPrime() finds a prime and returns the prime through p. If FirstPrime() +/// returns false, then no such prime exists and the value of p is undefined +/// \details FirstPrime() uses a fast sieve to find the first probable prime +/// in {x | p<=x<=max and x%mod==equiv} +CRYPTOPP_DLL bool CRYPTOPP_API FirstPrime(Integer &p, const Integer &max, const Integer &equiv, const Integer &mod, const PrimeSelector *pSelector); + +CRYPTOPP_DLL unsigned int CRYPTOPP_API PrimeSearchInterval(const Integer &max); + +CRYPTOPP_DLL AlgorithmParameters CRYPTOPP_API MakeParametersForTwoPrimesOfEqualSize(unsigned int productBitLength); + +// ********** other number theoretic functions ************ + +/// \brief Calculate the greatest common divisor +/// \param a the first term +/// \param b the second term +/// \return the greatest common divisor if one exists, 0 otherwise. +inline Integer GCD(const Integer &a, const Integer &b) + {return Integer::Gcd(a,b);} + +/// \brief Determine relative primality +/// \param a the first term +/// \param b the second term +/// \return true if a and b are relatively prime, false otherwise. +inline bool RelativelyPrime(const Integer &a, const Integer &b) + {return Integer::Gcd(a,b) == Integer::One();} + +/// \brief Calculate the least common multiple +/// \param a the first term +/// \param b the second term +/// \return the least common multiple of a and b. +inline Integer LCM(const Integer &a, const Integer &b) + {return a/Integer::Gcd(a,b)*b;} + +/// \brief Calculate multiplicative inverse +/// \param a the number to test +/// \param b the modulus +/// \return an Integer (a ^ -1) % n or 0 if none exists. +/// \details EuclideanMultiplicativeInverse returns the multiplicative inverse of the Integer +/// *a modulo the Integer b. If no Integer exists then Integer 0 is returned. +inline Integer EuclideanMultiplicativeInverse(const Integer &a, const Integer &b) + {return a.InverseMod(b);} + + +/// \brief Chinese Remainder Theorem +/// \param xp the first number, mod p +/// \param p the first prime modulus +/// \param xq the second number, mod q +/// \param q the second prime modulus +/// \param u inverse of p mod q +/// \return the CRT value of the parameters +/// \details CRT uses the Chinese Remainder Theorem to calculate x given +/// x mod p and x mod q, and u the inverse of p mod q. +CRYPTOPP_DLL Integer CRYPTOPP_API CRT(const Integer &xp, const Integer &p, const Integer &xq, const Integer &q, const Integer &u); + +/// \brief Calculate the Jacobi symbol +/// \param a the first term +/// \param b the second term +/// \return the Jacobi symbol. +/// \details Jacobi symbols are calculated using the following rules: +/// -# if b is prime, then Jacobi(a, b), then return 0 +/// -# if a%b==0 AND a is quadratic residue mod b, then return 1 +/// -# return -1 otherwise +/// \details Refer to a number theory book for what Jacobi symbol means when b is not prime. +CRYPTOPP_DLL int CRYPTOPP_API Jacobi(const Integer &a, const Integer &b); + +/// \brief Calculate the Lucas value +/// \return the Lucas value +/// \details Lucas() calculates the Lucas function V_e(p, 1) mod n. +CRYPTOPP_DLL Integer CRYPTOPP_API Lucas(const Integer &e, const Integer &p, const Integer &n); + +/// \brief Calculate the inverse Lucas value +/// \return the inverse Lucas value +/// \details InverseLucas() calculates x such that m==Lucas(e, x, p*q), +/// p q primes, u is inverse of p mod q. +CRYPTOPP_DLL Integer CRYPTOPP_API InverseLucas(const Integer &e, const Integer &m, const Integer &p, const Integer &q, const Integer &u); + +/// \brief Modular multiplication +/// \param x the first term +/// \param y the second term +/// \param m the modulus +/// \return an Integer (x * y) % m. +inline Integer ModularMultiplication(const Integer &x, const Integer &y, const Integer &m) + {return a_times_b_mod_c(x, y, m);} + +/// \brief Modular exponentiation +/// \param x the base +/// \param e the exponent +/// \param m the modulus +/// \return an Integer (a ^ b) % m. +inline Integer ModularExponentiation(const Integer &x, const Integer &e, const Integer &m) + {return a_exp_b_mod_c(x, e, m);} + +/// \brief Extract a modular square root +/// \param a the number to extract square root +/// \param p the prime modulus +/// \return the modular square root if it exists +/// \details ModularSquareRoot returns x such that x*x%p == a, p prime +CRYPTOPP_DLL Integer CRYPTOPP_API ModularSquareRoot(const Integer &a, const Integer &p); + +/// \brief Extract a modular root +/// \return a modular root if it exists +/// \details ModularRoot returns x such that a==ModularExponentiation(x, e, p*q), +/// p q primes, and e relatively prime to (p-1)*(q-1), +/// dp=d%(p-1), dq=d%(q-1), (d is inverse of e mod (p-1)*(q-1)) +/// and u=inverse of p mod q. +CRYPTOPP_DLL Integer CRYPTOPP_API ModularRoot(const Integer &a, const Integer &dp, const Integer &dq, const Integer &p, const Integer &q, const Integer &u); + +/// \brief Solve a Modular Quadratic Equation +/// \param r1 the first residue +/// \param r2 the second residue +/// \param a the first coefficient +/// \param b the second coefficient +/// \param c the third constant +/// \param p the prime modulus +/// \return true if solutions exist +/// \details SolveModularQuadraticEquation() finds r1 and r2 such that ax^2 + +/// bx + c == 0 (mod p) for x in {r1, r2}, p prime. +CRYPTOPP_DLL bool CRYPTOPP_API SolveModularQuadraticEquation(Integer &r1, Integer &r2, const Integer &a, const Integer &b, const Integer &c, const Integer &p); + +/// \brief Estimate work factor +/// \param bitlength the size of the number, in bits +/// \return the estimated work factor, in operations +/// \details DiscreteLogWorkFactor returns log base 2 of estimated number of operations to +/// calculate discrete log or factor a number. +CRYPTOPP_DLL unsigned int CRYPTOPP_API DiscreteLogWorkFactor(unsigned int bitlength); + +/// \brief Estimate work factor +/// \param bitlength the size of the number, in bits +/// \return the estimated work factor, in operations +/// \details FactoringWorkFactor returns log base 2 of estimated number of operations to +/// calculate discrete log or factor a number. +CRYPTOPP_DLL unsigned int CRYPTOPP_API FactoringWorkFactor(unsigned int bitlength); + +// ******************************************************** + +/// \brief Generator of prime numbers of special forms +class CRYPTOPP_DLL PrimeAndGenerator +{ +public: + /// \brief Construct a PrimeAndGenerator + PrimeAndGenerator() {} + + /// \brief Construct a PrimeAndGenerator + /// \param delta +1 or -1 + /// \param rng a RandomNumberGenerator derived class + /// \param pbits the number of bits in the prime p + /// \details PrimeAndGenerator() generates a random prime p of the form 2*q+delta, where delta is 1 or -1 and q is + /// also prime. Internally the constructor calls Generate(delta, rng, pbits, pbits-1). + /// \pre pbits > 5 + /// \warning This PrimeAndGenerator() is slow because primes of this form are harder to find. + PrimeAndGenerator(signed int delta, RandomNumberGenerator &rng, unsigned int pbits) + {Generate(delta, rng, pbits, pbits-1);} + + /// \brief Construct a PrimeAndGenerator + /// \param delta +1 or -1 + /// \param rng a RandomNumberGenerator derived class + /// \param pbits the number of bits in the prime p + /// \param qbits the number of bits in the prime q + /// \details PrimeAndGenerator() generates a random prime p of the form 2*r*q+delta, where q is also prime. + /// Internally the constructor calls Generate(delta, rng, pbits, qbits). + /// \pre qbits > 4 && pbits > qbits + PrimeAndGenerator(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned qbits) + {Generate(delta, rng, pbits, qbits);} + + /// \brief Generate a Prime and Generator + /// \param delta +1 or -1 + /// \param rng a RandomNumberGenerator derived class + /// \param pbits the number of bits in the prime p + /// \param qbits the number of bits in the prime q + /// \details Generate() generates a random prime p of the form 2*r*q+delta, where q is also prime. + void Generate(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned qbits); + + /// \brief Retrieve first prime + /// \return Prime() returns the prime p. + const Integer& Prime() const {return p;} + + /// \brief Retrieve second prime + /// \return SubPrime() returns the prime q. + const Integer& SubPrime() const {return q;} + + /// \brief Retrieve the generator + /// \return Generator() returns the generator g. + const Integer& Generator() const {return g;} + +private: + Integer p, q, g; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/nr.h b/third_party/cryptoppwin/include/cryptopp/nr.h new file mode 100644 index 00000000..21558be5 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/nr.h @@ -0,0 +1,11 @@ +// nr.h - originally written and placed in the public domain by Wei Dai + +/// \file nr.h +/// \brief Classes for Nyberg-Rueppel signature scheme + +#ifndef CRYPTOPP_NR_H +#define CRYPTOPP_NR_H + +#include "gfpcrypt.h" + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/oaep.h b/third_party/cryptoppwin/include/cryptopp/oaep.h new file mode 100644 index 00000000..a709e2ab --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/oaep.h @@ -0,0 +1,54 @@ +// oaep.h - originally written and placed in the public domain by Wei Dai + +/// \file oaep.h +/// \brief Classes for optimal asymmetric encryption padding +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_OAEP_H +#define CRYPTOPP_OAEP_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief OAEP padding base class +/// \since Crypto++ 2.1 +class CRYPTOPP_DLL OAEP_Base : public PK_EncryptionMessageEncodingMethod +{ +public: + bool ParameterSupported(const char *name) const {return strcmp(name, Name::EncodingParameters()) == 0;} + size_t MaxUnpaddedLength(size_t paddedLength) const; + void Pad(RandomNumberGenerator &rng, const byte *raw, size_t inputLength, byte *padded, size_t paddedLength, const NameValuePairs ¶meters) const; + DecodingResult Unpad(const byte *padded, size_t paddedLength, byte *raw, const NameValuePairs ¶meters) const; + +protected: + virtual unsigned int DigestSize() const =0; + virtual HashTransformation * NewHash() const =0; + virtual MaskGeneratingFunction * NewMGF() const =0; +}; + +/// \brief OAEP padding +/// \tparam H HashTransformation derived class +/// \tparam MGF MaskGeneratingFunction derived class +/// \sa EME-OAEP, for use with classes derived from TF_ES +/// \since Crypto++ 2.1 +template +class OAEP : public OAEP_Base, public EncryptionStandard +{ +public: + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("OAEP-") + MGF::StaticAlgorithmName() + "(" + H::StaticAlgorithmName() + ")";} + typedef OAEP EncryptionMessageEncodingMethod; + +protected: + unsigned int DigestSize() const {return H::DIGESTSIZE;} + HashTransformation * NewHash() const {return new H;} + MaskGeneratingFunction * NewMGF() const {return new MGF;} +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS OAEP; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/oids.h b/third_party/cryptoppwin/include/cryptopp/oids.h new file mode 100644 index 00000000..936f68b2 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/oids.h @@ -0,0 +1,197 @@ +// oids.h - originally written and placed in the public domain by Wei Dai + +/// \file oids.h +/// \brief ASN.1 object identifiers for algorithms and schemes +/// \details Most OIDs can be found at http://www.oid-info.com/. The Chinese OIDs +/// are assigned in GM/T 0006-2012, Cryptographic Application Identifier Criterion +/// Specification. A reproduction can be found at http://gmssl.org/docs/oid.html. +/// There seems to be some confusion between the text of GmSSL's oid.html web page +/// and the actual OID used in the code. We used the same OIDs that were detailed in +/// http://github.com/guanzhi/GmSSL/blob/master/crypto/objects/objects.txt. + +#ifndef CRYPTOPP_OIDS_H +#define CRYPTOPP_OIDS_H + +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +NAMESPACE_BEGIN(ASN1) + +#define DEFINE_OID(value, name) inline OID name() {return value;} + +DEFINE_OID(1, iso) + DEFINE_OID(iso()+2, member_body) + DEFINE_OID(member_body()+156, iso_cn) + DEFINE_OID(iso_cn()+10197, oscca) + DEFINE_OID(oscca()+1, sm_scheme) + DEFINE_OID(sm_scheme()+104, sms4) + DEFINE_OID(sm_scheme()+301, sm2p256v1) + DEFINE_OID(sm2p256v1()+1, sm2sign) + DEFINE_OID(sm2p256v1()+2, sm2exchange) + DEFINE_OID(sm2p256v1()+3, sm2encrypt) + DEFINE_OID(sm2encrypt()+1, sm2encrypt_recommendedParameters) + DEFINE_OID(sm2encrypt()+2, sm2encrypt_specifiedParameters) + DEFINE_OID(member_body()+840, iso_us) + DEFINE_OID(iso_us()+10040, ansi_x9_57) + DEFINE_OID(ansi_x9_57()+4, ansi_x9cm) + DEFINE_OID(ansi_x9cm()+1, id_dsa) + DEFINE_OID(iso_us()+10045, ansi_x9_62) + DEFINE_OID(ansi_x9_62()+1, id_fieldType) + DEFINE_OID(id_fieldType()+1, prime_field) + DEFINE_OID(id_fieldType()+2, characteristic_two_field) + DEFINE_OID(characteristic_two_field()+3, id_characteristic_two_basis) + DEFINE_OID(id_characteristic_two_basis()+1, gnBasis) + DEFINE_OID(id_characteristic_two_basis()+2, tpBasis) + DEFINE_OID(id_characteristic_two_basis()+3, ppBasis) + DEFINE_OID(ansi_x9_62()+2, id_publicKeyType) + DEFINE_OID(id_publicKeyType()+1, id_ecPublicKey) + DEFINE_OID(ansi_x9_62()+3, ansi_x9_62_curves) + DEFINE_OID(ansi_x9_62_curves()+1, ansi_x9_62_curves_prime) + // ANSI X9.62 + DEFINE_OID(ansi_x9_62_curves_prime()+1, secp192r1) // secp192v1 + //DEFINE_OID(ansi_x9_62_curves_prime()+2, secp192v2) + //DEFINE_OID(ansi_x9_62_curves_prime()+3, secp192v3) + //DEFINE_OID(ansi_x9_62_curves_prime()+4, secp239v1) + //DEFINE_OID(ansi_x9_62_curves_prime()+5, secp239v2) + //DEFINE_OID(ansi_x9_62_curves_prime()+6, secp239v3) + DEFINE_OID(ansi_x9_62_curves_prime()+7, secp256r1) // secp256v1 + DEFINE_OID(ansi_x9_62()+4, ansi_signatures) + DEFINE_OID(ansi_signatures()+3, ecdsa_with_sha2) + DEFINE_OID(ecdsa_with_sha2()+1, ecdsa_with_sha224) + DEFINE_OID(ecdsa_with_sha2()+2, ecdsa_with_sha256) + DEFINE_OID(ecdsa_with_sha2()+3, ecdsa_with_sha384) + DEFINE_OID(ecdsa_with_sha2()+4, ecdsa_with_sha512) + DEFINE_OID(iso_us()+113549, rsadsi) + DEFINE_OID(rsadsi()+1, pkcs) + DEFINE_OID(pkcs()+1, pkcs_1) + // Arc from PKCS #1 and RFC 2459 + DEFINE_OID(pkcs_1()+1, rsaEncryption) + DEFINE_OID(pkcs_1()+2, md2WithRSAEncryption) + DEFINE_OID(pkcs_1()+3, md4withRSAEncryption) + DEFINE_OID(pkcs_1()+4, md5WithRSAEncryption) + DEFINE_OID(pkcs_1()+5, sha1WithRSAEncryption) + DEFINE_OID(pkcs_1()+10, rsassa_pss) + DEFINE_OID(pkcs_1()+11, sha256WithRSAEncryption) + DEFINE_OID(pkcs_1()+12, sha384WithRSAEncryption) + DEFINE_OID(pkcs_1()+13, sha512WithRSAEncryption) + DEFINE_OID(pkcs_1()+14, sha224WithRSAEncryption) + DEFINE_OID(pkcs_1()+15, sha512_224WithRSAEncryption) + DEFINE_OID(pkcs_1()+16, sha512_256WithRSAEncryption) + DEFINE_OID(rsadsi()+2, rsadsi_digestAlgorithm) + DEFINE_OID(rsadsi_digestAlgorithm()+2, id_md2) + DEFINE_OID(rsadsi_digestAlgorithm()+5, id_md5) + DEFINE_OID(iso()+3, identified_organization) + // Arc from http://tools.ietf.org/html/draft-josefsson-pkix-newcurves + // GNU and OpenPGP uses 1.3.6.1.4.1.11591.15.1 for Ed25519. See + // https://www.gnu.org/prep/standards/html_node/OID-Allocations.html, + // https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-rfc4880bis + DEFINE_OID(identified_organization()+6, dod) + DEFINE_OID(dod()+1, internet) + DEFINE_OID(internet()+4, internet_private) + DEFINE_OID(internet_private()+1, enterprise) + DEFINE_OID(enterprise()+11591,gnu) + DEFINE_OID(gnu()+15,ellipticCurve) + DEFINE_OID(ellipticCurve()+1,curve25519) + DEFINE_OID(ellipticCurve()+2,curve448) + DEFINE_OID(ellipticCurve()+3,curve25519ph) + DEFINE_OID(ellipticCurve()+4,curve448ph) + DEFINE_OID(identified_organization()+14, oiw) + DEFINE_OID(oiw()+3, oiw_secsig) + DEFINE_OID(oiw_secsig()+2, oiw_secsig_algorithms) + DEFINE_OID(oiw_secsig_algorithms()+26, id_sha1) + DEFINE_OID(oiw()+7, dssig) + DEFINE_OID(dssig()+2, algorithm) + DEFINE_OID(algorithm()+1, encryptionAlgorithm) + DEFINE_OID(encryptionAlgorithm()+1, elGamal) + DEFINE_OID(identified_organization()+36, teletrust) + DEFINE_OID(teletrust()+3, teletrust_algorithm) + DEFINE_OID(teletrust_algorithm()+2+1, id_ripemd160) + DEFINE_OID(teletrust_algorithm()+3+2+8+1, teletrust_ellipticCurve) + DEFINE_OID(teletrust_ellipticCurve()+1+1, brainpoolP160r1) + DEFINE_OID(teletrust_ellipticCurve()+1+3, brainpoolP192r1) + DEFINE_OID(teletrust_ellipticCurve()+1+5, brainpoolP224r1) + DEFINE_OID(teletrust_ellipticCurve()+1+7, brainpoolP256r1) + DEFINE_OID(teletrust_ellipticCurve()+1+9, brainpoolP320r1) + DEFINE_OID(teletrust_ellipticCurve()+1+11, brainpoolP384r1) + DEFINE_OID(teletrust_ellipticCurve()+1+13, brainpoolP512r1) + // https://tools.ietf.org/html/draft-ietf-curdle-pkix-07 + DEFINE_OID(identified_organization()+101, thawte) + DEFINE_OID(thawte()+110, X25519) + DEFINE_OID(thawte()+111, X448) + DEFINE_OID(thawte()+112, Ed25519) + DEFINE_OID(thawte()+113, Ed448) + DEFINE_OID(identified_organization()+132, certicom) + DEFINE_OID(certicom()+0, certicom_ellipticCurve) + // these are sorted by curve type and then by OID + // first curves based on GF(p) + DEFINE_OID(certicom_ellipticCurve()+6, secp112r1) + DEFINE_OID(certicom_ellipticCurve()+7, secp112r2) + DEFINE_OID(certicom_ellipticCurve()+8, secp160r1) + DEFINE_OID(certicom_ellipticCurve()+9, secp160k1) + DEFINE_OID(certicom_ellipticCurve()+10, secp256k1) + DEFINE_OID(certicom_ellipticCurve()+28, secp128r1) + DEFINE_OID(certicom_ellipticCurve()+29, secp128r2) + DEFINE_OID(certicom_ellipticCurve()+30, secp160r2) + DEFINE_OID(certicom_ellipticCurve()+31, secp192k1) + DEFINE_OID(certicom_ellipticCurve()+32, secp224k1) + DEFINE_OID(certicom_ellipticCurve()+33, secp224r1) + DEFINE_OID(certicom_ellipticCurve()+34, secp384r1) + DEFINE_OID(certicom_ellipticCurve()+35, secp521r1) + // then curves based on GF(2^n) + DEFINE_OID(certicom_ellipticCurve()+1, sect163k1) + DEFINE_OID(certicom_ellipticCurve()+2, sect163r1) + DEFINE_OID(certicom_ellipticCurve()+3, sect239k1) + DEFINE_OID(certicom_ellipticCurve()+4, sect113r1) + DEFINE_OID(certicom_ellipticCurve()+5, sect113r2) + DEFINE_OID(certicom_ellipticCurve()+15, sect163r2) + DEFINE_OID(certicom_ellipticCurve()+16, sect283k1) + DEFINE_OID(certicom_ellipticCurve()+17, sect283r1) + DEFINE_OID(certicom_ellipticCurve()+22, sect131r1) + DEFINE_OID(certicom_ellipticCurve()+23, sect131r2) + DEFINE_OID(certicom_ellipticCurve()+24, sect193r1) + DEFINE_OID(certicom_ellipticCurve()+25, sect193r2) + DEFINE_OID(certicom_ellipticCurve()+26, sect233k1) + DEFINE_OID(certicom_ellipticCurve()+27, sect233r1) + DEFINE_OID(certicom_ellipticCurve()+36, sect409k1) + DEFINE_OID(certicom_ellipticCurve()+37, sect409r1) + DEFINE_OID(certicom_ellipticCurve()+38, sect571k1) + DEFINE_OID(certicom_ellipticCurve()+39, sect571r1) +DEFINE_OID(2, joint_iso_ccitt) + DEFINE_OID(joint_iso_ccitt()+16, country) + DEFINE_OID(country()+840, joint_iso_ccitt_us) + DEFINE_OID(joint_iso_ccitt_us()+1, us_organization) + DEFINE_OID(us_organization()+101, us_gov) + DEFINE_OID(us_gov()+3, csor) + DEFINE_OID(csor()+4, nistalgorithms) + DEFINE_OID(nistalgorithms()+1, aes) + DEFINE_OID(aes()+1, id_aes128_ECB) + DEFINE_OID(aes()+2, id_aes128_cbc) + DEFINE_OID(aes()+3, id_aes128_ofb) + DEFINE_OID(aes()+4, id_aes128_cfb) + DEFINE_OID(aes()+21, id_aes192_ECB) + DEFINE_OID(aes()+22, id_aes192_cbc) + DEFINE_OID(aes()+23, id_aes192_ofb) + DEFINE_OID(aes()+24, id_aes192_cfb) + DEFINE_OID(aes()+41, id_aes256_ECB) + DEFINE_OID(aes()+42, id_aes256_cbc) + DEFINE_OID(aes()+43, id_aes256_ofb) + DEFINE_OID(aes()+44, id_aes256_cfb) + DEFINE_OID(nistalgorithms()+2, nist_hashalgs) + DEFINE_OID(nist_hashalgs()+1, id_sha256) + DEFINE_OID(nist_hashalgs()+2, id_sha384) + DEFINE_OID(nist_hashalgs()+3, id_sha512) + DEFINE_OID(nist_hashalgs()+4, id_sha224) + DEFINE_OID(nist_hashalgs()+7, id_sha3_224) + DEFINE_OID(nist_hashalgs()+8, id_sha3_256) + DEFINE_OID(nist_hashalgs()+9, id_sha3_384) + DEFINE_OID(nist_hashalgs()+10, id_sha3_512) + DEFINE_OID(joint_iso_ccitt_us()+10046, ansi_x942) + DEFINE_OID(ansi_x942()+2, number_type) + DEFINE_OID(number_type()+1, dhpublicnumber) + +NAMESPACE_END + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/osrng.h b/third_party/cryptoppwin/include/cryptopp/osrng.h new file mode 100644 index 00000000..31c32957 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/osrng.h @@ -0,0 +1,304 @@ +// osrng.h - originally written and placed in the public domain by Wei Dai + +/// \file osrng.h +/// \brief Classes for access to the operating system's random number generators + +#ifndef CRYPTOPP_OSRNG_H +#define CRYPTOPP_OSRNG_H + +#include "config.h" + +#if !defined(NO_OS_DEPENDENCE) && defined(OS_RNG_AVAILABLE) + +#include "cryptlib.h" +#include "randpool.h" +#include "smartptr.h" +#include "fips140.h" +#include "hkdf.h" +#include "rng.h" +#include "aes.h" +#include "sha.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when an operating system error is encountered +class CRYPTOPP_DLL OS_RNG_Err : public Exception +{ +public: + /// \brief Constructs an OS_RNG_Err + /// \param operation the operation or API call when the error occurs + OS_RNG_Err(const std::string &operation); +}; + +#ifdef NONBLOCKING_RNG_AVAILABLE + +#ifdef CRYPTOPP_WIN32_AVAILABLE +/// \brief Wrapper for Microsoft crypto service provider +/// \sa \def USE_MS_CRYPTOAPI, \def USE_MS_CNGAPI +class CRYPTOPP_DLL MicrosoftCryptoProvider +{ +public: + /// \brief Construct a MicrosoftCryptoProvider + MicrosoftCryptoProvider(); + ~MicrosoftCryptoProvider(); + +// type HCRYPTPROV and BCRYPT_ALG_HANDLE, avoid #include +#if defined(USE_MS_CRYPTOAPI) +# if defined(__CYGWIN__) && defined(__x86_64__) + typedef unsigned long long ProviderHandle; +# elif defined(WIN64) || defined(_WIN64) + typedef unsigned __int64 ProviderHandle; +# else + typedef unsigned long ProviderHandle; +# endif +#elif defined(USE_MS_CNGAPI) + typedef void *PVOID; + typedef PVOID ProviderHandle; +#endif // USE_MS_CRYPTOAPI or USE_MS_CNGAPI + + /// \brief Retrieves the provider handle + /// \return CryptoAPI provider handle + /// \details If USE_MS_CRYPTOAPI is in effect, then CryptAcquireContext() + /// acquires then handle and CryptReleaseContext() releases the handle + /// upon destruction. If USE_MS_CNGAPI is in effect, then + /// BCryptOpenAlgorithmProvider() acquires then handle and + /// BCryptCloseAlgorithmProvider() releases the handle upon destruction. + ProviderHandle GetProviderHandle() const {return m_hProvider;} + +private: + ProviderHandle m_hProvider; +}; + +#if defined(CRYPTOPP_MSC_VERSION) && defined(USE_MS_CRYPTOAPI) +# pragma comment(lib, "advapi32.lib") +#endif + +#if defined(CRYPTOPP_MSC_VERSION) && defined(USE_MS_CNGAPI) +# pragma comment(lib, "bcrypt.lib") +#endif + +#endif // CRYPTOPP_WIN32_AVAILABLE + +/// \brief Wrapper class for /dev/random and /dev/srandom +/// \details Encapsulates CryptoAPI's CryptGenRandom() or CryptoNG's BCryptGenRandom() +/// on Windows, or /dev/urandom on Unix and compatibles. +class CRYPTOPP_DLL NonblockingRng : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "NonblockingRng"; } + + ~NonblockingRng(); + + /// \brief Construct a NonblockingRng + NonblockingRng(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \details GenerateIntoBufferedTransformation() calls are routed to GenerateBlock(). + void GenerateBlock(byte *output, size_t size); + +protected: +#ifdef CRYPTOPP_WIN32_AVAILABLE + MicrosoftCryptoProvider m_Provider; +#else + int m_fd; +#endif +}; + +#endif + +#if defined(BLOCKING_RNG_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Wrapper class for /dev/random and /dev/srandom +/// \details Encapsulates /dev/random on Linux, OS X and Unix; and /dev/srandom on the BSDs. +/// \note On Linux the /dev/random interface is effectively deprecated. According to the +/// Kernel Crypto developers, /dev/urandom or getrandom(2) should be used instead. Also +/// see [RFC PATCH v12 3/4] Linux Random +/// Number Generator on the kernel-crypto mailing list. +class CRYPTOPP_DLL BlockingRng : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "BlockingRng"; } + + ~BlockingRng(); + + /// \brief Construct a BlockingRng + BlockingRng(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \details GenerateIntoBufferedTransformation() calls are routed to GenerateBlock(). + void GenerateBlock(byte *output, size_t size); + +protected: + int m_fd; +}; + +#endif + +/// OS_GenerateRandomBlock +/// \brief Generate random array of bytes +/// \param blocking specifies whether a blocking or non-blocking generator should be used +/// \param output the byte buffer +/// \param size the length of the buffer, in bytes +/// \details OS_GenerateRandomBlock() uses the underlying operating system's +/// random number generator. On Windows, CryptGenRandom() is called using NonblockingRng. +/// \details On Unix and compatibles, /dev/urandom is called if blocking is false using +/// NonblockingRng. If blocking is true, then either /dev/randomd or /dev/srandom is used +/// by way of BlockingRng, if available. +CRYPTOPP_DLL void CRYPTOPP_API OS_GenerateRandomBlock(bool blocking, byte *output, size_t size); + +/// \brief Automatically Seeded Randomness Pool +/// \details This class seeds itself using an operating system provided RNG. +/// AutoSeededRandomPool was suggested by Leonard Janke. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +class CRYPTOPP_DLL AutoSeededRandomPool : public RandomPool +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "AutoSeededRandomPool"; } + + ~AutoSeededRandomPool() {} + + /// \brief Construct an AutoSeededRandomPool + /// \param blocking controls seeding with BlockingRng or NonblockingRng + /// \param seedSize the size of the seed, in bytes + /// \details Use blocking to choose seeding with BlockingRng or NonblockingRng. + /// The parameter is ignored if only one of these is available. + explicit AutoSeededRandomPool(bool blocking = false, unsigned int seedSize = 32) + {Reseed(blocking, seedSize);} + + /// \brief Reseed an AutoSeededRandomPool + /// \param blocking controls seeding with BlockingRng or NonblockingRng + /// \param seedSize the size of the seed, in bytes + void Reseed(bool blocking = false, unsigned int seedSize = 32); +}; + +/// \tparam BLOCK_CIPHER a block cipher +/// \brief Automatically Seeded X9.17 RNG +/// \details AutoSeededX917RNG is from ANSI X9.17 Appendix C, seeded using an OS provided RNG. +/// If 3-key TripleDES (DES_EDE3) is used, then its a X9.17 conforming generator. If AES is +/// used, then its a X9.31 conforming generator. +/// \details Though ANSI X9 prescribes 3-key TripleDES, the template parameter BLOCK_CIPHER +/// can be any BlockTransformation derived class. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa X917RNG, DefaultAutoSeededRNG +template +class AutoSeededX917RNG : public RandomNumberGenerator, public NotCopyable +{ +public: + static std::string StaticAlgorithmName() { + return std::string("AutoSeededX917RNG(") + BLOCK_CIPHER::StaticAlgorithmName() + std::string(")"); + } + + ~AutoSeededX917RNG() {} + + /// \brief Construct an AutoSeededX917RNG + /// \param blocking controls seeding with BlockingRng or NonblockingRng + /// \param autoSeed controls auto seeding of the generator + /// \details Use blocking to choose seeding with BlockingRng or NonblockingRng. + /// The parameter is ignored if only one of these is available. + /// \sa X917RNG + explicit AutoSeededX917RNG(bool blocking = false, bool autoSeed = true) + {if (autoSeed) Reseed(blocking);} + + /// \brief Reseed an AutoSeededX917RNG + /// \param blocking controls seeding with BlockingRng or NonblockingRng + /// \param input additional entropy to add to the generator + /// \param length the size of the additional entropy, in bytes + /// \details Internally, the generator uses SHA256 to extract the entropy from + /// from the seed and then stretch the material for the block cipher's key + /// and initialization vector. + void Reseed(bool blocking = false, const byte *input = NULLPTR, size_t length = 0); + + /// \brief Deterministically reseed an AutoSeededX917RNG for testing + /// \param key the key to use for the deterministic reseeding + /// \param keylength the size of the key, in bytes + /// \param seed the seed to use for the deterministic reseeding + /// \param timeVector a time vector to use for deterministic reseeding + /// \details This is a testing interface for testing purposes, and should \a NOT + /// be used in production. + void Reseed(const byte *key, size_t keylength, const byte *seed, const byte *timeVector); + + bool CanIncorporateEntropy() const {return true;} + void IncorporateEntropy(const byte *input, size_t length) {Reseed(false, input, length);} + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword length) + {m_rng->GenerateIntoBufferedTransformation(target, channel, length);} + + std::string AlgorithmProvider() const; + +private: + member_ptr m_rng; +}; + +template +void AutoSeededX917RNG::Reseed(const byte *key, size_t keylength, const byte *seed, const byte *timeVector) +{ + m_rng.reset(new X917RNG(new typename BLOCK_CIPHER::Encryption(key, keylength), seed, timeVector)); +} + +template +void AutoSeededX917RNG::Reseed(bool blocking, const byte *input, size_t length) +{ + enum {BlockSize=BLOCK_CIPHER::BLOCKSIZE}; + enum {KeyLength=BLOCK_CIPHER::DEFAULT_KEYLENGTH}; + enum {SeedSize=EnumToInt(BlockSize)+EnumToInt(KeyLength)}; + + SecByteBlock seed(SeedSize), temp(SeedSize); + const byte label[] = "X9.17 key generation"; + const byte *key=NULLPTR; + + do + { + OS_GenerateRandomBlock(blocking, temp, temp.size()); + + HKDF hkdf; + hkdf.DeriveKey( + seed, seed.size(), // derived secret + temp, temp.size(), // instance secret + input, length, // user secret + label, 20 // unique label + ); + + key = seed + BlockSize; + } // check that seed and key don't have same value + while (std::memcmp(key, seed, STDMIN((size_t)BlockSize, (size_t)KeyLength)) == 0); + + Reseed(key, KeyLength, seed, NULLPTR); +} + +template +std::string AutoSeededX917RNG::AlgorithmProvider() const +{ + // Hack for now... We need to instantiate one + typename BLOCK_CIPHER::Encryption bc; + return bc.AlgorithmProvider(); +} + +CRYPTOPP_DLL_TEMPLATE_CLASS AutoSeededX917RNG; + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief A typedef providing a default generator +/// \details DefaultAutoSeededRNG is a typedef of either AutoSeededX917RNG or AutoSeededRandomPool. +/// If CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 is defined, then DefaultAutoSeededRNG is +/// AutoSeededX917RNG. Otherwise, DefaultAutoSeededRNG is AutoSeededRandomPool. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +class DefaultAutoSeededRNG {} +#else +// AutoSeededX917RNG in FIPS mode, otherwise it's AutoSeededRandomPool +#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 +typedef AutoSeededX917RNG DefaultAutoSeededRNG; +#else +typedef AutoSeededRandomPool DefaultAutoSeededRNG; +#endif +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_END + +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/ossig.h b/third_party/cryptoppwin/include/cryptopp/ossig.h new file mode 100644 index 00000000..ce23b73d --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/ossig.h @@ -0,0 +1,128 @@ +// ossig.h - written and placed in the public domain by Jeffrey Walton +// +/// \file ossig.h +/// \brief Utility class for trapping OS signals. +/// \since Crypto++ 5.6.5 + +#ifndef CRYPTOPP_OS_SIGNAL_H +#define CRYPTOPP_OS_SIGNAL_H + +#include "config.h" + +#if defined(UNIX_SIGNALS_AVAILABLE) +# include +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// ************** Unix and Linux compatibles *************** + +#if defined(UNIX_SIGNALS_AVAILABLE) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Signal handler function pointer +/// \details SignalHandlerFn is provided as a stand alone function pointer with external "C" linkage +/// \sa SignalHandler, NullSignalHandler +extern "C" { + typedef void (*SignalHandlerFn) (int); +} + +/// \brief Null signal handler function +/// \param unused the signal number +/// \details NullSignalHandler is provided as a stand alone function with external "C" linkage +/// and not a static member function due to the member function's implicit +/// external "C++" linkage. +/// \sa SignalHandler, SignalHandlerFn +extern "C" { + inline void NullSignalHandler(int unused) {CRYPTOPP_UNUSED(unused);} +} + +/// Signal handler for Linux and Unix compatibles +/// \tparam S Signal number +/// \tparam O Flag indicating if an existing handler should be overwritten +/// \details SignalHandler() can be used to install a signal handler with the signature +/// void handler_fn(int). If SignalHandlerFn is not NULL, then +/// the sigaction is set to the function and the sigaction flags is set to the flags. +/// If SignalHandlerFn is NULL, then a default handler is installed +/// using sigaction flags set to 0. The default handler only returns from the call. +/// \details Upon destruction the previous signal handler is restored if the former signal handler +/// was replaced. +/// \details On Cygwin systems using Newlib, you should define _XOPEN_SOURCE=700 or +/// _GNU_SOURCE; or use -std=gnu++03, -std=gnu++11, or similar. If +/// you compile with -std=c++03, -std=c++11 or similar, then define +/// _XOPEN_SOURCE=700. +/// \warning Do not use SignalHandler in a code block that uses setjmp or longjmp +/// because the destructor may not run. +/// \since Crypto++ 5.6.5 +/// \sa NullSignalHandler, SignalHandlerFn, \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT", DebugTrapHandler +template +struct SignalHandler +{ + /// \brief Construct a signal handler + /// \param pfn Pointer to a signal handler function + /// \param flags Flags to use with the signal handler + /// \details SignalHandler() installs a signal handler with the signature + /// void handler_fn(int). If SignalHandlerFn is not NULL, then + /// the sigaction is set to the function and the sigaction flags is set to the flags. + /// If SignalHandlerFn is NULL, then a default handler is installed + /// using sigaction flags set to 0. The default handler only returns from the call. + /// \details Upon destruction the previous signal handler is restored if the former signal handler + /// was overwritten. + /// \details On Cygwin systems using Newlib, you should define _XOPEN_SOURCE=700 or + /// _GNU_SOURCE; or use -std=gnu++03, -std=gnu++11, or similar. If + /// you compile with -std=c++03, -std=c++11 or similar, then define + /// _XOPEN_SOURCE=700. + /// \warning Do not use SignalHandler in a code block that uses setjmp or longjmp + /// because the destructor may not run. setjmp is why cpu.cpp does not use SignalHandler + /// during CPU feature testing. + /// \since Crypto++ 5.6.5 + SignalHandler(SignalHandlerFn pfn = NULLPTR, int flags = 0) : m_installed(false) + { + // http://pubs.opengroup.org/onlinepubs/007908799/xsh/sigaction.html + struct sigaction new_handler; + + do + { + int ret = 0; + + ret = sigaction (S, 0, &m_old); + if (ret != 0) break; // Failed + + // Don't step on another's handler if Overwrite=false + if (m_old.sa_handler != 0 && !O) break; + + // Cygwin/Newlib requires -D_XOPEN_SOURCE=700 + ret = sigemptyset (&new_handler.sa_mask); + if (ret != 0) break; // Failed + + new_handler.sa_handler = (pfn ? pfn : &NullSignalHandler); + new_handler.sa_flags = (pfn ? flags : 0); + + // Install it + ret = sigaction (S, &new_handler, 0); + if (ret != 0) break; // Failed + + m_installed = true; + + } while(0); + } + + ~SignalHandler() + { + if (m_installed) + sigaction (S, &m_old, 0); + } + +private: + struct sigaction m_old; + bool m_installed; + +private: + // Not copyable + SignalHandler(const SignalHandler &); + void operator=(const SignalHandler &); +}; +#endif + +NAMESPACE_END + +#endif // CRYPTOPP_OS_SIGNAL_H diff --git a/third_party/cryptoppwin/include/cryptopp/padlkrng.h b/third_party/cryptoppwin/include/cryptopp/padlkrng.h new file mode 100644 index 00000000..7c6b0b33 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/padlkrng.h @@ -0,0 +1,138 @@ +// via-rng.h - written and placed in public domain by Jeffrey Walton + +/// \file padlkrng.h +/// \brief Classes for VIA Padlock RNG +/// \since Crypto++ 6.0 +/// \sa VIA +/// Padlock on the Crypto++ wiki + +#ifndef CRYPTOPP_PADLOCK_RNG_H +#define CRYPTOPP_PADLOCK_RNG_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when a PadlockRNG generator encounters +/// a generator related error. +/// \since Crypto++ 6.0 +class PadlockRNG_Err : public Exception +{ +public: + PadlockRNG_Err(const std::string &operation) + : Exception(OTHER_ERROR, "PadlockRNG: " + operation + " operation failed") {} + PadlockRNG_Err(const std::string &component, const std::string &message) + : Exception(OTHER_ERROR, component + ": " + message) {} +}; + +/// \brief Hardware generated random numbers using VIA XSTORE +/// \details Some VIA processors provide a Security Engine called Padlock. The Padlock +/// Security Engine provides AES, SHA and a RNG. The PadlockRNG class provides access +/// to the RNG. +/// \details The VIA generator uses an 8 byte FIFO buffer for random numbers. The +/// generator can be configured to discard bits from the buffer to resist analysis. +/// The divisor controls the number of bytes discarded. The formula for +/// the discard amount is 2**divisor - 1. When divisor=0 no bits +/// are discarded and the entire 8 byte buffer is read. If divisor=3 then +/// 7 bytes are discarded and 1 byte is read. TheVIA SDK samples use divisor=1. +/// \details Cryptography Research, Inc (CRI) audited the Padlock Security Engine +/// in 2003. CRI provided recommendations to operate the generator for secure and +/// non-secure applications. Additionally, the Programmers Guide and SDK provided a +/// different configuration in the sample code. +/// \details You can operate the generator according to CRI recommendations by setting +/// divisor, reading one word (or partial word) at a time from the FIFO, and +/// then inspecting the MSR after each read. +/// \details The audit report with recommendations is available on the Crypto++ wiki +/// at VIA Padlock. +/// \sa MaurerRandomnessTest() for random bit generators +/// \since Crypto++ 6.0 +class PadlockRNG : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "PadlockRNG"; } + + virtual ~PadlockRNG() {} + + /// \brief Construct a PadlockRNG generator + /// \param divisor the XSTORE divisor + /// \details Some VIA processors provide a Security Engine called Padlock. The Padlock + /// Security Engine provides AES, SHA and a RNG. The PadlockRNG class provides access + /// to the RNG. + /// \details The VIA generator uses an 8 byte FIFO buffer for random numbers. The + /// generator can be configured to discard bits from the buffer to resist analysis. + /// The divisor controls the number of bytes discarded. The formula for + /// the discard amount is 2**divisor - 1. When divisor=0 no bits + /// are discarded and the entire 8 byte buffer is read. If divisor=3 then + /// 7 bytes are discarded and 1 byte is read. VIA SDK samples use divisor=1. + /// \details Cryptography Research, Inc (CRI) audited the Padlock Security Engine + /// in 2003. CRI provided recommendations to operate the generator for secure and + /// non-secure applications. Additionally, the Programmers SDK provided a different + /// configuration in the sample code. + /// \details The audit report with recommendations is available on the Crypto++ wiki + /// at VIA Padlock. + /// \sa SetDivisor, GetDivisor + PadlockRNG(word32 divisor=1); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + /// \details the Padlock generator discards words, not bytes. If n is + /// not a multiple of a 32-bit word, then it is rounded up to + /// that size. + virtual void DiscardBytes(size_t n); + + /// \brief Update RNG state with additional unpredictable values + /// \param input unused + /// \param length unused + /// \details The operation is a nop for this generator. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + // Override to avoid the base class' throw. + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + } + + std::string AlgorithmProvider() const; + + /// \brief Set the XSTORE divisor + /// \param divisor the XSTORE divisor + /// \return the old XSTORE divisor + word32 SetDivisor(word32 divisor) + { + word32 old = m_divisor; + m_divisor = DivisorHelper(divisor); + return old; + } + + /// \brief Get the XSTORE divisor + /// \return the current XSTORE divisor + word32 GetDivisor() const + { + return m_divisor; + } + + /// \brief Get the MSR for the last operation + /// \return the MSR for the last read operation + word32 GetMSR() const + { + return m_msr; + } + +protected: + inline word32 DivisorHelper(word32 divisor) + { + return divisor > 3 ? 3 : divisor; + } + +private: + FixedSizeAlignedSecBlock m_buffer; + word32 m_divisor, m_msr; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_PADLOCK_RNG_H diff --git a/third_party/cryptoppwin/include/cryptopp/panama.h b/third_party/cryptoppwin/include/cryptopp/panama.h new file mode 100644 index 00000000..9c10f82c --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/panama.h @@ -0,0 +1,169 @@ +// panama.h - originally written and placed in the public domain by Wei Dai + +/// \file panama.h +/// \brief Classes for Panama hash and stream cipher + +#ifndef CRYPTOPP_PANAMA_H +#define CRYPTOPP_PANAMA_H + +#include "strciphr.h" +#include "iterhash.h" +#include "secblock.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler error with .intel_syntax +//#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +//# define CRYPTOPP_DISABLE_PANAMA_ASM +//#endif + +// https://github.com/weidai11/cryptopp/issues/758 +#define CRYPTOPP_DISABLE_PANAMA_ASM 1 + +NAMESPACE_BEGIN(CryptoPP) + +// Base class, do not use directly +template +class CRYPTOPP_NO_VTABLE Panama +{ +public: + virtual ~Panama() {} + std::string AlgorithmProvider() const; + void Reset(); + void Iterate(size_t count, const word32 *p=NULLPTR, byte *output=NULLPTR, const byte *input=NULLPTR, KeystreamOperation operation=WRITE_KEYSTREAM); + +protected: + typedef word32 Stage[8]; + CRYPTOPP_CONSTANT(STAGES = 32); + + FixedSizeAlignedSecBlock m_state; +}; + +namespace Weak { +/// \brief Panama hash +/// \sa Panama Hash +template +class PanamaHash : protected Panama, public AlgorithmImpl, PanamaHash > +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = 32); + virtual ~PanamaHash() {} + PanamaHash() {Panama::Reset();} + unsigned int DigestSize() const {return DIGESTSIZE;} + void TruncatedFinal(byte *hash, size_t size); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return B::ToEnum() == BIG_ENDIAN_ORDER ? "Panama-BE" : "Panama-LE";} + std::string AlgorithmProvider() const {return Panama::AlgorithmProvider();} // Fix https://github.com/weidai11/cryptopp/issues/801 + +protected: + void Init() {Panama::Reset();} + void HashEndianCorrectedBlock(const word32 *data) {this->Iterate(1, data);} // push + size_t HashMultipleBlocks(const word32 *input, size_t length); + word32* StateBuf() {return NULLPTR;} + + FixedSizeSecBlock m_buf; +}; +} + +/// \brief MAC construction using a hermetic hash function +template +class HermeticHashFunctionMAC : public AlgorithmImpl > >, T_Info> +{ +public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) + { + CRYPTOPP_UNUSED(params); + + m_key.Assign(key, length); + Restart(); + } + + void Restart() + { + m_hash.Restart(); + m_keyed = false; + } + + void Update(const byte *input, size_t length) + { + if (!m_keyed) + KeyHash(); + m_hash.Update(input, length); + } + + void TruncatedFinal(byte *digest, size_t digestSize) + { + if (!m_keyed) + KeyHash(); + m_hash.TruncatedFinal(digest, digestSize); + m_keyed = false; + } + + unsigned int DigestSize() const + {return m_hash.DigestSize();} + unsigned int BlockSize() const + {return m_hash.BlockSize();} + unsigned int OptimalBlockSize() const + {return m_hash.OptimalBlockSize();} + unsigned int OptimalDataAlignment() const + {return m_hash.OptimalDataAlignment();} + +protected: + void KeyHash() + { + m_hash.Update(m_key, m_key.size()); + m_keyed = true; + } + + T_Hash m_hash; + bool m_keyed; + SecByteBlock m_key; +}; + +namespace Weak { +/// \brief Panama message authentication code +template +class PanamaMAC : public HermeticHashFunctionMAC > +{ +public: + PanamaMAC() {} + PanamaMAC(const byte *key, unsigned int length) + {this->SetKey(key, length);} +}; +} + +/// \brief Panama stream cipher information +template +struct PanamaCipherInfo : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return B::ToEnum() == BIG_ENDIAN_ORDER ? "Panama-BE" : "Panama-LE";} +}; + +/// \brief Panama stream cipher operation +template +class PanamaCipherPolicy : public AdditiveCipherConcretePolicy, + public PanamaCipherInfo, + protected Panama +{ +protected: + virtual ~PanamaCipherPolicy() {} + std::string AlgorithmProvider() const; + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + bool CipherIsRandomAccess() const {return false;} + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + unsigned int GetAlignment() const; + + FixedSizeSecBlock m_key; + FixedSizeSecBlock m_buf; +}; + +/// \brief Panama stream cipher +/// \sa Panama Stream Cipher +template +struct PanamaCipher : public PanamaCipherInfo, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal, AdditiveCipherTemplate<> >, PanamaCipherInfo > Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/pch.h b/third_party/cryptoppwin/include/cryptopp/pch.h new file mode 100644 index 00000000..2cd163ea --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/pch.h @@ -0,0 +1,31 @@ +// pch.h - originally written and placed in the public domain by Wei Dai + +/// \file pch.h +/// \brief Precompiled header file +/// \details The precompiled header files are used Windows. + +#ifndef CRYPTOPP_PCH_H +#define CRYPTOPP_PCH_H + +# ifdef CRYPTOPP_GENERATE_X64_MASM + #include "cpu.h" + +# else + #include "config.h" + + #ifdef USE_PRECOMPILED_HEADERS + #include "simple.h" + #include "secblock.h" + #include "misc.h" + #include "smartptr.h" + #include "stdcpp.h" + #endif +# endif + +// Enable file and line numbers, if available. +// #if defined(_MSC_VER) && defined(_DEBUG) && defined(USE_PRECOMPILED_HEADERS) +// # define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +// # define new DEBUG_NEW +// #endif + +#endif // CRYPTOPP_PCH_H diff --git a/third_party/cryptoppwin/include/cryptopp/pkcspad.h b/third_party/cryptoppwin/include/cryptopp/pkcspad.h new file mode 100644 index 00000000..f112c521 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/pkcspad.h @@ -0,0 +1,123 @@ +// pkcspad.h - originally written and placed in the public domain by Wei Dai + +/// \file pkcspad.h +/// \brief Classes for PKCS padding schemes +/// \details PKCS #1 v1.5, v2.0 and P1363a allow MD2, MD5, SHA1, SHA224, SHA256, SHA384, +/// SHA512, Tiger and RipeMd-160 to be instantiated. + +#ifndef CRYPTOPP_PKCSPAD_H +#define CRYPTOPP_PKCSPAD_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "hashfwd.h" + +#ifdef CRYPTOPP_IS_DLL +#include "sha.h" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief PKCS #1 v1.5 Encryption Padding Scheme +/// \sa EME-PKCS1-v1_5 +class PKCS_EncryptionPaddingScheme : public PK_EncryptionMessageEncodingMethod +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "EME-PKCS1-v1_5";} + + size_t MaxUnpaddedLength(size_t paddedLength) const; + void Pad(RandomNumberGenerator &rng, const byte *raw, size_t inputLength, byte *padded, size_t paddedLength, const NameValuePairs ¶meters) const; + DecodingResult Unpad(const byte *padded, size_t paddedLength, byte *raw, const NameValuePairs ¶meters) const; +}; + +/// \brief PKCS #1 decoration data structure +template class PKCS_DigestDecoration +{ +public: + static const byte decoration[]; + static const unsigned int length; +}; + +// PKCS_DigestDecoration can be instantiated with the following +// classes as specified in PKCS #1 v2.0 and P1363a +// SHA1, SHA224, SHA256, SHA384, SHA512, Tiger, RIPEMD160, MD2, MD5 + +#if defined(CRYPTOPP_IS_DLL) +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +// http://github.com/weidai11/cryptopp/issues/517 +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +CRYPTOPP_DLL_TEMPLATE_CLASS PKCS_DigestDecoration; +#endif + +// https://github.com/weidai11/cryptopp/issues/300 and +// https://github.com/weidai11/cryptopp/issues/533 +#if defined(__clang__) +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; + +// http://github.com/weidai11/cryptopp/issues/517 +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; + +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +template<> const byte PKCS_DigestDecoration::decoration[]; +template<> const unsigned int PKCS_DigestDecoration::length; +#endif + +/// \brief PKCS #1 v1.5 Signature Encoding Scheme +/// \sa EMSA-PKCS1-v1_5 +class CRYPTOPP_DLL PKCS1v15_SignatureMessageEncodingMethod : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "EMSA-PKCS1-v1_5";} + + size_t MinRepresentativeBitLength(size_t hashIdentifierSize, size_t digestSize) const + {return 8 * (digestSize + hashIdentifierSize + 10);} + + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; + + struct HashIdentifierLookup + { + template struct HashIdentifierLookup2 + { + static HashIdentifier Lookup() + { + return HashIdentifier(PKCS_DigestDecoration::decoration, PKCS_DigestDecoration::length); + } + }; + }; +}; + +/// \brief PKCS #1 version 1.5, for use with RSAES and RSASS +/// \dontinclude pkcspad.h + +struct PKCS1v15 : public SignatureStandard, public EncryptionStandard +{ + typedef PKCS_EncryptionPaddingScheme EncryptionMessageEncodingMethod; + typedef PKCS1v15_SignatureMessageEncodingMethod SignatureMessageEncodingMethod; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/poly1305.h b/third_party/cryptoppwin/include/cryptopp/poly1305.h new file mode 100644 index 00000000..19e712bd --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/poly1305.h @@ -0,0 +1,241 @@ +// poly1305.h - written and placed in the public domain by Jeffrey Walton and Jean-Pierre Munch +// Based on Andy Polyakov's Base-2^26 scalar multiplication implementation. +// For more information, see https://www.openssl.org/~appro/cryptogams/. + +// The library added Bernstein's Poly1305 classes at Crypto++ 6.0. The IETF +// uses a slightly different implementation than Bernstein, and the IETF +// classes were added at Crypto++ 8.1. We wanted to maintain ABI compatibility +// at the 8.1 release so the original Poly1305 classes were not disturbed. +// Instead new classes were added for IETF Poly1305. The back-end implementation +// shares code as expected, however. + +/// \file poly1305.h +/// \brief Classes for Poly1305 message authentication code +/// \details Poly1305-AES is a state-of-the-art message-authentication code suitable for a wide +/// variety of applications. Poly1305-AES computes a 16-byte authenticator of a variable-length +/// message, using a 16-byte AES key, a 16-byte additional key, and a 16-byte nonce. +/// \details Crypto++ also supplies the IETF's version of Poly1305. It is a slightly different +/// algorithm than Bernstein's version. +/// \sa Daniel J. Bernstein The Poly1305-AES +/// Message-Authentication Code (20050329), RFC +/// 8439, ChaCha20 and Poly1305 for IETF Protocols and Andy Polyakov Poly1305 Revised +/// \since Poly1305 since Crypto++ 6.0, Poly1305TLS since Crypto++ 8.1 + +#ifndef CRYPTOPP_POLY1305_H +#define CRYPTOPP_POLY1305_H + +#include "cryptlib.h" +#include "seckey.h" +#include "secblock.h" +#include "argnames.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +////////////////////////////// Bernstein Poly1305 ////////////////////////////// + +/// \brief Poly1305 message authentication code base class +/// \tparam T BlockCipherDocumentation derived class with 16-byte key and 16-byte blocksize +/// \details Poly1305_Base is the base class of Bernstein's Poly1305 algorithm. +/// \since Crypto++ 6.0 +template +class CRYPTOPP_NO_VTABLE Poly1305_Base : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 16>, public MessageAuthenticationCode +{ + CRYPTOPP_COMPILE_ASSERT(T::DEFAULT_KEYLENGTH == 16); + CRYPTOPP_COMPILE_ASSERT(T::BLOCKSIZE == 16); + +public: + static std::string StaticAlgorithmName() {return std::string("Poly1305(") + T::StaticAlgorithmName() + ")";} + + CRYPTOPP_CONSTANT(DIGESTSIZE=T::BLOCKSIZE); + CRYPTOPP_CONSTANT(BLOCKSIZE=T::BLOCKSIZE); + + virtual ~Poly1305_Base() {} + Poly1305_Base() : m_idx(0), m_used(true) {} + + void Resynchronize (const byte *iv, int ivLength=-1); + void GetNextIV (RandomNumberGenerator &rng, byte *iv); + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + void Restart(); + + unsigned int BlockSize() const {return BLOCKSIZE;} + unsigned int DigestSize() const {return DIGESTSIZE;} + + std::string AlgorithmProvider() const; + +protected: + // TODO: No longer needed. Remove at next major version bump + void HashBlocks(const byte *input, size_t length, word32 padbit); + void HashFinal(byte *mac, size_t length); + + typename T::Encryption m_cipher; + + // Accumulated hash, clamped r-key, and encrypted nonce + FixedSizeAlignedSecBlock m_h; + FixedSizeAlignedSecBlock m_r; + FixedSizeAlignedSecBlock m_n; + + // Accumulated message bytes and index + FixedSizeAlignedSecBlock m_acc, m_nk; + size_t m_idx; + + // Track nonce reuse; assert in debug but continue + bool m_used; +}; + +/// \brief Poly1305 message authentication code +/// \tparam T class derived from BlockCipherDocumentation with 16-byte key and 16-byte blocksize +/// \details Poly1305-AES is a state-of-the-art message-authentication code suitable for a wide +/// variety of applications. Poly1305-AES computes a 16-byte authenticator of a variable-length +/// message, using a 16-byte AES key, a 16-byte additional key, and a 16-byte nonce. +/// \details The key is 32 bytes and a concatenation key = {k,s}, where +/// k is the AES key and r is additional key that gets clamped. +/// The key is clamped internally so there is no need to perform the operation +/// before setting the key. +/// \details Each message must have a unique security context, which means either the key or nonce +/// must be changed after each message. It can be accomplished in one of two ways. First, you +/// can create a new Poly1305 object each time its needed. +///
  SecByteBlock key(32), nonce(16);
+///   prng.GenerateBlock(key, key.size());
+///   prng.GenerateBlock(nonce, nonce.size());
+///
+///   Poly1305 poly1305(key, key.size(), nonce, nonce.size());
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+/// +/// \details Second, you can create a Poly1305 object, reuse the key, and set a fresh nonce +/// for each message. The second and subsequent nonces can be generated using GetNextIV(). +///
  SecByteBlock key(32), nonce(16);
+///   prng.GenerateBlock(key, key.size());
+///   prng.GenerateBlock(nonce, nonce.size());
+///
+///   // First message
+///   Poly1305 poly1305(key, key.size());
+///   poly1305.Resynchronize(nonce);
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+///
+///   // Second message
+///   poly1305.GetNextIV(prng, nonce);
+///   poly1305.Resynchronize(nonce);
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+///   ...
+/// \warning Each message must have a unique security context. The Poly1305 class does not +/// enforce a fresh key or nonce for each message. The source code will assert in debug +/// builds to alert of nonce reuse. No action is taken in release builds. +/// \sa Daniel J. Bernstein The Poly1305-AES +/// Message-Authentication Code (20050329) and Andy Polyakov Poly1305 Revised +/// \since Crypto++ 6.0 +template +class Poly1305 : public MessageAuthenticationCodeFinal > +{ +public: + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH=Poly1305_Base::DEFAULT_KEYLENGTH); + + /// \brief Construct a Poly1305 + Poly1305() {} + + /// \brief Construct a Poly1305 + /// \param key a byte array used to key the cipher + /// \param keyLength the size of the byte array, in bytes + /// \param nonce a byte array used to key the cipher + /// \param nonceLength the size of the byte array, in bytes + /// \details The key is 32 bytes and a concatenation key = {k,s}, where + /// k is the AES key and r is additional key that gets clamped. + /// The key is clamped internally so there is no need to perform the operation + /// before setting the key. + /// \details Each message requires a unique security context. You can use GetNextIV() + /// and Resynchronize() to set a new nonce under a key for a message. + Poly1305(const byte *key, size_t keyLength=DEFAULT_KEYLENGTH, const byte *nonce=NULLPTR, size_t nonceLength=0) + {this->SetKey(key, keyLength, MakeParameters(Name::IV(), ConstByteArrayParameter(nonce, nonceLength)));} +}; + +////////////////////////////// IETF Poly1305 ////////////////////////////// + +/// \brief Poly1305-TLS message authentication code base class +/// \details Poly1305TLS_Base is the base class of the IETF's Poly1305 algorithm. +/// \since Crypto++ 8.1 +class Poly1305TLS_Base : public FixedKeyLength<32>, public MessageAuthenticationCode +{ +public: + static std::string StaticAlgorithmName() {return std::string("Poly1305TLS");} + CRYPTOPP_CONSTANT(DIGESTSIZE=16); + CRYPTOPP_CONSTANT(BLOCKSIZE=16); + + virtual ~Poly1305TLS_Base() {} + Poly1305TLS_Base() {} + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void Update(const byte *input, size_t length); + void TruncatedFinal(byte *mac, size_t size); + void Restart(); + + unsigned int BlockSize() const {return BLOCKSIZE;} + unsigned int DigestSize() const {return DIGESTSIZE;} + +protected: + // Accumulated hash, clamped r-key, and encrypted nonce + FixedSizeAlignedSecBlock m_h; + FixedSizeAlignedSecBlock m_r; + FixedSizeAlignedSecBlock m_n; + + // Accumulated message bytes and index + FixedSizeAlignedSecBlock m_acc; + size_t m_idx; +}; + +/// \brief Poly1305-TLS message authentication code +/// \details This is the IETF's variant of Bernstein's Poly1305 from RFC 8439. +/// IETF Poly1305 is called Poly1305TLS in the Crypto++ library. It is +/// _slightly_ different from the Bernstein implementation. Poly1305-TLS +/// can be used for cipher suites +/// TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +/// TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, and +/// TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. +/// \details The key is 32 bytes and a concatenation key = {r,s}, where +/// r is additional key that gets clamped and s is the nonce. +/// The key is clamped internally so there is no need to perform the operation +/// before setting the key. +/// \details Each message must have a unique security context, which means the key +/// must be changed after each message. It can be accomplished in one of two ways. +/// First, you can create a new Poly1305 object with a new key each time its needed. +///
  SecByteBlock key(32);
+///   prng.GenerateBlock(key, key.size());
+///
+///   Poly1305TLS poly1305(key, key.size());
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+/// +/// \details Second, you can create a Poly1305 object, and use a new key for each +/// message. The keys can be generated directly using a RandomNumberGenerator() +/// derived class. +///
  SecByteBlock key(32);
+///   prng.GenerateBlock(key, key.size());
+///
+///   // First message
+///   Poly1305TLS poly1305(key, key.size());
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+///
+///   // Second message
+///   prng.GenerateBlock(key, key.size());
+///   poly1305.SetKey(key, key.size());
+///   poly1305.Update(...);
+///   poly1305.Final(...);
+///   ...
+/// \warning Each message must have a unique security context. The Poly1305-TLS class +/// does not enforce a fresh key or nonce for each message. +/// \since Crypto++ 8.1 +/// \sa MessageAuthenticationCode(), RFC +/// 8439, ChaCha20 and Poly1305 for IETF Protocols +DOCUMENTED_TYPEDEF(MessageAuthenticationCodeFinal, Poly1305TLS); + +NAMESPACE_END + +#endif // CRYPTOPP_POLY1305_H diff --git a/third_party/cryptoppwin/include/cryptopp/polynomi.h b/third_party/cryptoppwin/include/cryptopp/polynomi.h new file mode 100644 index 00000000..9a754ef3 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/polynomi.h @@ -0,0 +1,463 @@ +// polynomi.h - originally written and placed in the public domain by Wei Dai + +/// \file polynomi.h +/// \brief Classes for polynomial basis and operations + +#ifndef CRYPTOPP_POLYNOMI_H +#define CRYPTOPP_POLYNOMI_H + +#include "cryptlib.h" +#include "secblock.h" +#include "algebra.h" +#include "misc.h" + +#include +#include + +NAMESPACE_BEGIN(CryptoPP) + +/// represents single-variable polynomials over arbitrary rings +/*! \nosubgrouping */ +template class PolynomialOver +{ +public: + /// \name ENUMS, EXCEPTIONS, and TYPEDEFS + //@{ + /// division by zero exception + class DivideByZero : public Exception + { + public: + DivideByZero() : Exception(OTHER_ERROR, "PolynomialOver: division by zero") {} + }; + + /// specify the distribution for randomization functions + class RandomizationParameter + { + public: + RandomizationParameter(unsigned int coefficientCount, const typename T::RandomizationParameter &coefficientParameter ) + : m_coefficientCount(coefficientCount), m_coefficientParameter(coefficientParameter) {} + + private: + unsigned int m_coefficientCount; + typename T::RandomizationParameter m_coefficientParameter; + friend class PolynomialOver; + }; + + typedef T Ring; + typedef typename T::Element CoefficientType; + //@} + + /// \name CREATORS + //@{ + /// creates the zero polynomial + PolynomialOver() {} + + /// + PolynomialOver(const Ring &ring, unsigned int count) + : m_coefficients((size_t)count, ring.Identity()) {} + + /// copy constructor + PolynomialOver(const PolynomialOver &t) + : m_coefficients(t.m_coefficients.size()) {*this = t;} + + /// construct constant polynomial + PolynomialOver(const CoefficientType &element) + : m_coefficients(1, element) {} + + /// construct polynomial with specified coefficients, starting from coefficient of x^0 + template PolynomialOver(Iterator begin, Iterator end) + : m_coefficients(begin, end) {} + + /// convert from string + PolynomialOver(const char *str, const Ring &ring) {FromStr(str, ring);} + + /// convert from big-endian byte array + PolynomialOver(const byte *encodedPolynomialOver, unsigned int byteCount); + + /// convert from Basic Encoding Rules encoded byte array + explicit PolynomialOver(const byte *BEREncodedPolynomialOver); + + /// convert from BER encoded byte array stored in a BufferedTransformation object + explicit PolynomialOver(BufferedTransformation &bt); + + /// create a random PolynomialOver + PolynomialOver(RandomNumberGenerator &rng, const RandomizationParameter ¶meter, const Ring &ring) + {Randomize(rng, parameter, ring);} + //@} + + /// \name ACCESSORS + //@{ + /// the zero polynomial will return a degree of -1 + int Degree(const Ring &ring) const {return int(CoefficientCount(ring))-1;} + /// + unsigned int CoefficientCount(const Ring &ring) const; + /// return coefficient for x^i + CoefficientType GetCoefficient(unsigned int i, const Ring &ring) const; + //@} + + /// \name MANIPULATORS + //@{ + /// + PolynomialOver& operator=(const PolynomialOver& t); + + /// + void Randomize(RandomNumberGenerator &rng, const RandomizationParameter ¶meter, const Ring &ring); + + /// set the coefficient for x^i to value + void SetCoefficient(unsigned int i, const CoefficientType &value, const Ring &ring); + + /// + void Negate(const Ring &ring); + + /// + void swap(PolynomialOver &t); + //@} + + + /// \name BASIC ARITHMETIC ON POLYNOMIALS + //@{ + bool Equals(const PolynomialOver &t, const Ring &ring) const; + bool IsZero(const Ring &ring) const {return CoefficientCount(ring)==0;} + + PolynomialOver Plus(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver Minus(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver Inverse(const Ring &ring) const; + + PolynomialOver Times(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver DividedBy(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver Modulo(const PolynomialOver& t, const Ring &ring) const; + PolynomialOver MultiplicativeInverse(const Ring &ring) const; + bool IsUnit(const Ring &ring) const; + + PolynomialOver& Accumulate(const PolynomialOver& t, const Ring &ring); + PolynomialOver& Reduce(const PolynomialOver& t, const Ring &ring); + + /// + PolynomialOver Doubled(const Ring &ring) const {return Plus(*this, ring);} + /// + PolynomialOver Squared(const Ring &ring) const {return Times(*this, ring);} + + CoefficientType EvaluateAt(const CoefficientType &x, const Ring &ring) const; + + PolynomialOver& ShiftLeft(unsigned int n, const Ring &ring); + PolynomialOver& ShiftRight(unsigned int n, const Ring &ring); + + /// calculate r and q such that (a == d*q + r) && (0 <= degree of r < degree of d) + static void Divide(PolynomialOver &r, PolynomialOver &q, const PolynomialOver &a, const PolynomialOver &d, const Ring &ring); + //@} + + /// \name INPUT/OUTPUT + //@{ + std::istream& Input(std::istream &in, const Ring &ring); + std::ostream& Output(std::ostream &out, const Ring &ring) const; + //@} + +private: + void FromStr(const char *str, const Ring &ring); + + std::vector m_coefficients; +}; + +/// Polynomials over a fixed ring +/*! Having a fixed ring allows overloaded operators */ +template class PolynomialOverFixedRing : private PolynomialOver +{ + typedef PolynomialOver B; + typedef PolynomialOverFixedRing ThisType; + +public: + typedef T Ring; + typedef typename T::Element CoefficientType; + typedef typename B::DivideByZero DivideByZero; + typedef typename B::RandomizationParameter RandomizationParameter; + + /// \name CREATORS + //@{ + /// creates the zero polynomial + PolynomialOverFixedRing(unsigned int count = 0) : B(ms_fixedRing, count) {} + + /// copy constructor + PolynomialOverFixedRing(const ThisType &t) : B(t) {} + + explicit PolynomialOverFixedRing(const B &t) : B(t) {} + + /// construct constant polynomial + PolynomialOverFixedRing(const CoefficientType &element) : B(element) {} + + /// construct polynomial with specified coefficients, starting from coefficient of x^0 + template PolynomialOverFixedRing(Iterator first, Iterator last) + : B(first, last) {} + + /// convert from string + explicit PolynomialOverFixedRing(const char *str) : B(str, ms_fixedRing) {} + + /// convert from big-endian byte array + PolynomialOverFixedRing(const byte *encodedPoly, unsigned int byteCount) : B(encodedPoly, byteCount) {} + + /// convert from Basic Encoding Rules encoded byte array + explicit PolynomialOverFixedRing(const byte *BEREncodedPoly) : B(BEREncodedPoly) {} + + /// convert from BER encoded byte array stored in a BufferedTransformation object + explicit PolynomialOverFixedRing(BufferedTransformation &bt) : B(bt) {} + + /// create a random PolynomialOverFixedRing + PolynomialOverFixedRing(RandomNumberGenerator &rng, const RandomizationParameter ¶meter) : B(rng, parameter, ms_fixedRing) {} + + static const ThisType &Zero(); + static const ThisType &One(); + //@} + + /// \name ACCESSORS + //@{ + /// the zero polynomial will return a degree of -1 + int Degree() const {return B::Degree(ms_fixedRing);} + /// degree + 1 + unsigned int CoefficientCount() const {return B::CoefficientCount(ms_fixedRing);} + /// return coefficient for x^i + CoefficientType GetCoefficient(unsigned int i) const {return B::GetCoefficient(i, ms_fixedRing);} + /// return coefficient for x^i + CoefficientType operator[](unsigned int i) const {return B::GetCoefficient(i, ms_fixedRing);} + //@} + + /// \name MANIPULATORS + //@{ + /// + ThisType& operator=(const ThisType& t) {B::operator=(t); return *this;} + /// + ThisType& operator+=(const ThisType& t) {Accumulate(t, ms_fixedRing); return *this;} + /// + ThisType& operator-=(const ThisType& t) {Reduce(t, ms_fixedRing); return *this;} + /// + ThisType& operator*=(const ThisType& t) {return *this = *this*t;} + /// + ThisType& operator/=(const ThisType& t) {return *this = *this/t;} + /// + ThisType& operator%=(const ThisType& t) {return *this = *this%t;} + + /// + ThisType& operator<<=(unsigned int n) {ShiftLeft(n, ms_fixedRing); return *this;} + /// + ThisType& operator>>=(unsigned int n) {ShiftRight(n, ms_fixedRing); return *this;} + + /// set the coefficient for x^i to value + void SetCoefficient(unsigned int i, const CoefficientType &value) {B::SetCoefficient(i, value, ms_fixedRing);} + + /// + void Randomize(RandomNumberGenerator &rng, const RandomizationParameter ¶meter) {B::Randomize(rng, parameter, ms_fixedRing);} + + /// + void Negate() {B::Negate(ms_fixedRing);} + + void swap(ThisType &t) {B::swap(t);} + //@} + + /// \name UNARY OPERATORS + //@{ + /// + bool operator!() const {return CoefficientCount()==0;} + /// + ThisType operator+() const {return *this;} + /// + ThisType operator-() const {return ThisType(Inverse(ms_fixedRing));} + //@} + + /// \name BINARY OPERATORS + //@{ + /// + friend ThisType operator>>(ThisType a, unsigned int n) {return ThisType(a>>=n);} + /// + friend ThisType operator<<(ThisType a, unsigned int n) {return ThisType(a<<=n);} + //@} + + /// \name OTHER ARITHMETIC FUNCTIONS + //@{ + /// + ThisType MultiplicativeInverse() const {return ThisType(B::MultiplicativeInverse(ms_fixedRing));} + /// + bool IsUnit() const {return B::IsUnit(ms_fixedRing);} + + /// + ThisType Doubled() const {return ThisType(B::Doubled(ms_fixedRing));} + /// + ThisType Squared() const {return ThisType(B::Squared(ms_fixedRing));} + + CoefficientType EvaluateAt(const CoefficientType &x) const {return B::EvaluateAt(x, ms_fixedRing);} + + /// calculate r and q such that (a == d*q + r) && (0 <= r < abs(d)) + static void Divide(ThisType &r, ThisType &q, const ThisType &a, const ThisType &d) + {B::Divide(r, q, a, d, ms_fixedRing);} + //@} + + /// \name INPUT/OUTPUT + //@{ + /// + friend std::istream& operator>>(std::istream& in, ThisType &a) + {return a.Input(in, ms_fixedRing);} + /// + friend std::ostream& operator<<(std::ostream& out, const ThisType &a) + {return a.Output(out, ms_fixedRing);} + //@} + +private: + struct NewOnePolynomial + { + ThisType * operator()() const + { + return new ThisType(ms_fixedRing.MultiplicativeIdentity()); + } + }; + + static const Ring ms_fixedRing; +}; + +/// Ring of polynomials over another ring +template class RingOfPolynomialsOver : public AbstractEuclideanDomain > +{ +public: + typedef T CoefficientRing; + typedef PolynomialOver Element; + typedef typename Element::CoefficientType CoefficientType; + typedef typename Element::RandomizationParameter RandomizationParameter; + + RingOfPolynomialsOver(const CoefficientRing &ring) : m_ring(ring) {} + + Element RandomElement(RandomNumberGenerator &rng, const RandomizationParameter ¶meter) + {return Element(rng, parameter, m_ring);} + + bool Equal(const Element &a, const Element &b) const + {return a.Equals(b, m_ring);} + + const Element& Identity() const + {return this->result = m_ring.Identity();} + + const Element& Add(const Element &a, const Element &b) const + {return this->result = a.Plus(b, m_ring);} + + Element& Accumulate(Element &a, const Element &b) const + {a.Accumulate(b, m_ring); return a;} + + const Element& Inverse(const Element &a) const + {return this->result = a.Inverse(m_ring);} + + const Element& Subtract(const Element &a, const Element &b) const + {return this->result = a.Minus(b, m_ring);} + + Element& Reduce(Element &a, const Element &b) const + {return a.Reduce(b, m_ring);} + + const Element& Double(const Element &a) const + {return this->result = a.Doubled(m_ring);} + + const Element& MultiplicativeIdentity() const + {return this->result = m_ring.MultiplicativeIdentity();} + + const Element& Multiply(const Element &a, const Element &b) const + {return this->result = a.Times(b, m_ring);} + + const Element& Square(const Element &a) const + {return this->result = a.Squared(m_ring);} + + bool IsUnit(const Element &a) const + {return a.IsUnit(m_ring);} + + const Element& MultiplicativeInverse(const Element &a) const + {return this->result = a.MultiplicativeInverse(m_ring);} + + const Element& Divide(const Element &a, const Element &b) const + {return this->result = a.DividedBy(b, m_ring);} + + const Element& Mod(const Element &a, const Element &b) const + {return this->result = a.Modulo(b, m_ring);} + + void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const + {Element::Divide(r, q, a, d, m_ring);} + + class InterpolationFailed : public Exception + { + public: + InterpolationFailed() : Exception(OTHER_ERROR, "RingOfPolynomialsOver: interpolation failed") {} + }; + + Element Interpolate(const CoefficientType x[], const CoefficientType y[], unsigned int n) const; + + // a faster version of Interpolate(x, y, n).EvaluateAt(position) + CoefficientType InterpolateAt(const CoefficientType &position, const CoefficientType x[], const CoefficientType y[], unsigned int n) const; +/* + void PrepareBulkInterpolation(CoefficientType *w, const CoefficientType x[], unsigned int n) const; + void PrepareBulkInterpolationAt(CoefficientType *v, const CoefficientType &position, const CoefficientType x[], const CoefficientType w[], unsigned int n) const; + CoefficientType BulkInterpolateAt(const CoefficientType y[], const CoefficientType v[], unsigned int n) const; +*/ +protected: + void CalculateAlpha(std::vector &alpha, const CoefficientType x[], const CoefficientType y[], unsigned int n) const; + + CoefficientRing m_ring; +}; + +template +void PrepareBulkPolynomialInterpolation(const Ring &ring, Element *w, const Element x[], unsigned int n); +template +void PrepareBulkPolynomialInterpolationAt(const Ring &ring, Element *v, const Element &position, const Element x[], const Element w[], unsigned int n); +template +Element BulkPolynomialInterpolateAt(const Ring &ring, const Element y[], const Element v[], unsigned int n); + +/// +template +inline bool operator==(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Equals(b, a.ms_fixedRing);} +/// +template +inline bool operator!=(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return !(a==b);} + +/// +template +inline bool operator> (const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() > b.Degree();} +/// +template +inline bool operator>=(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() >= b.Degree();} +/// +template +inline bool operator< (const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() < b.Degree();} +/// +template +inline bool operator<=(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return a.Degree() <= b.Degree();} + +/// +template +inline CryptoPP::PolynomialOverFixedRing operator+(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Plus(b, a.ms_fixedRing));} +/// +template +inline CryptoPP::PolynomialOverFixedRing operator-(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Minus(b, a.ms_fixedRing));} +/// +template +inline CryptoPP::PolynomialOverFixedRing operator*(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Times(b, a.ms_fixedRing));} +/// +template +inline CryptoPP::PolynomialOverFixedRing operator/(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.DividedBy(b, a.ms_fixedRing));} +/// +template +inline CryptoPP::PolynomialOverFixedRing operator%(const CryptoPP::PolynomialOverFixedRing &a, const CryptoPP::PolynomialOverFixedRing &b) + {return CryptoPP::PolynomialOverFixedRing(a.Modulo(b, a.ms_fixedRing));} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) +template inline void swap(CryptoPP::PolynomialOver &a, CryptoPP::PolynomialOver &b) +{ + a.swap(b); +} +template inline void swap(CryptoPP::PolynomialOverFixedRing &a, CryptoPP::PolynomialOverFixedRing &b) +{ + a.swap(b); +} +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/ppc_simd.h b/third_party/cryptoppwin/include/cryptopp/ppc_simd.h new file mode 100644 index 00000000..a5297cf1 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/ppc_simd.h @@ -0,0 +1,2764 @@ +// ppc_simd.h - written and placed in public domain by Jeffrey Walton + +/// \file ppc_simd.h +/// \brief Support functions for PowerPC and vector operations +/// \details This header provides an agnostic interface into Clang, GCC +/// and IBM XL C/C++ compilers modulo their different built-in functions +/// for accessing vector instructions. +/// \details The abstractions are necessary to support back to GCC 4.8 and +/// XLC 11 and 12. GCC 4.8 and 4.9 are still popular, and they are the +/// default compiler for GCC112, GCC119 and others on the compile farm. +/// Older IBM XL C/C++ compilers also have the need due to lack of +/// vec_xl and vec_xst support on some platforms. Modern +/// compilers provide best support and don't need many of the hacks +/// below. +/// \details The library is tested with the following PowerPC machines and +/// compilers. GCC110, GCC111, GCC112, GCC119 and GCC135 are provided by +/// the GCC Compile Farm +/// - PowerMac G5, OSX 10.5, POWER4, Apple GCC 4.0 +/// - PowerMac G5, OSX 10.5, POWER4, Macports GCC 5.0 +/// - GCC110, Linux, POWER7, GCC 4.8.5 +/// - GCC110, Linux, POWER7, XLC 12.01 +/// - GCC111, AIX, POWER7, GCC 4.8.1 +/// - GCC111, AIX, POWER7, XLC 12.01 +/// - GCC112, Linux, POWER8, GCC 4.8.5 +/// - GCC112, Linux, POWER8, XLC 13.01 +/// - GCC112, Linux, POWER8, Clang 7.0 +/// - GCC119, AIX, POWER8, GCC 7.2.0 +/// - GCC119, AIX, POWER8, XLC 13.01 +/// - GCC135, Linux, POWER9, GCC 7.0 +/// \details 12 machines are used for testing because the three compilers form +/// five or six profiles. The profiles are listed below. +/// - GCC (Linux GCC, Macports GCC, etc. Consistent across machines) +/// - XLC 13.0 and earlier (all IBM components) +/// - XLC 13.1 and later on Linux (LLVM front-end, no compatibility macros) +/// - XLC 13.1 and later on Linux (LLVM front-end, -qxlcompatmacros option) +/// - early LLVM Clang (traditional Clang compiler) +/// - late LLVM Clang (traditional Clang compiler) +/// \details The LLVM front-end makes it tricky to write portable code because +/// LLVM pretends to be other compilers but cannot consume other compiler's +/// builtins. When using XLC with -qxlcompatmacros the compiler pretends to +/// be GCC, Clang and XLC all at once but it can only consume it's variety +/// of builtins. +/// \details At Crypto++ 8.0 the various Vector{FuncName} were +/// renamed to Vec{FuncName}. For example, VectorAnd was +/// changed to VecAnd. The name change helped consolidate two +/// slightly different implementations. +/// \details At Crypto++ 8.3 the library added select 64-bit functions for +/// 32-bit Altivec. For example, VecAdd64 and VecSub64 +/// take 32-bit vectors and adds or subtracts them as if there were vectors +/// with two 64-bit elements. The functions dramtically improve performance +/// for some algorithms on some platforms, like SIMON128 and SPECK128 on +/// Power6 and earlier. For example, SPECK128 improved from 70 cpb to +/// 10 cpb on an old PowerMac. Use the functions like shown below. +///
+///    \#if defined(_ARCH_PWR8)
+///    \#  define speck128_t uint64x2_p
+///    \#else
+///    \#  define speck128_t uint32x4_p
+///    \#endif
+///
+///    speck128_t rk, x1, x2, y1, y2;
+///    rk = (speck128_t)VecLoadAligned(ptr);
+///    x1 = VecRotateRight64<8>(x1);
+///    x1 = VecAdd64(x1, y1);
+///    ...
+/// \since Crypto++ 6.0, LLVM Clang compiler support since Crypto++ 8.0 + +// Use __ALTIVEC__, _ARCH_PWR7, __VSX__, and _ARCH_PWR8 when detecting +// actual availaibility of the feature for the source file being compiled. +// The preprocessor macros depend on compiler options like -maltivec; and +// not compiler versions. + +// For GCC see https://gcc.gnu.org/onlinedocs/gcc/Basic-PowerPC-Built-in-Functions.html +// For XLC see the Compiler Reference manual. For Clang you have to experiment. +// Clang does not document the compiler options, does not reject options it does +// not understand, and pretends to be other compilers even though it cannot +// process the builtins and intrinsics. Clang will waste hours of your time. + +// DO NOT USE this pattern in VecLoad and VecStore. We have to use the +// code paths guarded by preprocessor macros because XLC 12 generates +// bad code in some places. To verify the bad code generation test on +// GCC111 with XLC 12.01 installed. XLC 13.01 on GCC112 and GCC119 are OK. +// +// inline uint32x4_p VecLoad(const byte src[16]) +// { +// #if defined(__VSX__) || defined(_ARCH_PWR8) +// return (uint32x4_p) *(uint8x16_p*)((byte*)src); +// #else +// return VecLoad_ALTIVEC(src); +// #endif +// } + +// We should be able to perform the load using inline asm on Power7 with +// VSX or Power8. The inline asm will avoid C undefined behavior due to +// casting from byte* to word32*. We are safe because our byte* are +// 16-byte aligned for Altivec. Below is the big endian load. Little +// endian would need to follow with xxpermdi for the reversal. +// +// __asm__ ("lxvw4x %x0, %1, %2" : "=wa"(v) : "r"(0), "r"(src) : ); + +// GCC and XLC use integer math for the address (D-form or byte-offset +// in the ISA manual). LLVM uses pointer math for the address (DS-form +// or indexed in the ISA manual). To keep them consistent we calculate +// the address from the offset and pass to a load or store function +// using a 0 offset. + +#ifndef CRYPTOPP_PPC_CRYPTO_H +#define CRYPTOPP_PPC_CRYPTO_H + +#include "config.h" +#include "misc.h" + +#if defined(__ALTIVEC__) +# include +# undef vector +# undef pixel +# undef bool +#endif + +// XL C++ on AIX does not define VSX and does not +// provide an option to set it. We have to set it +// for the code below. This define must stay in +// sync with the define in test_ppc_power7.cpp. +#ifndef CRYPTOPP_DISABLE_POWER7 +# if defined(_AIX) && defined(_ARCH_PWR7) && defined(__xlC__) +# define __VSX__ 1 +# endif +#endif + +// XL C++ on AIX does not define CRYPTO and does not +// provide an option to set it. We have to set it +// for the code below. This define must stay in +// sync with the define in test_ppc_power8.cpp +#ifndef CRYPTOPP_DISABLE_POWER8 +# if defined(_AIX) && defined(_ARCH_PWR8) && defined(__xlC__) +# define __CRYPTO__ 1 +# endif +#endif + +/// \brief Cast array to vector pointer +/// \details CONST_V8_CAST casts a const array to a vector +/// pointer for a byte array. The Power ABI says source arrays +/// are non-const, so this define removes the const. XLC++ will +/// fail the compile if the source array is const. +#define CONST_V8_CAST(x) ((unsigned char*)(x)) +/// \brief Cast array to vector pointer +/// \details CONST_V32_CAST casts a const array to a vector +/// pointer for a word array. The Power ABI says source arrays +/// are non-const, so this define removes the const. XLC++ will +/// fail the compile if the source array is const. +#define CONST_V32_CAST(x) ((unsigned int*)(x)) +/// \brief Cast array to vector pointer +/// \details CONST_V64_CAST casts a const array to a vector +/// pointer for a double word array. The Power ABI says source arrays +/// are non-const, so this define removes the const. XLC++ will +/// fail the compile if the source array is const. +#define CONST_V64_CAST(x) ((unsigned long long*)(x)) +/// \brief Cast array to vector pointer +/// \details NCONST_V8_CAST casts an array to a vector +/// pointer for a byte array. The Power ABI says source arrays +/// are non-const, so this define removes the const. XLC++ will +/// fail the compile if the source array is const. +#define NCONST_V8_CAST(x) ((unsigned char*)(x)) +/// \brief Cast array to vector pointer +/// \details NCONST_V32_CAST casts an array to a vector +/// pointer for a word array. The Power ABI says source arrays +/// are non-const, so this define removes the const. XLC++ will +/// fail the compile if the source array is const. +#define NCONST_V32_CAST(x) ((unsigned int*)(x)) +/// \brief Cast array to vector pointer +/// \details NCONST_V64_CAST casts an array to a vector +/// pointer for a double word array. The Power ABI says source arrays +/// are non-const, so this define removes the const. XLC++ will +/// fail the compile if the source array is const. +#define NCONST_V64_CAST(x) ((unsigned long long*)(x)) + +// VecLoad_ALTIVEC and VecStore_ALTIVEC are +// too noisy on modern compilers +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#if defined(__ALTIVEC__) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Vector of 8-bit elements +/// \par Wraps +/// __vector unsigned char +/// \since Crypto++ 6.0 +typedef __vector unsigned char uint8x16_p; +/// \brief Vector of 16-bit elements +/// \par Wraps +/// __vector unsigned short +/// \since Crypto++ 6.0 +typedef __vector unsigned short uint16x8_p; +/// \brief Vector of 32-bit elements +/// \par Wraps +/// __vector unsigned int +/// \since Crypto++ 6.0 +typedef __vector unsigned int uint32x4_p; + +#if defined(__VSX__) || defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Vector of 64-bit elements +/// \details uint64x2_p is available on POWER7 with VSX and above. Most +/// supporting functions, like 64-bit vec_add (vaddudm) +/// and vec_sub (vsubudm), did not arrive until POWER8. +/// \par Wraps +/// __vector unsigned long long +/// \since Crypto++ 6.0 +typedef __vector unsigned long long uint64x2_p; +#endif // VSX or ARCH_PWR8 + +/// \brief The 0 vector +/// \return a 32-bit vector of 0's +/// \since Crypto++ 8.0 +inline uint32x4_p VecZero() +{ + const uint32x4_p v = {0,0,0,0}; + return v; +} + +/// \brief The 1 vector +/// \return a 32-bit vector of 1's +/// \since Crypto++ 8.0 +inline uint32x4_p VecOne() +{ + const uint32x4_p v = {1,1,1,1}; + return v; +} + +/// \brief Reverse bytes in a vector +/// \tparam T vector type +/// \param data the vector +/// \return vector +/// \details VecReverse() reverses the bytes in a vector +/// \par Wraps +/// vec_perm +/// \since Crypto++ 6.0 +template +inline T VecReverse(const T data) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + const uint8x16_p mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + return (T)vec_perm(data, data, mask); +#else + const uint8x16_p mask = {0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15}; + return (T)vec_perm(data, data, mask); +#endif +} + +/// \brief Reverse bytes in a vector +/// \tparam T vector type +/// \param data the vector +/// \return vector +/// \details VecReverseLE() reverses the bytes in a vector on +/// little-endian systems. +/// \par Wraps +/// vec_perm +/// \since Crypto++ 6.0 +template +inline T VecReverseLE(const T data) +{ +#if defined(CRYPTOPP_LITTLE_ENDIAN) + const uint8x16_p mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + return (T)vec_perm(data, data, mask); +#else + return data; +#endif +} + +/// \brief Reverse bytes in a vector +/// \tparam T vector type +/// \param data the vector +/// \return vector +/// \details VecReverseBE() reverses the bytes in a vector on +/// big-endian systems. +/// \par Wraps +/// vec_perm +/// \since Crypto++ 6.0 +template +inline T VecReverseBE(const T data) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + const uint8x16_p mask = {15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0}; + return (T)vec_perm(data, data, mask); +#else + return data; +#endif +} + +/// \name LOAD OPERATIONS +//@{ + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \details Loads a vector in native endian format from a byte array. +/// \details VecLoad_ALTIVEC() uses vec_ld if the effective address +/// of src is aligned. If unaligned it uses vec_lvsl, +/// vec_ld, vec_perm and src. The fixups using +/// vec_lvsl and vec_perm are relatively expensive so +/// you should provide aligned memory addresses. +/// \par Wraps +/// vec_ld, vec_lvsl, vec_perm +/// \sa VecLoad, VecLoadAligned +/// \since Crypto++ 6.0 +inline uint32x4_p VecLoad_ALTIVEC(const byte src[16]) +{ + // Avoid IsAlignedOn for convenience. + const uintptr_t addr = reinterpret_cast(src); + if (addr % 16 == 0) + { + return (uint32x4_p)vec_ld(0, CONST_V8_CAST(addr)); + } + else + { + // http://www.nxp.com/docs/en/reference-manual/ALTIVECPEM.pdf + const uint8x16_p perm = vec_lvsl(0, CONST_V8_CAST(addr)); + const uint8x16_p low = vec_ld(0, CONST_V8_CAST(addr)); + const uint8x16_p high = vec_ld(15, CONST_V8_CAST(addr)); + return (uint32x4_p)vec_perm(low, high, perm); + } +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \param off offset into the src byte array +/// \details Loads a vector in native endian format from a byte array. +/// \details VecLoad_ALTIVEC() uses vec_ld if the effective address +/// of src is aligned. If unaligned it uses vec_lvsl, +/// vec_ld, vec_perm and src. +/// \details The fixups using vec_lvsl and vec_perm are +/// relatively expensive so you should provide aligned memory addresses. +/// \par Wraps +/// vec_ld, vec_lvsl, vec_perm +/// \sa VecLoad, VecLoadAligned +/// \since Crypto++ 6.0 +inline uint32x4_p VecLoad_ALTIVEC(int off, const byte src[16]) +{ + // Avoid IsAlignedOn for convenience. + const uintptr_t addr = reinterpret_cast(src)+off; + if (addr % 16 == 0) + { + return (uint32x4_p)vec_ld(0, CONST_V8_CAST(addr)); + } + else + { + // http://www.nxp.com/docs/en/reference-manual/ALTIVECPEM.pdf + const uint8x16_p perm = vec_lvsl(0, CONST_V8_CAST(addr)); + const uint8x16_p low = vec_ld(0, CONST_V8_CAST(addr)); + const uint8x16_p high = vec_ld(15, CONST_V8_CAST(addr)); + return (uint32x4_p)vec_perm(low, high, perm); + } +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \details VecLoad() loads a vector from a byte array. +/// \details VecLoad() uses POWER9's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER9 is not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xl on POWER9 and above, Altivec load on POWER8 and below +/// \sa VecLoad_ALTIVEC, VecLoadAligned +/// \since Crypto++ 6.0 +inline uint32x4_p VecLoad(const byte src[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(0, CONST_V8_CAST(src)); +#else + return (uint32x4_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#endif +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \param off offset into the src byte array +/// \details VecLoad() loads a vector from a byte array. +/// \details VecLoad() uses POWER9's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER9 is not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xl on POWER9 and above, Altivec load on POWER8 and below +/// \sa VecLoad_ALTIVEC, VecLoadAligned +/// \since Crypto++ 6.0 +inline uint32x4_p VecLoad(int off, const byte src[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(off, CONST_V8_CAST(src)); +#else + return (uint32x4_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#endif +} + +/// \brief Loads a vector from a word array +/// \param src the word array +/// \details VecLoad() loads a vector from a word array. +/// \details VecLoad() uses POWER7's and VSX's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER7 is not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, Altivec load on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoadAligned +/// \since Crypto++ 8.0 +inline uint32x4_p VecLoad(const word32 src[4]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(0, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + return (uint32x4_p)vec_xl(0, CONST_V32_CAST(addr)); +#else + return (uint32x4_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#endif +} + +/// \brief Loads a vector from a word array +/// \param src the word array +/// \param off offset into the word array +/// \details VecLoad() loads a vector from a word array. +/// \details VecLoad() uses POWER7's and VSX's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER7 is not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, Altivec load on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoadAligned +/// \since Crypto++ 8.0 +inline uint32x4_p VecLoad(int off, const word32 src[4]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(off, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + return (uint32x4_p)vec_xl(0, CONST_V32_CAST(addr)); +#else + return (uint32x4_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#endif +} + +#if defined(__VSX__) || defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Loads a vector from a double word array +/// \param src the double word array +/// \details VecLoad() loads a vector from a double word array. +/// \details VecLoad() uses POWER7's and VSX's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER7 and VSX are not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \details VecLoad() with 64-bit elements is available on POWER7 and above. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, Altivec load on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoadAligned +/// \since Crypto++ 8.0 +inline uint64x2_p VecLoad(const word64 src[2]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint64x2_p)vec_xl(0, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + // The 32-bit cast is not a typo. Compiler workaround. + return (uint64x2_p)vec_xl(0, CONST_V32_CAST(addr)); +#else + return (uint64x2_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#endif +} + +/// \brief Loads a vector from a double word array +/// \param src the double word array +/// \param off offset into the double word array +/// \details VecLoad() loads a vector from a double word array. +/// \details VecLoad() uses POWER7's and VSX's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER7 and VSX are not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \details VecLoad() with 64-bit elements is available on POWER8 and above. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, Altivec load on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoadAligned +/// \since Crypto++ 8.0 +inline uint64x2_p VecLoad(int off, const word64 src[2]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint64x2_p)vec_xl(off, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + // The 32-bit cast is not a typo. Compiler workaround. + return (uint64x2_p)vec_xl(0, CONST_V32_CAST(addr)); +#else + return (uint64x2_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#endif +} + +#endif // VSX or ARCH_PWR8 + +/// \brief Loads a vector from an aligned byte array +/// \param src the byte array +/// \details VecLoadAligned() loads a vector from an aligned byte array. +/// \details VecLoadAligned() uses POWER9's vec_xl if available. +/// vec_ld is used if POWER9 is not available. The effective +/// address of src must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xl on POWER9, vec_ld on POWER8 and below +/// \sa VecLoad_ALTIVEC, VecLoad +/// \since Crypto++ 8.0 +inline uint32x4_p VecLoadAligned(const byte src[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + CRYPTOPP_ASSERT(addr % 16 == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(0, CONST_V8_CAST(src)); +#else + return (uint32x4_p)vec_ld(0, CONST_V8_CAST(src)); +#endif +} + +/// \brief Loads a vector from an aligned byte array +/// \param src the byte array +/// \param off offset into the src byte array +/// \details VecLoadAligned() loads a vector from an aligned byte array. +/// \details VecLoadAligned() uses POWER9's vec_xl if available. +/// vec_ld is used if POWER9 is not available. The effective +/// address of src must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xl on POWER9, vec_ld on POWER8 and below +/// \sa VecLoad_ALTIVEC, VecLoad +/// \since Crypto++ 8.0 +inline uint32x4_p VecLoadAligned(int off, const byte src[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + CRYPTOPP_ASSERT(addr % 16 == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(off, CONST_V8_CAST(src)); +#else + return (uint32x4_p)vec_ld(off, CONST_V8_CAST(src)); +#endif +} + +/// \brief Loads a vector from an aligned word array +/// \param src the word array +/// \details VecLoadAligned() loads a vector from an aligned word array. +/// \details VecLoadAligned() uses POWER7's and VSX's vec_xl if +/// available. vec_ld is used if POWER7 or VSX are not available. +/// The effective address of src must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, vec_ld on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoad +/// \since Crypto++ 8.0 +inline uint32x4_p VecLoadAligned(const word32 src[4]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + CRYPTOPP_ASSERT(addr % 16 == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(0, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + return (uint32x4_p)vec_xl(0, CONST_V32_CAST(src)); +#else + return (uint32x4_p)vec_ld(0, CONST_V8_CAST(src)); +#endif +} + +/// \brief Loads a vector from an aligned word array +/// \param src the word array +/// \param off offset into the src word array +/// \details VecLoadAligned() loads a vector from an aligned word array. +/// \details VecLoadAligned() uses POWER7's and VSX's vec_xl if +/// available. vec_ld is used if POWER7 or VSX are not available. +/// The effective address of src must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, vec_ld on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoad +/// \since Crypto++ 8.0 +inline uint32x4_p VecLoadAligned(int off, const word32 src[4]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + CRYPTOPP_ASSERT(addr % 16 == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint32x4_p)vec_xl(off, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + return (uint32x4_p)vec_xl(0, CONST_V32_CAST(addr)); +#else + return (uint32x4_p)vec_ld(off, CONST_V8_CAST(src)); +#endif +} + +#if defined(__VSX__) || defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Loads a vector from an aligned double word array +/// \param src the double word array +/// \details VecLoadAligned() loads a vector from an aligned double word array. +/// \details VecLoadAligned() uses POWER7's and VSX's vec_xl if +/// available. vec_ld is used if POWER7 or VSX are not available. +/// The effective address of src must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, vec_ld on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoad +/// \since Crypto++ 8.0 +inline uint64x2_p VecLoadAligned(const word64 src[4]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + CRYPTOPP_ASSERT(addr % 16 == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint64x2_p)vec_xl(0, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + // The 32-bit cast is not a typo. Compiler workaround. + return (uint64x2_p)vec_xl(0, CONST_V32_CAST(src)); +#else + return (uint64x2_p)vec_ld(0, CONST_V8_CAST(src)); +#endif +} + +/// \brief Loads a vector from an aligned double word array +/// \param src the double word array +/// \param off offset into the src double word array +/// \details VecLoadAligned() loads a vector from an aligned double word array. +/// \details VecLoadAligned() uses POWER7's and VSX's vec_xl if +/// available. vec_ld is used if POWER7 or VSX are not available. +/// The effective address of src must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xl on VSX or POWER8 and above, vec_ld on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoad +/// \since Crypto++ 8.0 +inline uint64x2_p VecLoadAligned(int off, const word64 src[4]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + CRYPTOPP_ASSERT(addr % 16 == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + return (uint64x2_p)vec_xl(off, CONST_V8_CAST(src)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + // The 32-bit cast is not a typo. Compiler workaround. + return (uint64x2_p)vec_xl(0, CONST_V32_CAST(addr)); +#else + return (uint64x2_p)vec_ld(off, CONST_V8_CAST(src)); +#endif +} + +#endif + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \details VecLoadBE() loads a vector from a byte array. VecLoadBE +/// will reverse all bytes in the array on a little endian system. +/// \details VecLoadBE() uses POWER7's and VSX's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER7 or VSX are not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xl on POWER8, Altivec load on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoad, VecLoadAligned +/// \since Crypto++ 6.0 +inline uint32x4_p VecLoadBE(const byte src[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src); + // CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + return (uint32x4_p)vec_xl_be(0, CONST_V8_CAST(src)); +#elif defined(CRYPTOPP_BIG_ENDIAN) + return (uint32x4_p)VecLoad_ALTIVEC(0, CONST_V8_CAST(src)); +#else + return (uint32x4_p)VecReverseLE(VecLoad_ALTIVEC(CONST_V8_CAST(src))); +#endif +} + +/// \brief Loads a vector from a byte array +/// \param src the byte array +/// \param off offset into the src byte array +/// \details VecLoadBE() loads a vector from a byte array. VecLoadBE +/// will reverse all bytes in the array on a little endian system. +/// \details VecLoadBE() uses POWER7's and VSX's vec_xl if available. +/// The instruction does not require aligned effective memory addresses. +/// VecLoad_ALTIVEC() is used if POWER7 is not available. +/// VecLoad_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xl on POWER8, Altivec load on POWER7 and below +/// \sa VecLoad_ALTIVEC, VecLoad, VecLoadAligned +/// \since Crypto++ 6.0 +inline uint32x4_p VecLoadBE(int off, const byte src[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(src)+off; + // CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + return (uint32x4_p)vec_xl_be(off, CONST_V8_CAST(src)); +#elif defined(CRYPTOPP_BIG_ENDIAN) + return (uint32x4_p)VecLoad_ALTIVEC(CONST_V8_CAST(addr)); +#else + return (uint32x4_p)VecReverseLE(VecLoad_ALTIVEC(CONST_V8_CAST(addr))); +#endif +} + +//@} + +/// \name STORE OPERATIONS +//@{ + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param dest the byte array +/// \details VecStore_ALTIVEC() stores a vector to a byte array. +/// \details VecStore_ALTIVEC() uses vec_st if the effective address +/// of dest is aligned, and uses vec_ste otherwise. +/// vec_ste is relatively expensive so you should provide aligned +/// memory addresses. +/// \details VecStore_ALTIVEC() is used when POWER7 or above +/// and unaligned loads is not available. +/// \par Wraps +/// vec_st, vec_ste, vec_lvsr, vec_perm +/// \sa VecStore, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStore_ALTIVEC(const T data, byte dest[16]) +{ + // Avoid IsAlignedOn for convenience. + uintptr_t addr = reinterpret_cast(dest); + if (addr % 16 == 0) + { + vec_st((uint8x16_p)data, 0, NCONST_V8_CAST(addr)); + } + else + { + // http://www.nxp.com/docs/en/reference-manual/ALTIVECPEM.pdf + uint8x16_p perm = (uint8x16_p)vec_perm(data, data, vec_lvsr(0, NCONST_V8_CAST(addr))); + vec_ste((uint8x16_p) perm, 0, (unsigned char*) NCONST_V8_CAST(addr)); + vec_ste((uint16x8_p) perm, 1, (unsigned short*)NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 3, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 4, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 8, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 12, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint16x8_p) perm, 14, (unsigned short*)NCONST_V8_CAST(addr)); + vec_ste((uint8x16_p) perm, 15, (unsigned char*) NCONST_V8_CAST(addr)); + } +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest byte array +/// \param dest the byte array +/// \details VecStore_ALTIVEC() stores a vector to a byte array. +/// \details VecStore_ALTIVEC() uses vec_st if the effective address +/// of dest is aligned, and uses vec_ste otherwise. +/// vec_ste is relatively expensive so you should provide aligned +/// memory addresses. +/// \details VecStore_ALTIVEC() is used when POWER7 or above +/// and unaligned loads is not available. +/// \par Wraps +/// vec_st, vec_ste, vec_lvsr, vec_perm +/// \sa VecStore, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStore_ALTIVEC(const T data, int off, byte dest[16]) +{ + // Avoid IsAlignedOn for convenience. + uintptr_t addr = reinterpret_cast(dest)+off; + if (addr % 16 == 0) + { + vec_st((uint8x16_p)data, 0, NCONST_V8_CAST(addr)); + } + else + { + // http://www.nxp.com/docs/en/reference-manual/ALTIVECPEM.pdf + uint8x16_p perm = (uint8x16_p)vec_perm(data, data, vec_lvsr(0, NCONST_V8_CAST(addr))); + vec_ste((uint8x16_p) perm, 0, (unsigned char*) NCONST_V8_CAST(addr)); + vec_ste((uint16x8_p) perm, 1, (unsigned short*)NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 3, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 4, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 8, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint32x4_p) perm, 12, (unsigned int*) NCONST_V8_CAST(addr)); + vec_ste((uint16x8_p) perm, 14, (unsigned short*)NCONST_V8_CAST(addr)); + vec_ste((uint8x16_p) perm, 15, (unsigned char*) NCONST_V8_CAST(addr)); + } +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param dest the byte array +/// \details VecStore() stores a vector to a byte array. +/// \details VecStore() uses POWER9's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER9 is not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on POWER9 and above, Altivec store on POWER8 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 6.0 +template +inline void VecStore(const T data, byte dest[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#else + VecStore_ALTIVEC((uint8x16_p)data, NCONST_V8_CAST(dest)); +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest byte array +/// \param dest the byte array +/// \details VecStore() stores a vector to a byte array. +/// \details VecStore() uses POWER9's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER9 is not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on POWER9 and above, Altivec store on POWER8 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 6.0 +template +inline void VecStore(const T data, int off, byte dest[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#else + VecStore_ALTIVEC((uint8x16_p)data, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param dest the word array +/// \details VecStore() stores a vector to a word array. +/// \details VecStore() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 or VSX are not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, Altivec store on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStore(const T data, word32 dest[4]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + vec_xst((uint32x4_p)data, 0, NCONST_V32_CAST(addr)); +#else + VecStore_ALTIVEC((uint8x16_p)data, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest word array +/// \param dest the word array +/// \details VecStore() stores a vector to a word array. +/// \details VecStore() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 or VSX are not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, Altivec store on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStore(const T data, int off, word32 dest[4]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + vec_xst((uint32x4_p)data, 0, NCONST_V32_CAST(addr)); +#else + VecStore_ALTIVEC((uint8x16_p)data, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param dest the word array +/// \details VecStore() stores a vector to a word array. +/// \details VecStore() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 or VSX are not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \details VecStore() with 64-bit elements is available on POWER8 and above. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, Altivec store on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStore(const T data, word64 dest[2]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + // 32-bit cast is not a typo. Compiler workaround. + vec_xst((uint32x4_p)data, 0, NCONST_V32_CAST(addr)); +#else + VecStore_ALTIVEC((uint8x16_p)data, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest word array +/// \param dest the word array +/// \details VecStore() stores a vector to a word array. +/// \details VecStore() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 or VSX are not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \details VecStore() with 64-bit elements is available on POWER8 and above. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, Altivec store on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStore(const T data, int off, word64 dest[2]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + // 32-bit cast is not a typo. Compiler workaround. + vec_xst((uint32x4_p)data, 0, NCONST_V32_CAST(addr)); +#else + VecStore_ALTIVEC((uint8x16_p)data, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param dest the byte array +/// \details VecStoreAligned() stores a vector from an aligned byte array. +/// \details VecStoreAligned() uses POWER9's vec_xl if available. +/// vec_st is used if POWER9 is not available. The effective +/// address of dest must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xst on POWER9 or above, vec_st on POWER8 and below +/// \sa VecStore_ALTIVEC, VecStore +/// \since Crypto++ 8.0 +template +inline void VecStoreAligned(const T data, byte dest[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#else + vec_st((uint8x16_p)data, 0, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest byte array +/// \param dest the byte array +/// \details VecStoreAligned() stores a vector from an aligned byte array. +/// \details VecStoreAligned() uses POWER9's vec_xl if available. +/// vec_st is used if POWER9 is not available. The effective +/// address of dest must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xst on POWER9 or above, vec_st on POWER8 and below +/// \sa VecStore_ALTIVEC, VecStore +/// \since Crypto++ 8.0 +template +inline void VecStoreAligned(const T data, int off, byte dest[16]) +{ + // Power7/ISA 2.06 provides vec_xl, but only for 32-bit and 64-bit + // word pointers. The ISA lacks loads for short* and char*. + // Power9/ISA 3.0 provides vec_xl for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#else + vec_st((uint8x16_p)data, 0, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param dest the word array +/// \details VecStoreAligned() stores a vector from an aligned word array. +/// \details VecStoreAligned() uses POWER9's vec_xl if available. +/// POWER7 vec_xst is used if POWER9 is not available. vec_st +/// is used if POWER7 is not available. The effective address of dest +/// must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, vec_st on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStore +/// \since Crypto++ 8.0 +template +inline void VecStoreAligned(const T data, word32 dest[4]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + vec_xst((uint32x4_p)data, 0, NCONST_V32_CAST(addr)); +#else + vec_st((uint8x16_p)data, 0, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest word array +/// \param dest the word array +/// \details VecStoreAligned() stores a vector from an aligned word array. +/// \details VecStoreAligned() uses POWER9's vec_xl if available. +/// POWER7 vec_xst is used if POWER9 is not available. vec_st +/// is used if POWER7 is not available. The effective address of dest +/// must be 16-byte aligned for Altivec. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, vec_st on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStore +/// \since Crypto++ 8.0 +template +inline void VecStoreAligned(const T data, int off, word32 dest[4]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#elif defined(__VSX__) || defined(_ARCH_PWR8) + vec_xst((uint32x4_p)data, 0, NCONST_V32_CAST(addr)); +#else + vec_st((uint8x16_p)data, 0, NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param dest the byte array +/// \details VecStoreBE() stores a vector to a byte array. VecStoreBE +/// will reverse all bytes in the array on a little endian system. +/// \details VecStoreBE() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 is not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, vec_st on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 6.0 +template +inline void VecStoreBE(const T data, byte dest[16]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst_be((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#elif defined(CRYPTOPP_BIG_ENDIAN) + VecStore((uint8x16_p)data, NCONST_V8_CAST(addr)); +#else + VecStore((uint8x16_p)VecReverseLE(data), NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a byte array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest byte array +/// \param dest the byte array +/// \details VecStoreBE() stores a vector to a byte array. VecStoreBE +/// will reverse all bytes in the array on a little endian system. +/// \details VecStoreBE() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 is not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, vec_st on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 6.0 +template +inline void VecStoreBE(const T data, int off, byte dest[16]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst_be((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#elif defined(CRYPTOPP_BIG_ENDIAN) + VecStore((uint8x16_p)data, NCONST_V8_CAST(addr)); +#else + VecStore((uint8x16_p)VecReverseLE(data), NCONST_V8_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param dest the word array +/// \details VecStoreBE() stores a vector to a word array. VecStoreBE +/// will reverse all bytes in the array on a little endian system. +/// \details VecStoreBE() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 is not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, vec_st on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStoreBE(const T data, word32 dest[4]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest); + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst_be((uint8x16_p)data, 0, NCONST_V8_CAST(dest)); +#elif defined(CRYPTOPP_BIG_ENDIAN) + VecStore((uint32x4_p)data, NCONST_V32_CAST(addr)); +#else + VecStore((uint32x4_p)VecReverseLE(data), NCONST_V32_CAST(addr)); +#endif +} + +/// \brief Stores a vector to a word array +/// \tparam T vector type +/// \param data the vector +/// \param off offset into the dest word array +/// \param dest the word array +/// \details VecStoreBE() stores a vector to a word array. VecStoreBE +/// will reverse all words in the array on a little endian system. +/// \details VecStoreBE() uses POWER7's and VSX's vec_xst if available. +/// The instruction does not require aligned effective memory addresses. +/// VecStore_ALTIVEC() is used if POWER7 is not available. +/// VecStore_ALTIVEC() can be relatively expensive if extra instructions +/// are required to fix up unaligned memory addresses. +/// \par Wraps +/// vec_xst on VSX or POWER8 and above, vec_st on POWER7 and below +/// \sa VecStore_ALTIVEC, VecStoreAligned +/// \since Crypto++ 8.0 +template +inline void VecStoreBE(const T data, int off, word32 dest[4]) +{ + // Power7/ISA 2.06 provides vec_xst, but only for 32-bit and 64-bit + // word pointers. The ISA lacks stores for short* and char*. + // Power9/ISA 3.0 provides vec_xst for all datatypes. + + const uintptr_t addr = reinterpret_cast(dest)+off; + CRYPTOPP_ASSERT(addr % GetAlignmentOf() == 0); + CRYPTOPP_UNUSED(addr); + +#if defined(_ARCH_PWR9) + vec_xst_be((uint8x16_p)data, off, NCONST_V8_CAST(dest)); +#elif defined(CRYPTOPP_BIG_ENDIAN) + VecStore((uint32x4_p)data, NCONST_V32_CAST(addr)); +#else + VecStore((uint32x4_p)VecReverseLE(data), NCONST_V32_CAST(addr)); +#endif +} + +//@} + +/// \name LOGICAL OPERATIONS +//@{ + +/// \brief AND two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecAnd() performs vec1 & vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \par Wraps +/// vec_and +/// \sa VecAnd64 +/// \since Crypto++ 6.0 +template +inline T1 VecAnd(const T1 vec1, const T2 vec2) +{ + return (T1)vec_and(vec1, (T1)vec2); +} + +/// \brief OR two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecOr() performs vec1 | vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \par Wraps +/// vec_or +/// \sa VecOr64 +/// \since Crypto++ 6.0 +template +inline T1 VecOr(const T1 vec1, const T2 vec2) +{ + return (T1)vec_or(vec1, (T1)vec2); +} + +/// \brief XOR two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecXor() performs vec1 ^ vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \par Wraps +/// vec_xor +/// \sa VecXor64 +/// \since Crypto++ 6.0 +template +inline T1 VecXor(const T1 vec1, const T2 vec2) +{ + return (T1)vec_xor(vec1, (T1)vec2); +} + +//@} + +/// \name ARITHMETIC OPERATIONS +//@{ + +/// \brief Add two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecAdd() performs vec1 + vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \par Wraps +/// vec_add +/// \sa VecAdd64 +/// \since Crypto++ 6.0 +template +inline T1 VecAdd(const T1 vec1, const T2 vec2) +{ + return (T1)vec_add(vec1, (T1)vec2); +} + +/// \brief Subtract two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \details VecSub() performs vec1 - vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \par Wraps +/// vec_sub +/// \sa VecSub64 +/// \since Crypto++ 6.0 +template +inline T1 VecSub(const T1 vec1, const T2 vec2) +{ + return (T1)vec_sub(vec1, (T1)vec2); +} + +//@} + +/// \name PERMUTE OPERATIONS +//@{ + +/// \brief Permutes a vector +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec the vector +/// \param mask vector mask +/// \return vector +/// \details VecPermute() creates a new vector from vec according to mask. +/// mask is an uint8x16_p vector. The return vector is the same type as vec. +/// \par Wraps +/// vec_perm +/// \since Crypto++ 6.0 +template +inline T1 VecPermute(const T1 vec, const T2 mask) +{ + return (T1)vec_perm(vec, vec, (uint8x16_p)mask); +} + +/// \brief Permutes two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \param mask vector mask +/// \return vector +/// \details VecPermute() creates a new vector from vec1 and vec2 according to mask. +/// mask is an uint8x16_p vector. The return vector is the same type as vec. +/// \par Wraps +/// vec_perm +/// \since Crypto++ 6.0 +template +inline T1 VecPermute(const T1 vec1, const T1 vec2, const T2 mask) +{ + return (T1)vec_perm(vec1, (T1)vec2, (uint8x16_p)mask); +} + +//@} + +/// \name SHIFT AND ROTATE OPERATIONS +//@{ + +/// \brief Shift a vector left +/// \tparam C shift byte count +/// \tparam T vector type +/// \param vec the vector +/// \return vector +/// \details VecShiftLeftOctet() returns a new vector after shifting the +/// concatenation of the zero vector and the source vector by the specified +/// number of bytes. The return vector is the same type as vec. +/// \details On big endian machines VecShiftLeftOctet() is vec_sld(a, z, +/// c). On little endian machines VecShiftLeftOctet() is translated to +/// vec_sld(z, a, 16-c). You should always call the function as +/// if on a big endian machine as shown below. +///
+///   uint8x16_p x = VecLoad(ptr);
+///   uint8x16_p y = VecShiftLeftOctet<12>(x);
+/// 
+/// \par Wraps +/// vec_sld +/// \sa Is vec_sld +/// endian sensitive? on Stack Overflow +/// \since Crypto++ 6.0 +template +inline T VecShiftLeftOctet(const T vec) +{ + const T zero = {0}; + if (C >= 16) + { + // Out of range + return zero; + } + else if (C == 0) + { + // Noop + return vec; + } + else + { +#if defined(CRYPTOPP_BIG_ENDIAN) + enum { R=C&0xf }; + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)zero, R); +#else + enum { R=(16-C)&0xf }; // Linux xlC 13.1 workaround in Debug builds + return (T)vec_sld((uint8x16_p)zero, (uint8x16_p)vec, R); +#endif + } +} + +/// \brief Shift a vector right +/// \tparam C shift byte count +/// \tparam T vector type +/// \param vec the vector +/// \return vector +/// \details VecShiftRightOctet() returns a new vector after shifting the +/// concatenation of the zero vector and the source vector by the specified +/// number of bytes. The return vector is the same type as vec. +/// \details On big endian machines VecShiftRightOctet() is vec_sld(a, z, +/// c). On little endian machines VecShiftRightOctet() is translated to +/// vec_sld(z, a, 16-c). You should always call the function as +/// if on a big endian machine as shown below. +///
+///   uint8x16_p x = VecLoad(ptr);
+///   uint8x16_p y = VecShiftRightOctet<12>(y);
+/// 
+/// \par Wraps +/// vec_sld +/// \sa Is vec_sld +/// endian sensitive? on Stack Overflow +/// \since Crypto++ 6.0 +template +inline T VecShiftRightOctet(const T vec) +{ + const T zero = {0}; + if (C >= 16) + { + // Out of range + return zero; + } + else if (C == 0) + { + // Noop + return vec; + } + else + { +#if defined(CRYPTOPP_BIG_ENDIAN) + enum { R=(16-C)&0xf }; // Linux xlC 13.1 workaround in Debug builds + return (T)vec_sld((uint8x16_p)zero, (uint8x16_p)vec, R); +#else + enum { R=C&0xf }; + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)zero, R); +#endif + } +} + +/// \brief Rotate a vector left +/// \tparam C shift byte count +/// \tparam T vector type +/// \param vec the vector +/// \return vector +/// \details VecRotateLeftOctet() returns a new vector after rotating the +/// concatenation of the source vector with itself by the specified +/// number of bytes. The return vector is the same type as vec. +/// \par Wraps +/// vec_sld +/// \sa Is vec_sld +/// endian sensitive? on Stack Overflow +/// \since Crypto++ 6.0 +template +inline T VecRotateLeftOctet(const T vec) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + enum { R = C&0xf }; + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)vec, R); +#else + enum { R=(16-C)&0xf }; // Linux xlC 13.1 workaround in Debug builds + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)vec, R); +#endif +} + +/// \brief Rotate a vector right +/// \tparam C shift byte count +/// \tparam T vector type +/// \param vec the vector +/// \return vector +/// \details VecRotateRightOctet() returns a new vector after rotating the +/// concatenation of the source vector with itself by the specified +/// number of bytes. The return vector is the same type as vec. +/// \par Wraps +/// vec_sld +/// \sa Is vec_sld +/// endian sensitive? on Stack Overflow +/// \since Crypto++ 6.0 +template +inline T VecRotateRightOctet(const T vec) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + enum { R=(16-C)&0xf }; // Linux xlC 13.1 workaround in Debug builds + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)vec, R); +#else + enum { R = C&0xf }; + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)vec, R); +#endif +} + +/// \brief Rotate a vector left +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateLeft() rotates each element in a vector by +/// bit count. The return vector is the same type as vec. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 7.0 +template +inline uint32x4_p VecRotateLeft(const uint32x4_p vec) +{ + const uint32x4_p m = {C, C, C, C}; + return vec_rl(vec, m); +} + +/// \brief Rotate a vector right +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateRight() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 7.0 +template +inline uint32x4_p VecRotateRight(const uint32x4_p vec) +{ + const uint32x4_p m = {32-C, 32-C, 32-C, 32-C}; + return vec_rl(vec, m); +} + +/// \brief Shift a vector left +/// \tparam C shift bit count +/// \param vec the vector +/// \return vector +/// \details VecShiftLeft() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \par Wraps +/// vec_sl +/// \since Crypto++ 8.1 +template +inline uint32x4_p VecShiftLeft(const uint32x4_p vec) +{ + const uint32x4_p m = {C, C, C, C}; + return vec_sl(vec, m); +} + +/// \brief Shift a vector right +/// \tparam C shift bit count +/// \param vec the vector +/// \return vector +/// \details VecShiftRight() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.1 +template +inline uint32x4_p VecShiftRight(const uint32x4_p vec) +{ + const uint32x4_p m = {C, C, C, C}; + return vec_sr(vec, m); +} + +// 64-bit elements available at POWER7 with VSX, but vec_rl and vec_sl require POWER8 +#if defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \brief Rotate a vector left +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateLeft() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \details VecRotateLeft() with 64-bit elements is available on +/// POWER8 and above. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.0 +template +inline uint64x2_p VecRotateLeft(const uint64x2_p vec) +{ + const uint64x2_p m = {C, C}; + return vec_rl(vec, m); +} + +/// \brief Shift a vector left +/// \tparam C shift bit count +/// \param vec the vector +/// \return vector +/// \details VecShiftLeft() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \details VecShiftLeft() with 64-bit elements is available on +/// POWER8 and above. +/// \par Wraps +/// vec_sl +/// \since Crypto++ 8.1 +template +inline uint64x2_p VecShiftLeft(const uint64x2_p vec) +{ + const uint64x2_p m = {C, C}; + return vec_sl(vec, m); +} + +/// \brief Rotate a vector right +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateRight() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \details VecRotateRight() with 64-bit elements is available on +/// POWER8 and above. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.0 +template +inline uint64x2_p VecRotateRight(const uint64x2_p vec) +{ + const uint64x2_p m = {64-C, 64-C}; + return vec_rl(vec, m); +} + +/// \brief Shift a vector right +/// \tparam C shift bit count +/// \param vec the vector +/// \return vector +/// \details VecShiftRight() rotates each element in a vector +/// by bit count. The return vector is the same type as vec. +/// \details VecShiftRight() with 64-bit elements is available on +/// POWER8 and above. +/// \par Wraps +/// vec_sr +/// \since Crypto++ 8.1 +template +inline uint64x2_p VecShiftRight(const uint64x2_p vec) +{ + const uint64x2_p m = {C, C}; + return vec_sr(vec, m); +} + +#endif // ARCH_PWR8 + +//@} + +/// \name OTHER OPERATIONS +//@{ + +/// \brief Merge two vectors +/// \tparam T vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \par Wraps +/// vec_mergel +/// \since Crypto++ 8.1 +template +inline T VecMergeLow(const T vec1, const T vec2) +{ + return vec_mergel(vec1, vec2); +} + +/// \brief Merge two vectors +/// \tparam T vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \par Wraps +/// vec_mergeh +/// \since Crypto++ 8.1 +template +inline T VecMergeHigh(const T vec1, const T vec2) +{ + return vec_mergeh(vec1, vec2); +} + +/// \brief Broadcast 32-bit word to a vector +/// \param val the 32-bit value +/// \return vector +/// \par Wraps +/// vec_splats +/// \since Crypto++ 8.3 +inline uint32x4_p VecSplatWord(word32 val) +{ + // Fix spurious GCC warning??? + CRYPTOPP_UNUSED(val); + + // Apple Altivec and XL C++ do not offer vec_splats. + // GCC offers vec_splats back to -mcpu=power4. +#if defined(_ARCH_PWR4) && defined(__GNUC__) + return vec_splats(val); +#else + //const word32 x[4] = {val,val,val,val}; + //return VecLoad(x); + const word32 x[4] = {val}; + return vec_splat(VecLoad(x),0); +#endif +} + +/// \brief Broadcast 32-bit element to a vector +/// \tparam the element number +/// \param val the 32-bit value +/// \return vector +/// \par Wraps +/// vec_splat +/// \since Crypto++ 8.3 +template +inline uint32x4_p VecSplatElement(const uint32x4_p val) +{ + return vec_splat(val, N); +} + +#if defined(__VSX__) || defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Broadcast 64-bit double word to a vector +/// \param val the 64-bit value +/// \return vector +/// \par Wraps +/// vec_splats +/// \since Crypto++ 8.3 +inline uint64x2_p VecSplatWord(word64 val) +{ + // The PPC64 ABI says so. + return vec_splats((unsigned long long)val); +} + +/// \brief Broadcast 64-bit element to a vector +/// \tparam the element number +/// \param val the 64-bit value +/// \return vector +/// \par Wraps +/// vec_splat +/// \since Crypto++ 8.3 +template +inline uint64x2_p VecSplatElement(const uint64x2_p val) +{ +#if defined(__VSX__) || defined(_ARCH_PWR8) + return vec_splat(val, N); +#else + enum {E=N&1}; + if (E == 0) + { + const uint8x16_p m = {0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7}; + return vec_perm(val, val, m); + } + else // (E == 1) + { + const uint8x16_p m = {8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15}; + return vec_perm(val, val, m); + } +#endif +} +#endif + +/// \brief Extract a dword from a vector +/// \tparam T vector type +/// \param val the vector +/// \return vector created from low dword +/// \details VecGetLow() extracts the low dword from a vector. The low dword +/// is composed of the least significant bits and occupies bytes 8 through 15 +/// when viewed as a big endian array. The return vector is the same type as +/// the original vector and padded with 0's in the most significant bit positions. +/// \par Wraps +/// vec_sld +/// \since Crypto++ 7.0 +template +inline T VecGetLow(const T val) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) && (defined(__VSX__) || defined(_ARCH_PWR8)) + const T zero = {0}; + return (T)VecMergeLow((uint64x2_p)zero, (uint64x2_p)val); +#else + return VecShiftRightOctet<8>(VecShiftLeftOctet<8>(val)); +#endif +} + +/// \brief Extract a dword from a vector +/// \tparam T vector type +/// \param val the vector +/// \return vector created from high dword +/// \details VecGetHigh() extracts the high dword from a vector. The high dword +/// is composed of the most significant bits and occupies bytes 0 through 7 +/// when viewed as a big endian array. The return vector is the same type as +/// the original vector and padded with 0's in the most significant bit positions. +/// \par Wraps +/// vec_sld +/// \since Crypto++ 7.0 +template +inline T VecGetHigh(const T val) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) && (defined(__VSX__) || defined(_ARCH_PWR8)) + const T zero = {0}; + return (T)VecMergeHigh((uint64x2_p)zero, (uint64x2_p)val); +#else + return VecShiftRightOctet<8>(val); +#endif +} + +/// \brief Exchange high and low double words +/// \tparam T vector type +/// \param vec the vector +/// \return vector +/// \par Wraps +/// vec_sld +/// \since Crypto++ 7.0 +template +inline T VecSwapWords(const T vec) +{ + return (T)vec_sld((uint8x16_p)vec, (uint8x16_p)vec, 8); +} + +//@} + +/// \name COMPARISON +//@{ + +/// \brief Compare two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return true if vec1 equals vec2, false otherwise +/// \details VecEqual() performs a bitwise compare. The vector element types do +/// not matter. +/// \par Wraps +/// vec_all_eq +/// \since Crypto++ 8.0 +template +inline bool VecEqual(const T1 vec1, const T2 vec2) +{ + return 1 == vec_all_eq((uint32x4_p)vec1, (uint32x4_p)vec2); +} + +/// \brief Compare two vectors +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return true if vec1 does not equal vec2, false otherwise +/// \details VecNotEqual() performs a bitwise compare. The vector element types do +/// not matter. +/// \par Wraps +/// vec_all_eq +/// \since Crypto++ 8.0 +template +inline bool VecNotEqual(const T1 vec1, const T2 vec2) +{ + return 0 == vec_all_eq((uint32x4_p)vec1, (uint32x4_p)vec2); +} + +//@} + +////////////////// 32-bit Altivec ///////////////// + +/// \name 32-BIT ALTIVEC +//@{ + +/// \brief Add two vectors as if uint64x2_p +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecAdd64() performs vec1 + vec2. VecAdd64() performs as +/// if adding two uint64x2_p vectors. On POWER7 and below VecAdd64() manages +/// the carries from the elements. +/// \par Wraps +/// vec_add for POWER8, vec_addc, vec_perm, vec_add for Altivec +/// \since Crypto++ 8.3 +inline uint32x4_p VecAdd64(const uint32x4_p& vec1, const uint32x4_p& vec2) +{ + // 64-bit elements available at POWER7 with VSX, but addudm requires POWER8 +#if defined(_ARCH_PWR8) && !defined(CRYPTOPP_DEBUG) + return (uint32x4_p)vec_add((uint64x2_p)vec1, (uint64x2_p)vec2); +#else + // The carry mask selects carrys for elements 1 and 3 and sets + // remaining elements to 0. The results is then shifted so the + // carried values are added to elements 0 and 2. +#if defined(CRYPTOPP_BIG_ENDIAN) + const uint32x4_p zero = {0, 0, 0, 0}; + const uint32x4_p mask = {0, 1, 0, 1}; +#else + const uint32x4_p zero = {0, 0, 0, 0}; + const uint32x4_p mask = {1, 0, 1, 0}; +#endif + + uint32x4_p cy = vec_addc(vec1, vec2); + uint32x4_p res = vec_add(vec1, vec2); + cy = vec_and(mask, cy); + cy = vec_sld (cy, zero, 4); + return vec_add(res, cy); +#endif +} + +#if defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Add two vectors as if uint64x2_p +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecAdd64() performs vec1 + vec2. VecAdd64() performs as +/// if adding two uint64x2_p vectors. On POWER7 and below VecAdd64() manages +/// the carries from the elements. +/// \par Wraps +/// vec_add for POWER8 +/// \since Crypto++ 8.3 +inline uint64x2_p VecAdd64(const uint64x2_p& vec1, const uint64x2_p& vec2) +{ + // 64-bit elements available at POWER7 with VSX, but addudm requires POWER8 + const uint64x2_p res = vec_add(vec1, vec2); + +#if defined(CRYPTOPP_DEBUG) + // Test 32-bit add in debug builds while we are here. + const uint32x4_p x = (uint32x4_p)vec1; + const uint32x4_p y = (uint32x4_p)vec2; + const uint32x4_p r = VecAdd64(x, y); + + CRYPTOPP_ASSERT(vec_all_eq((uint32x4_p)res, r) == 1); +#endif + + return res; +} +#endif + +/// \brief Subtract two vectors as if uint64x2_p +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \details VecSub64() performs vec1 - vec2. VecSub64() performs as +/// if subtracting two uint64x2_p vectors. On POWER7 and below VecSub64() +/// manages the borrows from the elements. +/// \par Wraps +/// vec_sub for POWER8, vec_subc, vec_andc, vec_perm, vec_sub for Altivec +/// \since Crypto++ 8.3 +inline uint32x4_p VecSub64(const uint32x4_p& vec1, const uint32x4_p& vec2) +{ +#if defined(_ARCH_PWR8) && !defined(CRYPTOPP_DEBUG) + // 64-bit elements available at POWER7 with VSX, but subudm requires POWER8 + return (uint32x4_p)vec_sub((uint64x2_p)vec1, (uint64x2_p)vec2); +#else + // The borrow mask selects borrows for elements 1 and 3 and sets + // remaining elements to 0. The results is then shifted so the + // borrowed values are subtracted from elements 0 and 2. +#if defined(CRYPTOPP_BIG_ENDIAN) + const uint32x4_p zero = {0, 0, 0, 0}; + const uint32x4_p mask = {0, 1, 0, 1}; +#else + const uint32x4_p zero = {0, 0, 0, 0}; + const uint32x4_p mask = {1, 0, 1, 0}; +#endif + + // subc sets the complement of borrow, so we have to + // un-complement it using andc. + uint32x4_p bw = vec_subc(vec1, vec2); + uint32x4_p res = vec_sub(vec1, vec2); + bw = vec_andc(mask, bw); + bw = vec_sld (bw, zero, 4); + return vec_sub(res, bw); +#endif +} + +#if defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Subtract two vectors as if uint64x2_p +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \details VecSub64() performs vec1 - vec2. VecSub64() performs as +/// if subtracting two uint64x2_p vectors. On POWER7 and below VecSub64() +/// manages the borrows from the elements. +/// \par Wraps +/// vec_sub for POWER8 +/// \since Crypto++ 8.3 +inline uint64x2_p VecSub64(const uint64x2_p& vec1, const uint64x2_p& vec2) +{ + // 64-bit elements available at POWER7 with VSX, but subudm requires POWER8 + const uint64x2_p res = vec_sub(vec1, vec2); + +#if defined(CRYPTOPP_DEBUG) + // Test 32-bit sub in debug builds while we are here. + const uint32x4_p x = (uint32x4_p)vec1; + const uint32x4_p y = (uint32x4_p)vec2; + const uint32x4_p r = VecSub64(x, y); + + CRYPTOPP_ASSERT(vec_all_eq((uint32x4_p)res, r) == 1); +#endif + + return res; +} +#endif + +/// \brief Rotate a vector left as if uint64x2_p +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateLeft() rotates each element in a vector by bit count. +/// vec is rotated as if uint64x2_p. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.3 +template +inline uint32x4_p VecRotateLeft64(const uint32x4_p vec) +{ +#if defined(_ARCH_PWR8) && !defined(CRYPTOPP_DEBUG) + // 64-bit elements available at POWER7 with VSX, but vec_rl and vec_sl require POWER8 + return (uint32x4_p)VecRotateLeft((uint64x2_p)vec); +#else + // C=0, 32, or 64 needs special handling. That is S32 and S64 below. + enum {S64=C&63, S32=C&31, BR=(S64>=32)}; + + // Get the low bits, shift them to high bits + uint32x4_p t1 = VecShiftLeft(vec); + // Get the high bits, shift them to low bits + uint32x4_p t2 = VecShiftRight<32-S32>(vec); + + if (S64 == 0) + { + const uint8x16_p m = {0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15}; + return VecPermute(vec, m); + } + else if (S64 == 32) + { + const uint8x16_p m = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + return VecPermute(vec, m); + } + else if (BR) // Big rotate amount? + { + const uint8x16_p m = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + t1 = VecPermute(t1, m); + } + else + { + const uint8x16_p m = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + t2 = VecPermute(t2, m); + } + + return vec_or(t1, t2); +#endif +} + +/// \brief Rotate a vector left as if uint64x2_p +/// \param vec the vector +/// \return vector +/// \details VecRotateLeft<8>() rotates each element in a vector +/// by 8-bits. vec is rotated as if uint64x2_p. This specialization +/// is used by algorithms like Speck128. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.3 +template<> +inline uint32x4_p VecRotateLeft64<8>(const uint32x4_p vec) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m = { 1,2,3,4, 5,6,7,0, 9,10,11,12, 13,14,15,8 }; + return VecPermute(vec, m); +#else + const uint8x16_p m = { 7,0,1,2, 3,4,5,6, 15,8,9,10, 11,12,13,14 }; + return VecPermute(vec, m); +#endif +} + +#if defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Rotate a vector left as if uint64x2_p +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateLeft64() rotates each element in a vector by +/// bit count. vec is rotated as if uint64x2_p. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.3 +template +inline uint64x2_p VecRotateLeft64(const uint64x2_p vec) +{ + // 64-bit elements available at POWER7 with VSX, but vec_rl and vec_sl require POWER8 + const uint64x2_p res = VecRotateLeft(vec); + +#if defined(CRYPTOPP_DEBUG) + // Test 32-bit rotate in debug builds while we are here. + const uint32x4_p x = (uint32x4_p)vec; + const uint32x4_p r = VecRotateLeft64(x); + + CRYPTOPP_ASSERT(vec_all_eq((uint32x4_p)res, r) == 1); +#endif + + return res; +} +#endif + +/// \brief Rotate a vector right as if uint64x2_p +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateRight64() rotates each element in a vector by +/// bit count. vec is rotated as if uint64x2_p. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.3 +template +inline uint32x4_p VecRotateRight64(const uint32x4_p vec) +{ +#if defined(_ARCH_PWR8) && !defined(CRYPTOPP_DEBUG) + // 64-bit elements available at POWER7 with VSX, but vec_rl and vec_sl require POWER8 + return (uint32x4_p)VecRotateRight((uint64x2_p)vec); +#else + // C=0, 32, or 64 needs special handling. That is S32 and S64 below. + enum {S64=C&63, S32=C&31, BR=(S64>=32)}; + + // Get the low bits, shift them to high bits + uint32x4_p t1 = VecShiftRight(vec); + // Get the high bits, shift them to low bits + uint32x4_p t2 = VecShiftLeft<32-S32>(vec); + + if (S64 == 0) + { + const uint8x16_p m = {0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15}; + return VecPermute(vec, m); + } + else if (S64 == 32) + { + const uint8x16_p m = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + return VecPermute(vec, m); + } + else if (BR) // Big rotate amount? + { + const uint8x16_p m = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + t1 = VecPermute(t1, m); + } + else + { + const uint8x16_p m = {4,5,6,7, 0,1,2,3, 12,13,14,15, 8,9,10,11}; + t2 = VecPermute(t2, m); + } + + return vec_or(t1, t2); +#endif +} + +/// \brief Rotate a vector right as if uint64x2_p +/// \param vec the vector +/// \return vector +/// \details VecRotateRight64<8>() rotates each element in a vector +/// by 8-bits. vec is rotated as if uint64x2_p. This specialization +/// is used by algorithms like Speck128. +/// \details vec is rotated as if uint64x2_p. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.3 +template<> +inline uint32x4_p VecRotateRight64<8>(const uint32x4_p vec) +{ +#if (CRYPTOPP_BIG_ENDIAN) + const uint8x16_p m = { 7,0,1,2, 3,4,5,6, 15,8,9,10, 11,12,13,14 }; + return VecPermute(vec, m); +#else + const uint8x16_p m = { 1,2,3,4, 5,6,7,0, 9,10,11,12, 13,14,15,8 }; + return VecPermute(vec, m); +#endif +} + +#if defined(__VSX__) || defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Rotate a vector right as if uint64x2_p +/// \tparam C rotate bit count +/// \param vec the vector +/// \return vector +/// \details VecRotateRight64() rotates each element in a vector by +/// bit count. vec is rotated as if uint64x2_p. +/// \par Wraps +/// vec_rl +/// \since Crypto++ 8.3 +template +inline uint64x2_p VecRotateRight64(const uint64x2_p vec) +{ + // 64-bit elements available at POWER7 with VSX, but vec_rl and vec_sl require POWER8 + const uint64x2_p res = VecRotateRight(vec); + +#if defined(CRYPTOPP_DEBUG) + // Test 32-bit rotate in debug builds while we are here. + const uint32x4_p x = (uint32x4_p)vec; + const uint32x4_p r = VecRotateRight64(x); + + CRYPTOPP_ASSERT(vec_all_eq((uint32x4_p)res, r) == 1); +#endif + + return res; +} +#endif + +/// \brief AND two vectors as if uint64x2_p +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecAnd64() performs vec1 & vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \details VecAnd64() is a convenience function that simply performs a VecAnd(). +/// \par Wraps +/// vec_and +/// \since Crypto++ 8.3 +template +inline T1 VecAnd64(const T1 vec1, const T2 vec2) +{ + return (T1)vec_and(vec1, (T1)vec2); +} + +/// \brief OR two vectors as if uint64x2_p +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecOr64() performs vec1 | vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \details VecOr64() is a convenience function that simply performs a VecOr(). +/// \par Wraps +/// vec_or +/// \since Crypto++ 8.3 +template +inline T1 VecOr64(const T1 vec1, const T2 vec2) +{ + return (T1)vec_or(vec1, (T1)vec2); +} + +/// \brief XOR two vectors as if uint64x2_p +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param vec1 the first vector +/// \param vec2 the second vector +/// \return vector +/// \details VecXor64() performs vec1 ^ vec2. +/// vec2 is cast to the same type as vec1. The return vector +/// is the same type as vec1. +/// \details VecXor64() is a convenience function that simply performs a VecXor(). +/// \par Wraps +/// vec_xor +/// \since Crypto++ 8.3 +template +inline T1 VecXor64(const T1 vec1, const T2 vec2) +{ + return (T1)vec_xor(vec1, (T1)vec2); +} + +/// \brief Broadcast 64-bit double word to a vector +/// \param val the 64-bit value +/// \return vector +/// \par Wraps +/// vec_splats +/// \since Crypto++ 8.3 +inline uint32x4_p VecSplatWord64(word64 val) +{ +#if defined(_ARCH_PWR8) + // The PPC64 ABI says so. + return (uint32x4_p)vec_splats((unsigned long long)val); +#else + const word64 x[2] = {val,val}; + return (uint32x4_p)VecLoad((const word32*)x); +#endif +} + +/// \brief Broadcast 64-bit element to a vector as if uint64x2_p +/// \tparam the element number +/// \param val the 64-bit value +/// \return vector +/// \par Wraps +/// vec_splat +/// \since Crypto++ 8.3 +template +inline uint32x4_p VecSplatElement64(const uint32x4_p val) +{ +#if defined(__VSX__) || defined(_ARCH_PWR8) + return (uint32x4_p)vec_splat((uint64x2_p)val, N); +#else + enum {E=N&1}; + if (E == 0) + { + const uint8x16_p m = {0,1,2,3, 4,5,6,7, 0,1,2,3, 4,5,6,7}; + return (uint32x4_p)vec_perm(val, val, m); + } + else // (E == 1) + { + const uint8x16_p m = {8,9,10,11, 12,13,14,15, 8,9,10,11, 12,13,14,15}; + return (uint32x4_p)vec_perm(val, val, m); + } +#endif +} + +#if defined(__VSX__) || defined(_ARCH_PWR8) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Broadcast 64-bit element to a vector +/// \tparam the element number +/// \param val the 64-bit value +/// \return vector +/// \since Crypto++ 8.3 +template +inline uint64x2_p VecSplatElement64(const uint64x2_p val) +{ + return vec_splat(val, N); +} +#endif + +//@} + +//////////////////////// Power8 Crypto //////////////////////// + +// __CRYPTO__ alone is not enough. Clang will define __CRYPTO__ +// when it is not available, like with Power7. Sigh... +#if (defined(_ARCH_PWR8) && defined(__CRYPTO__)) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + +/// \name POLYNOMIAL MULTIPLICATION +//@{ + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details VecPolyMultiply() performs polynomial multiplication. POWER8 +/// polynomial multiplication multiplies the high and low terms, and then +/// XOR's the high and low products. That is, the result is ah*bh XOR +/// al*bl. It is different behavior than Intel polynomial +/// multiplication. To obtain a single product without the XOR, then set +/// one of the high or low terms to 0. For example, setting ah=0 +/// results in 0*bh XOR al*bl = al*bl. +/// \par Wraps +/// __vpmsumw, __builtin_altivec_crypto_vpmsumw and __builtin_crypto_vpmsumw. +/// \since Crypto++ 8.1 +inline uint32x4_p VecPolyMultiply(const uint32x4_p& a, const uint32x4_p& b) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return __vpmsumw (a, b); +#elif defined(__clang__) + return __builtin_altivec_crypto_vpmsumw (a, b); +#else + return __builtin_crypto_vpmsumw (a, b); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details VecPolyMultiply() performs polynomial multiplication. POWER8 +/// polynomial multiplication multiplies the high and low terms, and then +/// XOR's the high and low products. That is, the result is ah*bh XOR +/// al*bl. It is different behavior than Intel polynomial +/// multiplication. To obtain a single product without the XOR, then set +/// one of the high or low terms to 0. For example, setting ah=0 +/// results in 0*bh XOR al*bl = al*bl. +/// \par Wraps +/// __vpmsumd, __builtin_altivec_crypto_vpmsumd and __builtin_crypto_vpmsumd. +/// \since Crypto++ 8.1 +inline uint64x2_p VecPolyMultiply(const uint64x2_p& a, const uint64x2_p& b) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return __vpmsumd (a, b); +#elif defined(__clang__) + return __builtin_altivec_crypto_vpmsumd (a, b); +#else + return __builtin_crypto_vpmsumd (a, b); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details VecIntelMultiply00() performs polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x00). +/// The 0x00 indicates the low 64-bits of a and b +/// are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the rightmost bit is LSB and numbered 0. +/// \par Wraps +/// __vpmsumd, __builtin_altivec_crypto_vpmsumd and __builtin_crypto_vpmsumd. +/// \since Crypto++ 8.0 +inline uint64x2_p VecIntelMultiply00(const uint64x2_p& a, const uint64x2_p& b) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + return VecSwapWords(VecPolyMultiply(VecGetHigh(a), VecGetHigh(b))); +#else + return VecPolyMultiply(VecGetHigh(a), VecGetHigh(b)); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details VecIntelMultiply01 performs() polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x01). +/// The 0x01 indicates the low 64-bits of a and high +/// 64-bits of b are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the rightmost bit is LSB and numbered 0. +/// \par Wraps +/// __vpmsumd, __builtin_altivec_crypto_vpmsumd and __builtin_crypto_vpmsumd. +/// \since Crypto++ 8.0 +inline uint64x2_p VecIntelMultiply01(const uint64x2_p& a, const uint64x2_p& b) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + return VecSwapWords(VecPolyMultiply(a, VecGetHigh(b))); +#else + return VecPolyMultiply(a, VecGetHigh(b)); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details VecIntelMultiply10() performs polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x10). +/// The 0x10 indicates the high 64-bits of a and low +/// 64-bits of b are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the rightmost bit is LSB and numbered 0. +/// \par Wraps +/// __vpmsumd, __builtin_altivec_crypto_vpmsumd and __builtin_crypto_vpmsumd. +/// \since Crypto++ 8.0 +inline uint64x2_p VecIntelMultiply10(const uint64x2_p& a, const uint64x2_p& b) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + return VecSwapWords(VecPolyMultiply(VecGetHigh(a), b)); +#else + return VecPolyMultiply(VecGetHigh(a), b); +#endif +} + +/// \brief Polynomial multiplication +/// \param a the first term +/// \param b the second term +/// \return vector product +/// \details VecIntelMultiply11() performs polynomial multiplication and presents +/// the result like Intel's c = _mm_clmulepi64_si128(a, b, 0x11). +/// The 0x11 indicates the high 64-bits of a and b +/// are multiplied. +/// \note An Intel XMM register is composed of 128-bits. The leftmost bit +/// is MSB and numbered 127, while the rightmost bit is LSB and numbered 0. +/// \par Wraps +/// __vpmsumd, __builtin_altivec_crypto_vpmsumd and __builtin_crypto_vpmsumd. +/// \since Crypto++ 8.0 +inline uint64x2_p VecIntelMultiply11(const uint64x2_p& a, const uint64x2_p& b) +{ +#if defined(CRYPTOPP_BIG_ENDIAN) + return VecSwapWords(VecPolyMultiply(VecGetLow(a), b)); +#else + return VecPolyMultiply(VecGetLow(a), b); +#endif +} + +//@} + +/// \name AES ENCRYPTION +//@{ + +/// \brief One round of AES encryption +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param state the state vector +/// \param key the subkey vector +/// \details VecEncrypt() performs one round of AES encryption of state +/// using subkey key. The return vector is the same type as state. +/// \details VecEncrypt() is available on POWER8 and above. +/// \par Wraps +/// __vcipher, __builtin_altivec_crypto_vcipher, __builtin_crypto_vcipher +/// \since GCC and XLC since Crypto++ 6.0, LLVM Clang since Crypto++ 8.0 +template +inline T1 VecEncrypt(const T1 state, const T2 key) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return (T1)__vcipher((uint8x16_p)state, (uint8x16_p)key); +#elif defined(__clang__) + return (T1)__builtin_altivec_crypto_vcipher((uint64x2_p)state, (uint64x2_p)key); +#elif defined(__GNUC__) + return (T1)__builtin_crypto_vcipher((uint64x2_p)state, (uint64x2_p)key); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief Final round of AES encryption +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param state the state vector +/// \param key the subkey vector +/// \details VecEncryptLast() performs the final round of AES encryption +/// of state using subkey key. The return vector is the same type as state. +/// \details VecEncryptLast() is available on POWER8 and above. +/// \par Wraps +/// __vcipherlast, __builtin_altivec_crypto_vcipherlast, __builtin_crypto_vcipherlast +/// \since GCC and XLC since Crypto++ 6.0, LLVM Clang since Crypto++ 8.0 +template +inline T1 VecEncryptLast(const T1 state, const T2 key) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return (T1)__vcipherlast((uint8x16_p)state, (uint8x16_p)key); +#elif defined(__clang__) + return (T1)__builtin_altivec_crypto_vcipherlast((uint64x2_p)state, (uint64x2_p)key); +#elif defined(__GNUC__) + return (T1)__builtin_crypto_vcipherlast((uint64x2_p)state, (uint64x2_p)key); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief One round of AES decryption +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param state the state vector +/// \param key the subkey vector +/// \details VecDecrypt() performs one round of AES decryption of state +/// using subkey key. The return vector is the same type as state. +/// \details VecDecrypt() is available on POWER8 and above. +/// \par Wraps +/// __vncipher, __builtin_altivec_crypto_vncipher, __builtin_crypto_vncipher +/// \since GCC and XLC since Crypto++ 6.0, LLVM Clang since Crypto++ 8.0 +template +inline T1 VecDecrypt(const T1 state, const T2 key) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return (T1)__vncipher((uint8x16_p)state, (uint8x16_p)key); +#elif defined(__clang__) + return (T1)__builtin_altivec_crypto_vncipher((uint64x2_p)state, (uint64x2_p)key); +#elif defined(__GNUC__) + return (T1)__builtin_crypto_vncipher((uint64x2_p)state, (uint64x2_p)key); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief Final round of AES decryption +/// \tparam T1 vector type +/// \tparam T2 vector type +/// \param state the state vector +/// \param key the subkey vector +/// \details VecDecryptLast() performs the final round of AES decryption +/// of state using subkey key. The return vector is the same type as state. +/// \details VecDecryptLast() is available on POWER8 and above. +/// \par Wraps +/// __vncipherlast, __builtin_altivec_crypto_vncipherlast, __builtin_crypto_vncipherlast +/// \since GCC and XLC since Crypto++ 6.0, LLVM Clang since Crypto++ 8.0 +template +inline T1 VecDecryptLast(const T1 state, const T2 key) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return (T1)__vncipherlast((uint8x16_p)state, (uint8x16_p)key); +#elif defined(__clang__) + return (T1)__builtin_altivec_crypto_vncipherlast((uint64x2_p)state, (uint64x2_p)key); +#elif defined(__GNUC__) + return (T1)__builtin_crypto_vncipherlast((uint64x2_p)state, (uint64x2_p)key); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +//@} + +/// \name SHA DIGESTS +//@{ + +/// \brief SHA256 Sigma functions +/// \tparam func function +/// \tparam fmask function mask +/// \tparam T vector type +/// \param data the block to transform +/// \details VecSHA256() selects sigma0, sigma1, Sigma0, Sigma1 based on +/// func and fmask. The return vector is the same type as data. +/// \details VecSHA256() is available on POWER8 and above. +/// \par Wraps +/// __vshasigmaw, __builtin_altivec_crypto_vshasigmaw, __builtin_crypto_vshasigmaw +/// \since GCC and XLC since Crypto++ 6.0, LLVM Clang since Crypto++ 8.0 +template +inline T VecSHA256(const T data) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return (T)__vshasigmaw((uint32x4_p)data, func, fmask); +#elif defined(__clang__) + return (T)__builtin_altivec_crypto_vshasigmaw((uint32x4_p)data, func, fmask); +#elif defined(__GNUC__) + return (T)__builtin_crypto_vshasigmaw((uint32x4_p)data, func, fmask); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +/// \brief SHA512 Sigma functions +/// \tparam func function +/// \tparam fmask function mask +/// \tparam T vector type +/// \param data the block to transform +/// \details VecSHA512() selects sigma0, sigma1, Sigma0, Sigma1 based on +/// func and fmask. The return vector is the same type as data. +/// \details VecSHA512() is available on POWER8 and above. +/// \par Wraps +/// __vshasigmad, __builtin_altivec_crypto_vshasigmad, __builtin_crypto_vshasigmad +/// \since GCC and XLC since Crypto++ 6.0, LLVM Clang since Crypto++ 8.0 +template +inline T VecSHA512(const T data) +{ +#if defined(__ibmxl__) || (defined(_AIX) && defined(__xlC__)) + return (T)__vshasigmad((uint64x2_p)data, func, fmask); +#elif defined(__clang__) + return (T)__builtin_altivec_crypto_vshasigmad((uint64x2_p)data, func, fmask); +#elif defined(__GNUC__) + return (T)__builtin_crypto_vshasigmad((uint64x2_p)data, func, fmask); +#else + CRYPTOPP_ASSERT(0); +#endif +} + +//@} + +#endif // __CRYPTO__ + +#endif // _ALTIVEC_ + +NAMESPACE_END + +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif // CRYPTOPP_PPC_CRYPTO_H diff --git a/third_party/cryptoppwin/include/cryptopp/pssr.h b/third_party/cryptoppwin/include/cryptopp/pssr.h new file mode 100644 index 00000000..46386227 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/pssr.h @@ -0,0 +1,105 @@ +// pssr.h - originally written and placed in the public domain by Wei Dai + +/// \file pssr.h +/// \brief Classes for probabilistic signature schemes +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_PSSR_H +#define CRYPTOPP_PSSR_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "emsa2.h" + +#ifdef CRYPTOPP_IS_DLL +#include "sha.h" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief PSSR Message Encoding Method interface +/// \since Crypto++ 2.1 +class CRYPTOPP_DLL PSSR_MEM_Base : public PK_RecoverableSignatureMessageEncodingMethod +{ +public: + virtual ~PSSR_MEM_Base() {} + +protected: + virtual bool AllowRecovery() const =0; + virtual size_t SaltLen(size_t hashLen) const =0; + virtual size_t MinPadLen(size_t hashLen) const =0; + virtual const MaskGeneratingFunction & GetMGF() const =0; + +private: + size_t MinRepresentativeBitLength(size_t hashIdentifierLength, size_t digestLength) const; + size_t MaxRecoverableLength(size_t representativeBitLength, size_t hashIdentifierLength, size_t digestLength) const; + bool IsProbabilistic() const; + bool AllowNonrecoverablePart() const; + bool RecoverablePartFirst() const; + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; + DecodingResult RecoverMessageFromRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength, + byte *recoverableMessage) const; +}; + +/// \brief PSSR Message Encoding Method with Hash Identifier +/// \tparam USE_HASH_ID flag indicating whether the HashId is used +/// \since Crypto++ 2.1 +template class PSSR_MEM_BaseWithHashId; + +/// \brief PSSR Message Encoding Method with Hash Identifier +/// \details If USE_HASH_ID is true, then EMSA2HashIdLookup is used for the base class +template<> class PSSR_MEM_BaseWithHashId : public EMSA2HashIdLookup {}; + +/// \brief PSSR Message Encoding Method without Hash Identifier +/// \details If USE_HASH_ID is false, then PSSR_MEM_Base is used for the base class +/// \since Crypto++ 2.1 +template<> class PSSR_MEM_BaseWithHashId : public PSSR_MEM_Base {}; + +/// \brief PSSR Message Encoding Method +/// \tparam ALLOW_RECOVERY flag indicating whether the scheme provides message recovery +/// \tparam MGF mask generation function +/// \tparam SALT_LEN length of the salt +/// \tparam MIN_PAD_LEN minimum length of the pad +/// \tparam USE_HASH_ID flag indicating whether the HashId is used +/// \details If ALLOW_RECOVERY is true, the signature scheme provides message recovery. If +/// ALLOW_RECOVERY is false, the signature scheme is appendix, and the message must be +/// provided during verification. +/// \since Crypto++ 2.1 +template +class PSSR_MEM : public PSSR_MEM_BaseWithHashId +{ + virtual bool AllowRecovery() const {return ALLOW_RECOVERY;} + virtual size_t SaltLen(size_t hashLen) const {return SALT_LEN < 0 ? hashLen : SALT_LEN;} + virtual size_t MinPadLen(size_t hashLen) const {return MIN_PAD_LEN < 0 ? hashLen : MIN_PAD_LEN;} + virtual const MaskGeneratingFunction & GetMGF() const {static MGF mgf; return mgf;} + +public: + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string(ALLOW_RECOVERY ? "PSSR-" : "PSS-") + MGF::StaticAlgorithmName();} +}; + +/// \brief Probabilistic Signature Scheme with Recovery +/// \details Signature Schemes with Recovery encode the message with the signature. +/// \sa PSSR-MGF1 +/// \since Crypto++ 2.1 +struct PSSR : public SignatureStandard +{ + typedef PSSR_MEM SignatureMessageEncodingMethod; +}; + +/// \brief Probabilistic Signature Scheme with Appendix +/// \details Signature Schemes with Appendix require the message to be provided during verification. +/// \sa PSS-MGF1 +/// \since Crypto++ 2.1 +struct PSS : public SignatureStandard +{ + typedef PSSR_MEM SignatureMessageEncodingMethod; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/pubkey.h b/third_party/cryptoppwin/include/cryptopp/pubkey.h new file mode 100644 index 00000000..bdfeef42 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/pubkey.h @@ -0,0 +1,2378 @@ +// pubkey.h - originally written and placed in the public domain by Wei Dai + +/// \file pubkey.h +/// \brief This file contains helper classes/functions for implementing public key algorithms. +/// \details The class hierarchies in this header file tend to look like this: +/// +///
+///                   x1
+///                  +--+
+///                  |  |
+///                 y1  z1
+///                  |  |
+///             x2  x2
+///                  |  |
+///                 y2  z2
+///                  |  |
+///             x3  x3
+///                  |  |
+///                 y3  z3
+/// 
+/// +///
    +///
  • x1, y1, z1 are abstract interface classes defined in cryptlib.h +///
  • x2, y2, z2 are implementations of the interfaces using "abstract policies", which +/// are pure virtual functions that should return interfaces to interchangeable algorithms. +/// These classes have Base suffixes. +///
  • x3, y3, z3 hold actual algorithms and implement those virtual functions. +/// These classes have Impl suffixes. +///
+/// +/// \details The TF_ prefix means an implementation using trapdoor functions on integers. +/// \details The DL_ prefix means an implementation using group operations in groups where discrete log is hard. + +#ifndef CRYPTOPP_PUBKEY_H +#define CRYPTOPP_PUBKEY_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4702) +#endif + +#include "cryptlib.h" +#include "integer.h" +#include "algebra.h" +#include "modarith.h" +#include "filters.h" +#include "eprecomp.h" +#include "fips140.h" +#include "argnames.h" +#include "smartptr.h" +#include "stdcpp.h" + +#if defined(__SUNPRO_CC) +# define MAYBE_RETURN(x) return x +#else +# define MAYBE_RETURN(x) CRYPTOPP_UNUSED(x) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Provides range for plaintext and ciphertext lengths +/// \details A trapdoor function is a function that is easy to compute in one direction, +/// but difficult to compute in the opposite direction without special knowledge. +/// The special knowledge is usually the private key. +/// \details Trapdoor functions only handle messages of a limited length or size. +/// MaxPreimage is the plaintext's maximum length, and MaxImage is the +/// ciphertext's maximum length. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TrapdoorFunctionBounds +{ +public: + virtual ~TrapdoorFunctionBounds() {} + + /// \brief Returns the maximum size of a message before the trapdoor function is applied + /// \return the maximum size of a message before the trapdoor function is applied + /// \details Derived classes must implement PreimageBound(). + virtual Integer PreimageBound() const =0; + /// \brief Returns the maximum size of a representation after the trapdoor function is applied + /// \return the maximum size of a representation after the trapdoor function is applied + /// \details Derived classes must implement ImageBound(). + virtual Integer ImageBound() const =0; + /// \brief Returns the maximum size of a message before the trapdoor function is applied bound to a public key + /// \return the maximum size of a message before the trapdoor function is applied bound to a public key + /// \details The default implementation returns PreimageBound() - 1. + virtual Integer MaxPreimage() const {return --PreimageBound();} + /// \brief Returns the maximum size of a representation after the trapdoor function is applied bound to a public key + /// \return the maximum size of a representation after the trapdoor function is applied bound to a public key + /// \details The default implementation returns ImageBound() - 1. + virtual Integer MaxImage() const {return --ImageBound();} +}; + +/// \brief Applies the trapdoor function, using random data if required +/// \details ApplyFunction() is the foundation for encrypting a message under a public key. +/// Derived classes will override it at some point. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE RandomizedTrapdoorFunction : public TrapdoorFunctionBounds +{ +public: + virtual ~RandomizedTrapdoorFunction() {} + + /// \brief Applies the trapdoor function, using random data if required + /// \param rng a RandomNumberGenerator derived class + /// \param x the message on which the encryption function is applied + /// \return the message x encrypted under the public key + /// \details ApplyRandomizedFunction is a generalization of encryption under a public key + /// cryptosystem. The RandomNumberGenerator may (or may not) be required. + /// Derived classes must implement it. + virtual Integer ApplyRandomizedFunction(RandomNumberGenerator &rng, const Integer &x) const =0; + + /// \brief Determines if the encryption algorithm is randomized + /// \return true if the encryption algorithm is randomized, false otherwise + /// \details If IsRandomized() returns false, then NullRNG() can be used. + virtual bool IsRandomized() const {return true;} +}; + +/// \brief Applies the trapdoor function +/// \details ApplyFunction() is the foundation for encrypting a message under a public key. +/// Derived classes will override it at some point. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TrapdoorFunction : public RandomizedTrapdoorFunction +{ +public: + virtual ~TrapdoorFunction() {} + + /// \brief Applies the trapdoor function + /// \param rng a RandomNumberGenerator derived class + /// \param x the message on which the encryption function is applied + /// \details ApplyRandomizedFunction is a generalization of encryption under a public key + /// cryptosystem. The RandomNumberGenerator may (or may not) be required. + /// \details Internally, ApplyRandomizedFunction() calls ApplyFunction() + /// without the RandomNumberGenerator. + Integer ApplyRandomizedFunction(RandomNumberGenerator &rng, const Integer &x) const + {CRYPTOPP_UNUSED(rng); return ApplyFunction(x);} + bool IsRandomized() const {return false;} + + /// \brief Applies the trapdoor + /// \param x the message on which the encryption function is applied + /// \return the message x encrypted under the public key + /// \details ApplyFunction is a generalization of encryption under a public key + /// cryptosystem. Derived classes must implement it. + virtual Integer ApplyFunction(const Integer &x) const =0; +}; + +/// \brief Applies the inverse of the trapdoor function, using random data if required +/// \details CalculateInverse() is the foundation for decrypting a message under a private key +/// in a public key cryptosystem. Derived classes will override it at some point. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE RandomizedTrapdoorFunctionInverse +{ +public: + virtual ~RandomizedTrapdoorFunctionInverse() {} + + /// \brief Applies the inverse of the trapdoor function, using random data if required + /// \param rng a RandomNumberGenerator derived class + /// \param x the message on which the decryption function is applied + /// \return the message x decrypted under the private key + /// \details CalculateRandomizedInverse is a generalization of decryption using the private key + /// The RandomNumberGenerator may (or may not) be required. Derived classes must implement it. + virtual Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const =0; + + /// \brief Determines if the decryption algorithm is randomized + /// \return true if the decryption algorithm is randomized, false otherwise + /// \details If IsRandomized() returns false, then NullRNG() can be used. + virtual bool IsRandomized() const {return true;} +}; + +/// \brief Applies the inverse of the trapdoor function +/// \details CalculateInverse() is the foundation for decrypting a message under a private key +/// in a public key cryptosystem. Derived classes will override it at some point. +/// \sa TrapdoorFunctionBounds(), RandomizedTrapdoorFunction(), TrapdoorFunction(), +/// RandomizedTrapdoorFunctionInverse() and TrapdoorFunctionInverse() +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TrapdoorFunctionInverse : public RandomizedTrapdoorFunctionInverse +{ +public: + virtual ~TrapdoorFunctionInverse() {} + + /// \brief Applies the inverse of the trapdoor function + /// \param rng a RandomNumberGenerator derived class + /// \param x the message on which the decryption function is applied + /// \return the message x decrypted under the private key + /// \details CalculateRandomizedInverse is a generalization of decryption using the private key + /// \details Internally, CalculateRandomizedInverse() calls CalculateInverse() + /// without the RandomNumberGenerator. + Integer CalculateRandomizedInverse(RandomNumberGenerator &rng, const Integer &x) const + {return CalculateInverse(rng, x);} + + /// \brief Determines if the decryption algorithm is randomized + /// \return true if the decryption algorithm is randomized, false otherwise + /// \details If IsRandomized() returns false, then NullRNG() can be used. + bool IsRandomized() const {return false;} + + /// \brief Calculates the inverse of an element + /// \param rng a RandomNumberGenerator derived class + /// \param x the element + /// \return the inverse of the element in the group + virtual Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const =0; +}; + +// ******************************************************** + +/// \brief Message encoding method for public key encryption +class CRYPTOPP_NO_VTABLE PK_EncryptionMessageEncodingMethod +{ +public: + virtual ~PK_EncryptionMessageEncodingMethod() {} + + virtual bool ParameterSupported(const char *name) const + {CRYPTOPP_UNUSED(name); return false;} + + /// max size of unpadded message in bytes, given max size of padded message in bits (1 less than size of modulus) + virtual size_t MaxUnpaddedLength(size_t paddedLength) const =0; + + virtual void Pad(RandomNumberGenerator &rng, const byte *raw, size_t inputLength, byte *padded, size_t paddedBitLength, const NameValuePairs ¶meters) const =0; + + virtual DecodingResult Unpad(const byte *padded, size_t paddedBitLength, byte *raw, const NameValuePairs ¶meters) const =0; +}; + +// ******************************************************** + +/// \brief The base for trapdoor based cryptosystems +/// \tparam TFI trapdoor function interface derived class +/// \tparam MEI message encoding interface derived class +template +class CRYPTOPP_NO_VTABLE TF_Base +{ +protected: + virtual ~TF_Base() {} + + virtual const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const =0; + + typedef TFI TrapdoorFunctionInterface; + virtual const TrapdoorFunctionInterface & GetTrapdoorFunctionInterface() const =0; + + typedef MEI MessageEncodingInterface; + virtual const MessageEncodingInterface & GetMessageEncodingInterface() const =0; +}; + +// ******************************************************** + +/// \brief Public key trapdoor function default implementation +/// \tparam BASE public key cryptosystem with a fixed length +template +class CRYPTOPP_NO_VTABLE PK_FixedLengthCryptoSystemImpl : public BASE +{ +public: + virtual ~PK_FixedLengthCryptoSystemImpl() {} + + size_t MaxPlaintextLength(size_t ciphertextLength) const + {return ciphertextLength == FixedCiphertextLength() ? FixedMaxPlaintextLength() : 0;} + size_t CiphertextLength(size_t plaintextLength) const + {return plaintextLength <= FixedMaxPlaintextLength() ? FixedCiphertextLength() : 0;} + + virtual size_t FixedMaxPlaintextLength() const =0; + virtual size_t FixedCiphertextLength() const =0; +}; + +/// \brief Trapdoor function cryptosystem base class +/// \tparam INTFACE public key cryptosystem base interface +/// \tparam BASE public key cryptosystem implementation base +template +class CRYPTOPP_NO_VTABLE TF_CryptoSystemBase : public PK_FixedLengthCryptoSystemImpl, protected BASE +{ +public: + virtual ~TF_CryptoSystemBase() {} + + bool ParameterSupported(const char *name) const {return this->GetMessageEncodingInterface().ParameterSupported(name);} + size_t FixedMaxPlaintextLength() const {return this->GetMessageEncodingInterface().MaxUnpaddedLength(PaddedBlockBitLength());} + size_t FixedCiphertextLength() const {return this->GetTrapdoorFunctionBounds().MaxImage().ByteCount();} + +protected: + size_t PaddedBlockByteLength() const {return BitsToBytes(PaddedBlockBitLength());} + // Coverity finding on potential overflow/underflow. + size_t PaddedBlockBitLength() const {return SaturatingSubtract(this->GetTrapdoorFunctionBounds().PreimageBound().BitCount(),1U);} +}; + +/// \brief Trapdoor function cryptosystems decryption base class +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TF_DecryptorBase : public TF_CryptoSystemBase > +{ +public: + virtual ~TF_DecryptorBase() {} + + DecodingResult Decrypt(RandomNumberGenerator &rng, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const; +}; + +/// \brief Trapdoor function cryptosystems encryption base class +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TF_EncryptorBase : public TF_CryptoSystemBase > +{ +public: + virtual ~TF_EncryptorBase() {} + + void Encrypt(RandomNumberGenerator &rng, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters = g_nullNameValuePairs) const; +}; + +// ******************************************************** + +// Typedef change due to Clang, http://github.com/weidai11/cryptopp/issues/300 +typedef std::pair HashIdentifier; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_SignatureMessageEncodingMethod provides interfaces for message +/// encoding method for public key signature schemes. The methods support both +/// trapdoor functions (TF_*) and discrete logarithm (DL_*) +/// based schemes. +class CRYPTOPP_NO_VTABLE PK_SignatureMessageEncodingMethod +{ +public: + virtual ~PK_SignatureMessageEncodingMethod() {} + + virtual size_t MinRepresentativeBitLength(size_t hashIdentifierLength, size_t digestLength) const + {CRYPTOPP_UNUSED(hashIdentifierLength); CRYPTOPP_UNUSED(digestLength); return 0;} + virtual size_t MaxRecoverableLength(size_t representativeBitLength, size_t hashIdentifierLength, size_t digestLength) const + {CRYPTOPP_UNUSED(representativeBitLength); CRYPTOPP_UNUSED(representativeBitLength); CRYPTOPP_UNUSED(hashIdentifierLength); CRYPTOPP_UNUSED(digestLength); return 0;} + + /// \brief Determines whether an encoding method requires a random number generator + /// \return true if the encoding method requires a RandomNumberGenerator() + /// \details if IsProbabilistic() returns false, then NullRNG() can be passed to functions that take + /// RandomNumberGenerator(). + /// \sa Bellare and RogawayPSS: + /// Provably Secure Encoding Method for Digital Signatures + bool IsProbabilistic() const + {return true;} + bool AllowNonrecoverablePart() const + {throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + virtual bool RecoverablePartFirst() const + {throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + + // for verification, DL + virtual void ProcessSemisignature(HashTransformation &hash, const byte *semisignature, size_t semisignatureLength) const + {CRYPTOPP_UNUSED(hash); CRYPTOPP_UNUSED(semisignature); CRYPTOPP_UNUSED(semisignatureLength);} + + // for signature + virtual void ProcessRecoverableMessage(HashTransformation &hash, + const byte *recoverableMessage, size_t recoverableMessageLength, + const byte *presignature, size_t presignatureLength, + SecByteBlock &semisignature) const + { + CRYPTOPP_UNUSED(hash);CRYPTOPP_UNUSED(recoverableMessage); CRYPTOPP_UNUSED(recoverableMessageLength); + CRYPTOPP_UNUSED(presignature); CRYPTOPP_UNUSED(presignatureLength); CRYPTOPP_UNUSED(semisignature); + if (RecoverablePartFirst()) + CRYPTOPP_ASSERT(!"ProcessRecoverableMessage() not implemented"); + } + + virtual void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const =0; + + virtual bool VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const =0; + + virtual DecodingResult RecoverMessageFromRepresentative( // for TF + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength, + byte *recoveredMessage) const + {CRYPTOPP_UNUSED(hash);CRYPTOPP_UNUSED(hashIdentifier); CRYPTOPP_UNUSED(messageEmpty); + CRYPTOPP_UNUSED(representative); CRYPTOPP_UNUSED(representativeBitLength); CRYPTOPP_UNUSED(recoveredMessage); + throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + + virtual DecodingResult RecoverMessageFromSemisignature( // for DL + HashTransformation &hash, HashIdentifier hashIdentifier, + const byte *presignature, size_t presignatureLength, + const byte *semisignature, size_t semisignatureLength, + byte *recoveredMessage) const + {CRYPTOPP_UNUSED(hash);CRYPTOPP_UNUSED(hashIdentifier); CRYPTOPP_UNUSED(presignature); CRYPTOPP_UNUSED(presignatureLength); + CRYPTOPP_UNUSED(semisignature); CRYPTOPP_UNUSED(semisignatureLength); CRYPTOPP_UNUSED(recoveredMessage); + throw NotImplemented("PK_MessageEncodingMethod: this signature scheme does not support message recovery");} + + // VC60 workaround + struct HashIdentifierLookup + { + template struct HashIdentifierLookup2 + { + static HashIdentifier CRYPTOPP_API Lookup() + { + return HashIdentifier(static_cast(NULLPTR), 0); + } + }; + }; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_DeterministicSignatureMessageEncodingMethod provides interfaces +/// for message encoding method for public key signature schemes. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_DeterministicSignatureMessageEncodingMethod : public PK_SignatureMessageEncodingMethod +{ +public: + bool VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_RecoverableSignatureMessageEncodingMethod provides interfaces +/// for message encoding method for public key signature schemes. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_RecoverableSignatureMessageEncodingMethod : public PK_SignatureMessageEncodingMethod +{ +public: + bool VerifyMessageRepresentative( + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details DL_SignatureMessageEncodingMethod_DSA provides interfaces +/// for message encoding method for DSA. +class CRYPTOPP_DLL DL_SignatureMessageEncodingMethod_DSA : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details DL_SignatureMessageEncodingMethod_NR provides interfaces +/// for message encoding method for Nyberg-Rueppel. +class CRYPTOPP_DLL DL_SignatureMessageEncodingMethod_NR : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; + +#if 0 +/// \brief Interface for message encoding method for public key signature schemes. +/// \details DL_SignatureMessageEncodingMethod_SM2 provides interfaces +/// for message encoding method for SM2. +class CRYPTOPP_DLL DL_SignatureMessageEncodingMethod_SM2 : public PK_DeterministicSignatureMessageEncodingMethod +{ +public: + void ComputeMessageRepresentative(RandomNumberGenerator &rng, + const byte *recoverableMessage, size_t recoverableMessageLength, + HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty, + byte *representative, size_t representativeBitLength) const; +}; +#endif + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_MessageAccumulatorBase provides interfaces +/// for message encoding method. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_MessageAccumulatorBase : public PK_MessageAccumulator +{ +public: + PK_MessageAccumulatorBase() : m_empty(true) {} + + virtual HashTransformation & AccessHash() =0; + + void Update(const byte *input, size_t length) + { + AccessHash().Update(input, length); + m_empty = m_empty && length == 0; + } + + SecByteBlock m_recoverableMessage, m_representative, m_presignature, m_semisignature; + Integer m_k, m_s; + bool m_empty; +}; + +/// \brief Interface for message encoding method for public key signature schemes. +/// \details PK_MessageAccumulatorBase provides interfaces +/// for message encoding method. +template +class PK_MessageAccumulatorImpl : public PK_MessageAccumulatorBase, protected ObjectHolder +{ +public: + HashTransformation & AccessHash() {return this->m_object;} +}; + +/// \brief Trapdoor Function (TF) Signature Scheme base class +/// \tparam INTFACE interface +/// \tparam BASE base class +template +class CRYPTOPP_NO_VTABLE TF_SignatureSchemeBase : public INTFACE, protected BASE +{ +public: + virtual ~TF_SignatureSchemeBase() {} + + size_t SignatureLength() const + {return this->GetTrapdoorFunctionBounds().MaxPreimage().ByteCount();} + size_t MaxRecoverableLength() const + {return this->GetMessageEncodingInterface().MaxRecoverableLength(MessageRepresentativeBitLength(), GetHashIdentifier().second, GetDigestSize());} + size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const + {CRYPTOPP_UNUSED(signatureLength); return this->MaxRecoverableLength();} + + bool IsProbabilistic() const + {return this->GetTrapdoorFunctionInterface().IsRandomized() || this->GetMessageEncodingInterface().IsProbabilistic();} + bool AllowNonrecoverablePart() const + {return this->GetMessageEncodingInterface().AllowNonrecoverablePart();} + bool RecoverablePartFirst() const + {return this->GetMessageEncodingInterface().RecoverablePartFirst();} + +protected: + size_t MessageRepresentativeLength() const {return BitsToBytes(MessageRepresentativeBitLength());} + // Coverity finding on potential overflow/underflow. + size_t MessageRepresentativeBitLength() const {return SaturatingSubtract(this->GetTrapdoorFunctionBounds().ImageBound().BitCount(),1U);} + virtual HashIdentifier GetHashIdentifier() const =0; + virtual size_t GetDigestSize() const =0; +}; + +/// \brief Trapdoor Function (TF) Signer base class +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TF_SignerBase : public TF_SignatureSchemeBase > +{ +public: + virtual ~TF_SignerBase() {} + + void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const; + size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart=true) const; +}; + +/// \brief Trapdoor Function (TF) Verifier base class +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE TF_VerifierBase : public TF_SignatureSchemeBase > +{ +public: + virtual ~TF_VerifierBase() {} + + void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const; + bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const; + DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &recoveryAccumulator) const; +}; + +// ******************************************************** + +/// \brief Trapdoor Function (TF) scheme options +/// \tparam T1 algorithm info class +/// \tparam T2 keys class with public and private key +/// \tparam T3 message encoding class +template +struct TF_CryptoSchemeOptions +{ + typedef T1 AlgorithmInfo; + typedef T2 Keys; + typedef typename Keys::PrivateKey PrivateKey; + typedef typename Keys::PublicKey PublicKey; + typedef T3 MessageEncodingMethod; +}; + +/// \brief Trapdoor Function (TF) signature scheme options +/// \tparam T1 algorithm info class +/// \tparam T2 keys class with public and private key +/// \tparam T3 message encoding class +/// \tparam T4 HashTransformation class +template +struct TF_SignatureSchemeOptions : public TF_CryptoSchemeOptions +{ + typedef T4 HashFunction; +}; + +/// \brief Trapdoor Function (TF) base implementation +/// \tparam BASE base class +/// \tparam SCHEME_OPTIONS scheme options class +/// \tparam KEY_CLASS key class +template +class CRYPTOPP_NO_VTABLE TF_ObjectImplBase : public AlgorithmImpl +{ +public: + typedef SCHEME_OPTIONS SchemeOptions; + typedef KEY_CLASS KeyClass; + + virtual ~TF_ObjectImplBase() {} + + PublicKey & AccessPublicKey() {return AccessKey();} + const PublicKey & GetPublicKey() const {return GetKey();} + + PrivateKey & AccessPrivateKey() {return AccessKey();} + const PrivateKey & GetPrivateKey() const {return GetKey();} + + virtual const KeyClass & GetKey() const =0; + virtual KeyClass & AccessKey() =0; + + const KeyClass & GetTrapdoorFunction() const {return GetKey();} + + PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng) const + { + CRYPTOPP_UNUSED(rng); + return new PK_MessageAccumulatorImpl; + } + PK_MessageAccumulator * NewVerificationAccumulator() const + { + return new PK_MessageAccumulatorImpl; + } + +protected: + const typename BASE::MessageEncodingInterface & GetMessageEncodingInterface() const + {return Singleton().Ref();} + const TrapdoorFunctionBounds & GetTrapdoorFunctionBounds() const + {return GetKey();} + const typename BASE::TrapdoorFunctionInterface & GetTrapdoorFunctionInterface() const + {return GetKey();} + + // for signature scheme + HashIdentifier GetHashIdentifier() const + { + typedef typename SchemeOptions::MessageEncodingMethod::HashIdentifierLookup::template HashIdentifierLookup2 L; + return L::Lookup(); + } + size_t GetDigestSize() const + { + typedef typename SchemeOptions::HashFunction H; + return H::DIGESTSIZE; + } +}; + +/// \brief Trapdoor Function (TF) signature with external reference +/// \tparam BASE base class +/// \tparam SCHEME_OPTIONS scheme options class +/// \tparam KEY key class +/// \details TF_ObjectImplExtRef() holds a pointer to an external key structure +template +class TF_ObjectImplExtRef : public TF_ObjectImplBase +{ +public: + virtual ~TF_ObjectImplExtRef() {} + + TF_ObjectImplExtRef(const KEY *pKey = NULLPTR) : m_pKey(pKey) {} + void SetKeyPtr(const KEY *pKey) {m_pKey = pKey;} + + const KEY & GetKey() const {return *m_pKey;} + KEY & AccessKey() {throw NotImplemented("TF_ObjectImplExtRef: cannot modify refererenced key");} + +private: + const KEY * m_pKey; +}; + +/// \brief Trapdoor Function (TF) signature scheme options +/// \tparam BASE base class +/// \tparam SCHEME_OPTIONS scheme options class +/// \tparam KEY_CLASS key class +/// \details TF_ObjectImpl() holds a reference to a trapdoor function +template +class CRYPTOPP_NO_VTABLE TF_ObjectImpl : public TF_ObjectImplBase +{ +public: + typedef KEY_CLASS KeyClass; + + virtual ~TF_ObjectImpl() {} + + const KeyClass & GetKey() const {return m_trapdoorFunction;} + KeyClass & AccessKey() {return m_trapdoorFunction;} + +private: + KeyClass m_trapdoorFunction; +}; + +/// \brief Trapdoor Function (TF) decryptor options +/// \tparam SCHEME_OPTIONS scheme options class +template +class TF_DecryptorImpl : public TF_ObjectImpl +{ +}; + +/// \brief Trapdoor Function (TF) encryptor options +/// \tparam SCHEME_OPTIONS scheme options class +template +class TF_EncryptorImpl : public TF_ObjectImpl +{ +}; + +/// \brief Trapdoor Function (TF) encryptor options +/// \tparam SCHEME_OPTIONS scheme options class +template +class TF_SignerImpl : public TF_ObjectImpl +{ +}; + +/// \brief Trapdoor Function (TF) encryptor options +/// \tparam SCHEME_OPTIONS scheme options class +template +class TF_VerifierImpl : public TF_ObjectImpl +{ +}; + +// ******************************************************** + +/// \brief Mask generation function interface +/// \sa P1363_KDF2, P1363_MGF1 +/// \since Crypto++ 2.0 +class CRYPTOPP_NO_VTABLE MaskGeneratingFunction +{ +public: + virtual ~MaskGeneratingFunction() {} + + /// \brief Generate and apply mask + /// \param hash HashTransformation derived class + /// \param output the destination byte array + /// \param outputLength the size of the destination byte array + /// \param input the message to hash + /// \param inputLength the size of the message + /// \param mask flag indicating whether to apply the mask + virtual void GenerateAndMask(HashTransformation &hash, byte *output, size_t outputLength, const byte *input, size_t inputLength, bool mask = true) const =0; +}; + +/// \fn P1363_MGF1KDF2_Common +/// \brief P1363 mask generation function +/// \param hash HashTransformation derived class +/// \param output the destination byte array +/// \param outputLength the size of the destination byte array +/// \param input the message to hash +/// \param inputLength the size of the message +/// \param derivationParams additional derivation parameters +/// \param derivationParamsLength the size of the additional derivation parameters +/// \param mask flag indicating whether to apply the mask +/// \param counterStart starting counter value used in generation function +CRYPTOPP_DLL void CRYPTOPP_API P1363_MGF1KDF2_Common(HashTransformation &hash, byte *output, size_t outputLength, const byte *input, size_t inputLength, const byte *derivationParams, size_t derivationParamsLength, bool mask, unsigned int counterStart); + +/// \brief P1363 mask generation function +/// \sa P1363_KDF2, MaskGeneratingFunction +/// \since Crypto++ 2.0 +class P1363_MGF1 : public MaskGeneratingFunction +{ +public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "MGF1";} + + /// \brief P1363 mask generation function + /// \param hash HashTransformation derived class + /// \param output the destination byte array + /// \param outputLength the size of the destination byte array + /// \param input the message to hash + /// \param inputLength the size of the message + /// \param mask flag indicating whether to apply the mask + void GenerateAndMask(HashTransformation &hash, byte *output, size_t outputLength, const byte *input, size_t inputLength, bool mask = true) const + { + P1363_MGF1KDF2_Common(hash, output, outputLength, input, inputLength, NULLPTR, 0, mask, 0); + } +}; + +// ******************************************************** + +/// \brief P1363 key derivation function +/// \tparam H hash function used in the derivation +/// \sa P1363_MGF1, KeyDerivationFunction, P1363_KDF2 +/// on the Crypto++ wiki +/// \since Crypto++ 2.0 +template +class P1363_KDF2 +{ +public: + /// \brief P1363 key derivation function + /// \param output the destination byte array + /// \param outputLength the size of the destination byte array + /// \param input the message to hash + /// \param inputLength the size of the message + /// \param derivationParams additional derivation parameters + /// \param derivationParamsLength the size of the additional derivation parameters + /// \details DeriveKey calls P1363_MGF1KDF2_Common + static void CRYPTOPP_API DeriveKey(byte *output, size_t outputLength, const byte *input, size_t inputLength, const byte *derivationParams, size_t derivationParamsLength) + { + H h; + P1363_MGF1KDF2_Common(h, output, outputLength, input, inputLength, derivationParams, derivationParamsLength, false, 1); + } +}; + +// ******************************************************** + +/// \brief Exception thrown when an invalid group element is encountered +/// \details Thrown by DecodeElement and AgreeWithStaticPrivateKey +class DL_BadElement : public InvalidDataFormat +{ +public: + DL_BadElement() : InvalidDataFormat("CryptoPP: invalid group element") {} +}; + +/// \brief Interface for Discrete Log (DL) group parameters +/// \tparam T element in the group +/// \details The element is usually an Integer, \ref ECP "ECP::Point" or \ref EC2N "EC2N::Point" +template +class CRYPTOPP_NO_VTABLE DL_GroupParameters : public CryptoParameters +{ + typedef DL_GroupParameters ThisClass; + +public: + typedef T Element; + + virtual ~DL_GroupParameters() {} + + DL_GroupParameters() : m_validationLevel(0) {} + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + if (!GetBasePrecomputation().IsInitialized()) + return false; + + if (m_validationLevel > level) + return true; + + CRYPTOPP_ASSERT(ValidateGroup(rng, level)); + bool pass = ValidateGroup(rng, level); + CRYPTOPP_ASSERT(ValidateElement(level, GetSubgroupGenerator(), &GetBasePrecomputation())); + pass = pass && ValidateElement(level, GetSubgroupGenerator(), &GetBasePrecomputation()); + + m_validationLevel = pass ? level+1 : 0; + + return pass; + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue) + CRYPTOPP_GET_FUNCTION_ENTRY(SubgroupOrder) + CRYPTOPP_GET_FUNCTION_ENTRY(SubgroupGenerator) + ; + } + + /// \brief Determines whether the object supports precomputation + /// \return true if the object supports precomputation, false otherwise + /// \sa Precompute() + bool SupportsPrecomputation() const {return true;} + + /// \brief Perform precomputation + /// \param precomputationStorage the suggested number of objects for the precompute table + /// \throw NotImplemented + /// \details The exact semantics of Precompute() varies, but it typically means calculate + /// a table of n objects that can be used later to speed up computation. + /// \details If a derived class does not override Precompute(), then the base class throws + /// NotImplemented. + /// \sa SupportsPrecomputation(), LoadPrecomputation(), SavePrecomputation() + void Precompute(unsigned int precomputationStorage=16) + { + AccessBasePrecomputation().Precompute(GetGroupPrecomputation(), GetSubgroupOrder().BitCount(), precomputationStorage); + } + + /// \brief Retrieve previously saved precomputation + /// \param storedPrecomputation BufferedTransformation with the saved precomputation + /// \throw NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + { + AccessBasePrecomputation().Load(GetGroupPrecomputation(), storedPrecomputation); + m_validationLevel = 0; + } + + /// \brief Save precomputation for later use + /// \param storedPrecomputation BufferedTransformation to write the precomputation + /// \throw NotImplemented + /// \sa SupportsPrecomputation(), Precompute() + void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + { + GetBasePrecomputation().Save(GetGroupPrecomputation(), storedPrecomputation); + } + + /// \brief Retrieves the subgroup generator + /// \return the subgroup generator + /// \details The subgroup generator is retrieved from the base precomputation + virtual const Element & GetSubgroupGenerator() const {return GetBasePrecomputation().GetBase(GetGroupPrecomputation());} + + /// \brief Sets the subgroup generator + /// \param base the new subgroup generator + /// \details The subgroup generator is set in the base precomputation + virtual void SetSubgroupGenerator(const Element &base) {AccessBasePrecomputation().SetBase(GetGroupPrecomputation(), base);} + + /// \brief Exponentiates the base + /// \return the element after exponentiation + /// \details ExponentiateBase() calls GetBasePrecomputation() and then exponentiates. + virtual Element ExponentiateBase(const Integer &exponent) const + { + return GetBasePrecomputation().Exponentiate(GetGroupPrecomputation(), exponent); + } + + /// \brief Exponentiates an element + /// \param base the base element + /// \param exponent the exponent to raise the base + /// \return the result of the exponentiation + /// \details Internally, ExponentiateElement() calls SimultaneousExponentiate(). + virtual Element ExponentiateElement(const Element &base, const Integer &exponent) const + { + Element result; + SimultaneousExponentiate(&result, base, &exponent, 1); + return result; + } + + /// \brief Retrieves the group precomputation + /// \return a const reference to the group precomputation + virtual const DL_GroupPrecomputation & GetGroupPrecomputation() const =0; + + /// \brief Retrieves the group precomputation + /// \return a const reference to the group precomputation using a fixed base + virtual const DL_FixedBasePrecomputation & GetBasePrecomputation() const =0; + + /// \brief Retrieves the group precomputation + /// \return a non-const reference to the group precomputation using a fixed base + virtual DL_FixedBasePrecomputation & AccessBasePrecomputation() =0; + + /// \brief Retrieves the subgroup order + /// \return the order of subgroup generated by the base element + virtual const Integer & GetSubgroupOrder() const =0; + + /// \brief Retrieves the maximum exponent for the group + /// \return the maximum exponent for the group + virtual Integer GetMaxExponent() const =0; + + /// \brief Retrieves the order of the group + /// \return the order of the group + /// \details Either GetGroupOrder() or GetCofactor() must be overridden in a derived class. + virtual Integer GetGroupOrder() const {return GetSubgroupOrder()*GetCofactor();} + + /// \brief Retrieves the cofactor + /// \return the cofactor + /// \details Either GetGroupOrder() or GetCofactor() must be overridden in a derived class. + virtual Integer GetCofactor() const {return GetGroupOrder()/GetSubgroupOrder();} + + /// \brief Retrieves the encoded element's size + /// \param reversible flag indicating the encoding format + /// \return encoded element's size, in bytes + /// \details The format of the encoded element varies by the underlying type of the element and the + /// reversible flag. GetEncodedElementSize() must be implemented in a derived class. + /// \sa GetEncodedElementSize(), EncodeElement(), DecodeElement() + virtual unsigned int GetEncodedElementSize(bool reversible) const =0; + + /// \brief Encodes the element + /// \param reversible flag indicating the encoding format + /// \param element reference to the element to encode + /// \param encoded destination byte array for the encoded element + /// \details EncodeElement() must be implemented in a derived class. + /// \pre COUNTOF(encoded) == GetEncodedElementSize() + virtual void EncodeElement(bool reversible, const Element &element, byte *encoded) const =0; + + /// \brief Decodes the element + /// \param encoded byte array with the encoded element + /// \param checkForGroupMembership flag indicating if the element should be validated + /// \return Element after decoding + /// \details DecodeElement() must be implemented in a derived class. + /// \pre COUNTOF(encoded) == GetEncodedElementSize() + virtual Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const =0; + + /// \brief Converts an element to an Integer + /// \param element the element to convert to an Integer + /// \return Element after converting to an Integer + /// \details ConvertElementToInteger() must be implemented in a derived class. + virtual Integer ConvertElementToInteger(const Element &element) const =0; + + /// \brief Check the group for errors + /// \param rng RandomNumberGenerator for objects which use randomized testing + /// \param level level of thoroughness + /// \return true if the tests succeed, false otherwise + /// \details There are four levels of thoroughness: + ///
    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other operations correctly + ///
  • 2 - ensure this object will function correctly, and perform reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may take a long time + ///
+ /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can be used for level 0. + /// Level 1 may not check for weak keys and such. Levels 2 and 3 are recommended. + /// \details ValidateGroup() must be implemented in a derived class. + virtual bool ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const =0; + + /// \brief Check the element for errors + /// \param level level of thoroughness + /// \param element element to check + /// \param precomp optional pointer to DL_FixedBasePrecomputation + /// \return true if the tests succeed, false otherwise + /// \details There are four levels of thoroughness: + ///
    + ///
  • 0 - using this object won't cause a crash or exception + ///
  • 1 - this object will probably function, and encrypt, sign, other operations correctly + ///
  • 2 - ensure this object will function correctly, and perform reasonable security checks + ///
  • 3 - perform reasonable security checks, and do checks that may take a long time + ///
+ /// \details Level 0 performs group membership checks. Level 1 may not check for weak keys and such. + /// Levels 2 and 3 are recommended. + /// \details ValidateElement() must be implemented in a derived class. + virtual bool ValidateElement(unsigned int level, const Element &element, const DL_FixedBasePrecomputation *precomp) const =0; + + virtual bool FastSubgroupCheckAvailable() const =0; + + /// \brief Determines if an element is an identity + /// \param element element to check + /// \return true if the element is an identity, false otherwise + /// \details The identity element or or neutral element is a special element in a group that leaves + /// other elements unchanged when combined with it. + /// \details IsIdentity() must be implemented in a derived class. + virtual bool IsIdentity(const Element &element) const =0; + + /// \brief Exponentiates a base to multiple exponents + /// \param results an array of Elements + /// \param base the base to raise to the exponents + /// \param exponents an array of exponents + /// \param exponentsCount the number of exponents in the array + /// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the + /// result at the respective position in the results array. + /// \details SimultaneousExponentiate() must be implemented in a derived class. + /// \pre COUNTOF(results) == exponentsCount + /// \pre COUNTOF(exponents) == exponentsCount + virtual void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const =0; + +protected: + void ParametersChanged() {m_validationLevel = 0;} + +private: + mutable unsigned int m_validationLevel; +}; + +/// \brief Base implementation of Discrete Log (DL) group parameters +/// \tparam GROUP_PRECOMP group precomputation class +/// \tparam BASE_PRECOMP fixed base precomputation class +/// \tparam BASE class or type of an element +template , class BASE = DL_GroupParameters > +class DL_GroupParametersImpl : public BASE +{ +public: + typedef GROUP_PRECOMP GroupPrecomputation; + typedef typename GROUP_PRECOMP::Element Element; + typedef BASE_PRECOMP BasePrecomputation; + + virtual ~DL_GroupParametersImpl() {} + + /// \brief Retrieves the group precomputation + /// \return a const reference to the group precomputation + const DL_GroupPrecomputation & GetGroupPrecomputation() const {return m_groupPrecomputation;} + + /// \brief Retrieves the group precomputation + /// \return a const reference to the group precomputation using a fixed base + const DL_FixedBasePrecomputation & GetBasePrecomputation() const {return m_gpc;} + + /// \brief Retrieves the group precomputation + /// \return a non-const reference to the group precomputation using a fixed base + DL_FixedBasePrecomputation & AccessBasePrecomputation() {return m_gpc;} + +protected: + GROUP_PRECOMP m_groupPrecomputation; + BASE_PRECOMP m_gpc; +}; + +/// \brief Base class for a Discrete Log (DL) key +/// \tparam T class or type of an element +/// \details The element is usually an Integer, \ref ECP "ECP::Point" or \ref EC2N "EC2N::Point" +template +class CRYPTOPP_NO_VTABLE DL_Key +{ +public: + virtual ~DL_Key() {} + + /// \brief Retrieves abstract group parameters + /// \return a const reference to the group parameters + virtual const DL_GroupParameters & GetAbstractGroupParameters() const =0; + /// \brief Retrieves abstract group parameters + /// \return a non-const reference to the group parameters + virtual DL_GroupParameters & AccessAbstractGroupParameters() =0; +}; + +/// \brief Interface for Discrete Log (DL) public keys +template +class CRYPTOPP_NO_VTABLE DL_PublicKey : public DL_Key +{ + typedef DL_PublicKey ThisClass; + +public: + typedef T Element; + + virtual ~DL_PublicKey(); + + /// \brief Get a named value + /// \param name the name of the object or value to retrieve + /// \param valueType reference to a variable that receives the value + /// \param pValue void pointer to a variable that receives the value + /// \return true if the value was retrieved, false otherwise + /// \details GetVoidValue() retrieves the value of name if it exists. + /// \note GetVoidValue() is an internal function and should be implemented + /// by derived classes. Users should use one of the other functions instead. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue, &this->GetAbstractGroupParameters()) + CRYPTOPP_GET_FUNCTION_ENTRY(PublicElement); + } + + /// \brief Initialize or reinitialize this key + /// \param source NameValuePairs to assign + void AssignFrom(const NameValuePairs &source); + + /// \brief Retrieves the public element + /// \return the public element + virtual const Element & GetPublicElement() const {return GetPublicPrecomputation().GetBase(this->GetAbstractGroupParameters().GetGroupPrecomputation());} + + /// \brief Sets the public element + /// \param y the public element + virtual void SetPublicElement(const Element &y) {AccessPublicPrecomputation().SetBase(this->GetAbstractGroupParameters().GetGroupPrecomputation(), y);} + + /// \brief Exponentiates this element + /// \param exponent the exponent to raise the base + /// \return the public element raised to the exponent + virtual Element ExponentiatePublicElement(const Integer &exponent) const + { + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + return GetPublicPrecomputation().Exponentiate(params.GetGroupPrecomputation(), exponent); + } + + /// \brief Exponentiates an element + /// \param baseExp the first exponent + /// \param publicExp the second exponent + /// \return the public element raised to the exponent + /// \details CascadeExponentiateBaseAndPublicElement raises the public element to + /// the base element and precomputation. + virtual Element CascadeExponentiateBaseAndPublicElement(const Integer &baseExp, const Integer &publicExp) const + { + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + return params.GetBasePrecomputation().CascadeExponentiate(params.GetGroupPrecomputation(), baseExp, GetPublicPrecomputation(), publicExp); + } + + /// \brief Accesses the public precomputation + /// \details GetPublicPrecomputation returns a const reference, while + /// AccessPublicPrecomputation returns a non-const reference. Must be + /// overridden in derived classes. + virtual const DL_FixedBasePrecomputation & GetPublicPrecomputation() const =0; + + /// \brief Accesses the public precomputation + /// \details GetPublicPrecomputation returns a const reference, while + /// AccessPublicPrecomputation returns a non-const reference. Must be + /// overridden in derived classes. + virtual DL_FixedBasePrecomputation & AccessPublicPrecomputation() =0; +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PublicKey::~DL_PublicKey() {} + +/// \brief Interface for Discrete Log (DL) private keys +template +class CRYPTOPP_NO_VTABLE DL_PrivateKey : public DL_Key +{ + typedef DL_PrivateKey ThisClass; + +public: + typedef T Element; + + virtual ~DL_PrivateKey(); + + /// \brief Initializes a public key from this key + /// \param pub reference to a public key + void MakePublicKey(DL_PublicKey &pub) const + { + pub.AccessAbstractGroupParameters().AssignFrom(this->GetAbstractGroupParameters()); + pub.SetPublicElement(this->GetAbstractGroupParameters().ExponentiateBase(GetPrivateExponent())); + } + + /// \brief Get a named value + /// \param name the name of the object or value to retrieve + /// \param valueType reference to a variable that receives the value + /// \param pValue void pointer to a variable that receives the value + /// \return true if the value was retrieved, false otherwise + /// \details GetVoidValue() retrieves the value of name if it exists. + /// \note GetVoidValue() is an internal function and should be implemented + /// by derived classes. Users should use one of the other functions instead. + /// \sa GetValue(), GetValueWithDefault(), GetIntValue(), GetIntValueWithDefault(), + /// GetRequiredParameter() and GetRequiredIntParameter() + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper(this, name, valueType, pValue, &this->GetAbstractGroupParameters()) + CRYPTOPP_GET_FUNCTION_ENTRY(PrivateExponent); + } + + /// \brief Initialize or reinitialize this key + /// \param source NameValuePairs to assign + void AssignFrom(const NameValuePairs &source) + { + this->AccessAbstractGroupParameters().AssignFrom(source); + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(PrivateExponent); + } + + /// \brief Retrieves the private exponent + /// \return the private exponent + /// \details Must be overridden in derived classes. + virtual const Integer & GetPrivateExponent() const =0; + /// \brief Sets the private exponent + /// \param x the private exponent + /// \details Must be overridden in derived classes. + virtual void SetPrivateExponent(const Integer &x) =0; +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PrivateKey::~DL_PrivateKey() {} + +template +void DL_PublicKey::AssignFrom(const NameValuePairs &source) +{ + DL_PrivateKey *pPrivateKey = NULLPTR; + if (source.GetThisPointer(pPrivateKey)) + pPrivateKey->MakePublicKey(*this); + else + { + this->AccessAbstractGroupParameters().AssignFrom(source); + AssignFromHelper(this, source) + CRYPTOPP_SET_FUNCTION_ENTRY(PublicElement); + } +} + +class OID; + +/// \brief Discrete Log (DL) key base implementation +/// \tparam PK Key class +/// \tparam GP GroupParameters class +/// \tparam O OID class +template +class DL_KeyImpl : public PK +{ +public: + typedef GP GroupParameters; + + virtual ~DL_KeyImpl() {} + + O GetAlgorithmID() const {return GetGroupParameters().GetAlgorithmID();} + bool BERDecodeAlgorithmParameters(BufferedTransformation &bt) + {AccessGroupParameters().BERDecode(bt); return true;} + bool DEREncodeAlgorithmParameters(BufferedTransformation &bt) const + {GetGroupParameters().DEREncode(bt); return true;} + + const GP & GetGroupParameters() const {return m_groupParameters;} + GP & AccessGroupParameters() {return m_groupParameters;} + +private: + GP m_groupParameters; +}; + +class X509PublicKey; +class PKCS8PrivateKey; + +/// \brief Discrete Log (DL) private key base implementation +/// \tparam GP GroupParameters class +template +class DL_PrivateKeyImpl : public DL_PrivateKey, public DL_KeyImpl +{ +public: + typedef typename GP::Element Element; + + virtual ~DL_PrivateKeyImpl() {} + + // GeneratableCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + CRYPTOPP_ASSERT(GetAbstractGroupParameters().Validate(rng, level)); + bool pass = GetAbstractGroupParameters().Validate(rng, level); + + const Integer &q = GetAbstractGroupParameters().GetSubgroupOrder(); + const Integer &x = GetPrivateExponent(); + + CRYPTOPP_ASSERT(x.IsPositive()); + CRYPTOPP_ASSERT(x < q); + pass = pass && x.IsPositive() && x < q; + + if (level >= 1) + { + CRYPTOPP_ASSERT(Integer::Gcd(x, q) == Integer::One()); + pass = pass && Integer::Gcd(x, q) == Integer::One(); + } + return pass; + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper >(this, name, valueType, pValue).Assignable(); + } + + void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper >(this, source); + } + + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms) + { + if (!params.GetThisObject(this->AccessGroupParameters())) + this->AccessGroupParameters().GenerateRandom(rng, params); + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + SetPrivateExponent(x); + } + + bool SupportsPrecomputation() const {return true;} + + void Precompute(unsigned int precomputationStorage=16) + {AccessAbstractGroupParameters().Precompute(precomputationStorage);} + + void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + {AccessAbstractGroupParameters().LoadPrecomputation(storedPrecomputation);} + + void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + {GetAbstractGroupParameters().SavePrecomputation(storedPrecomputation);} + + // DL_Key + const DL_GroupParameters & GetAbstractGroupParameters() const {return this->GetGroupParameters();} + DL_GroupParameters & AccessAbstractGroupParameters() {return this->AccessGroupParameters();} + + // DL_PrivateKey + const Integer & GetPrivateExponent() const {return m_x;} + void SetPrivateExponent(const Integer &x) {m_x = x;} + + // PKCS8PrivateKey + void BERDecodePrivateKey(BufferedTransformation &bt, bool, size_t) + {m_x.BERDecode(bt);} + void DEREncodePrivateKey(BufferedTransformation &bt) const + {m_x.DEREncode(bt);} + +private: + Integer m_x; +}; + +template +class DL_PrivateKey_WithSignaturePairwiseConsistencyTest : public BASE +{ +public: + virtual ~DL_PrivateKey_WithSignaturePairwiseConsistencyTest() {} + + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms) + { + BASE::GenerateRandom(rng, params); + + if (FIPS_140_2_ComplianceEnabled()) + { + typename SIGNATURE_SCHEME::Signer signer(*this); + typename SIGNATURE_SCHEME::Verifier verifier(signer); + SignaturePairwiseConsistencyTest_FIPS_140_Only(signer, verifier); + } + } +}; + +/// \brief Discrete Log (DL) public key base implementation +/// \tparam GP GroupParameters class +template +class DL_PublicKeyImpl : public DL_PublicKey, public DL_KeyImpl +{ +public: + typedef typename GP::Element Element; + + virtual ~DL_PublicKeyImpl(); + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const + { + CRYPTOPP_ASSERT(GetAbstractGroupParameters().Validate(rng, level)); + bool pass = GetAbstractGroupParameters().Validate(rng, level); + CRYPTOPP_ASSERT(GetAbstractGroupParameters().ValidateElement(level, this->GetPublicElement(), &GetPublicPrecomputation())); + pass = pass && GetAbstractGroupParameters().ValidateElement(level, this->GetPublicElement(), &GetPublicPrecomputation()); + return pass; + } + + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const + { + return GetValueHelper >(this, name, valueType, pValue).Assignable(); + } + + void AssignFrom(const NameValuePairs &source) + { + AssignFromHelper >(this, source); + } + + bool SupportsPrecomputation() const {return true;} + + void Precompute(unsigned int precomputationStorage=16) + { + AccessAbstractGroupParameters().Precompute(precomputationStorage); + AccessPublicPrecomputation().Precompute(GetAbstractGroupParameters().GetGroupPrecomputation(), GetAbstractGroupParameters().GetSubgroupOrder().BitCount(), precomputationStorage); + } + + void LoadPrecomputation(BufferedTransformation &storedPrecomputation) + { + AccessAbstractGroupParameters().LoadPrecomputation(storedPrecomputation); + AccessPublicPrecomputation().Load(GetAbstractGroupParameters().GetGroupPrecomputation(), storedPrecomputation); + } + + void SavePrecomputation(BufferedTransformation &storedPrecomputation) const + { + GetAbstractGroupParameters().SavePrecomputation(storedPrecomputation); + GetPublicPrecomputation().Save(GetAbstractGroupParameters().GetGroupPrecomputation(), storedPrecomputation); + } + + // DL_Key + const DL_GroupParameters & GetAbstractGroupParameters() const {return this->GetGroupParameters();} + DL_GroupParameters & AccessAbstractGroupParameters() {return this->AccessGroupParameters();} + + // DL_PublicKey + const DL_FixedBasePrecomputation & GetPublicPrecomputation() const {return m_ypc;} + DL_FixedBasePrecomputation & AccessPublicPrecomputation() {return m_ypc;} + + // non-inherited + bool operator==(const DL_PublicKeyImpl &rhs) const + {return this->GetGroupParameters() == rhs.GetGroupParameters() && this->GetPublicElement() == rhs.GetPublicElement();} + +private: + typename GP::BasePrecomputation m_ypc; +}; + +// Out-of-line dtor due to AIX and GCC, http://github.com/weidai11/cryptopp/issues/499 +template +DL_PublicKeyImpl::~DL_PublicKeyImpl() {} + +/// \brief Interface for Elgamal-like signature algorithms +/// \tparam T Field element type or class +/// \details Field element T can be Integer, ECP or EC2N. +template +class CRYPTOPP_NO_VTABLE DL_ElgamalLikeSignatureAlgorithm +{ +public: + virtual ~DL_ElgamalLikeSignatureAlgorithm() {} + + /// \brief Sign a message using a private key + /// \param params GroupParameters + /// \param privateKey private key + /// \param k signing exponent + /// \param e encoded message + /// \param r r part of signature + /// \param s s part of signature + virtual void Sign(const DL_GroupParameters ¶ms, const Integer &privateKey, const Integer &k, const Integer &e, Integer &r, Integer &s) const =0; + + /// \brief Verify a message using a public key + /// \param params GroupParameters + /// \param publicKey public key + /// \param e encoded message + /// \param r r part of signature + /// \param s s part of signature + virtual bool Verify(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &e, const Integer &r, const Integer &s) const =0; + + /// \brief Recover a Presignature + /// \param params GroupParameters + /// \param publicKey public key + /// \param r r part of signature + /// \param s s part of signature + virtual Integer RecoverPresignature(const DL_GroupParameters ¶ms, const DL_PublicKey &publicKey, const Integer &r, const Integer &s) const + { + CRYPTOPP_UNUSED(params); CRYPTOPP_UNUSED(publicKey); CRYPTOPP_UNUSED(r); CRYPTOPP_UNUSED(s); + throw NotImplemented("DL_ElgamalLikeSignatureAlgorithm: this signature scheme does not support message recovery"); + MAYBE_RETURN(Integer::Zero()); + } + + /// \brief Retrieve R length + /// \param params GroupParameters + virtual size_t RLen(const DL_GroupParameters ¶ms) const + {return params.GetSubgroupOrder().ByteCount();} + + /// \brief Retrieve S length + /// \param params GroupParameters + virtual size_t SLen(const DL_GroupParameters ¶ms) const + {return params.GetSubgroupOrder().ByteCount();} + + /// \brief Signature scheme flag + /// \return true if the signature scheme is deterministic, false otherwise + /// \details IsDeterministic() is provided for DL signers. It is used by RFC 6979 signature schemes. + virtual bool IsDeterministic() const + {return false;} +}; + +/// \brief Interface for deterministic signers +/// \details RFC 6979 signers which generate k based on the encoded message and private key +class CRYPTOPP_NO_VTABLE DeterministicSignatureAlgorithm +{ +public: + virtual ~DeterministicSignatureAlgorithm() {} + + /// \brief Generate k + /// \param x private key + /// \param q subgroup generator + /// \param e encoded message + virtual Integer GenerateRandom(const Integer &x, const Integer &q, const Integer &e) const =0; +}; + +/// \brief Interface for DL key agreement algorithms +/// \tparam T Field element type or class +/// \details Field element T can be Integer, ECP or EC2N. +/// \sa DLIES, ECIES, ECIES_P1363 +template +class CRYPTOPP_NO_VTABLE DL_KeyAgreementAlgorithm +{ +public: + typedef T Element; + + virtual ~DL_KeyAgreementAlgorithm() {} + + virtual Element AgreeWithEphemeralPrivateKey(const DL_GroupParameters ¶ms, const DL_FixedBasePrecomputation &publicPrecomputation, const Integer &privateExponent) const =0; + virtual Element AgreeWithStaticPrivateKey(const DL_GroupParameters ¶ms, const Element &publicElement, bool validateOtherPublicKey, const Integer &privateExponent) const =0; +}; + +/// \brief Interface for key derivation algorithms used in DL cryptosystems +/// \tparam T Field element type or class +/// \details Field element T can be Integer, ECP or EC2N. +/// \sa DLIES, ECIES, ECIES_P1363 +template +class CRYPTOPP_NO_VTABLE DL_KeyDerivationAlgorithm +{ +public: + virtual ~DL_KeyDerivationAlgorithm() {} + + virtual bool ParameterSupported(const char *name) const + {CRYPTOPP_UNUSED(name); return false;} + virtual void Derive(const DL_GroupParameters &groupParams, byte *derivedKey, size_t derivedLength, const T &agreedElement, const T &ephemeralPublicKey, const NameValuePairs &derivationParams) const =0; +}; + +/// \brief Interface for symmetric encryption algorithms used in DL cryptosystems +/// \sa DLIES, ECIES, ECIES_P1363 +class CRYPTOPP_NO_VTABLE DL_SymmetricEncryptionAlgorithm +{ +public: + virtual ~DL_SymmetricEncryptionAlgorithm() {} + + virtual bool ParameterSupported(const char *name) const + {CRYPTOPP_UNUSED(name); return false;} + virtual size_t GetSymmetricKeyLength(size_t plaintextLength) const =0; + virtual size_t GetSymmetricCiphertextLength(size_t plaintextLength) const =0; + virtual size_t GetMaxSymmetricPlaintextLength(size_t ciphertextLength) const =0; + virtual void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters) const =0; + virtual DecodingResult SymmetricDecrypt(const byte *key, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters) const =0; +}; + +/// \brief Discrete Log (DL) base interface +/// \tparam KI public or private key interface +template +class CRYPTOPP_NO_VTABLE DL_Base +{ +protected: + typedef KI KeyInterface; + typedef typename KI::Element Element; + + virtual ~DL_Base() {} + + const DL_GroupParameters & GetAbstractGroupParameters() const {return GetKeyInterface().GetAbstractGroupParameters();} + DL_GroupParameters & AccessAbstractGroupParameters() {return AccessKeyInterface().AccessAbstractGroupParameters();} + + virtual KeyInterface & AccessKeyInterface() =0; + virtual const KeyInterface & GetKeyInterface() const =0; +}; + +/// \brief Discrete Log (DL) signature scheme base implementation +/// \tparam INTFACE PK_Signer or PK_Verifier derived class +/// \tparam KEY_INTFACE DL_Base key base used in the scheme +/// \details DL_SignatureSchemeBase provides common functions for signers and verifiers. +/// DL_Base is used for signers, and DL_Base is used for verifiers. +template +class CRYPTOPP_NO_VTABLE DL_SignatureSchemeBase : public INTFACE, public DL_Base +{ +public: + virtual ~DL_SignatureSchemeBase() {} + + /// \brief Provides the signature length + /// \return signature length, in bytes + /// \details SignatureLength returns the size required for r+s. + size_t SignatureLength() const + { + return GetSignatureAlgorithm().RLen(this->GetAbstractGroupParameters()) + + GetSignatureAlgorithm().SLen(this->GetAbstractGroupParameters()); + } + + /// \brief Provides the maximum recoverable length + /// \return maximum recoverable length, in bytes + size_t MaxRecoverableLength() const + {return GetMessageEncodingInterface().MaxRecoverableLength(0, GetHashIdentifier().second, GetDigestSize());} + + /// \brief Provides the maximum recoverable length + /// \param signatureLength the size of the signature + /// \return maximum recoverable length based on signature length, in bytes + /// \details this function is not implemented and always returns 0. + size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const + {CRYPTOPP_UNUSED(signatureLength); CRYPTOPP_ASSERT(false); return 0;} // TODO + + /// \brief Determines if the scheme is probabilistic + /// \return true if the scheme is probabilistic, false otherwise + bool IsProbabilistic() const + {return true;} + + /// \brief Determines if the scheme has non-recoverable part + /// \return true if the message encoding has a non-recoverable part, false otherwise. + bool AllowNonrecoverablePart() const + {return GetMessageEncodingInterface().AllowNonrecoverablePart();} + + /// \brief Determines if the scheme allows recoverable part first + /// \return true if the message encoding allows the recoverable part, false otherwise. + bool RecoverablePartFirst() const + {return GetMessageEncodingInterface().RecoverablePartFirst();} + +protected: + size_t MessageRepresentativeLength() const {return BitsToBytes(MessageRepresentativeBitLength());} + size_t MessageRepresentativeBitLength() const {return this->GetAbstractGroupParameters().GetSubgroupOrder().BitCount();} + + // true if the scheme conforms to RFC 6979 + virtual bool IsDeterministic() const {return false;} + + virtual const DL_ElgamalLikeSignatureAlgorithm & GetSignatureAlgorithm() const =0; + virtual const PK_SignatureMessageEncodingMethod & GetMessageEncodingInterface() const =0; + virtual HashIdentifier GetHashIdentifier() const =0; + virtual size_t GetDigestSize() const =0; +}; + +/// \brief Discrete Log (DL) signature scheme signer base implementation +/// \tparam T Field element type or class +/// \details Field element T can be Integer, ECP or EC2N. +template +class CRYPTOPP_NO_VTABLE DL_SignerBase : public DL_SignatureSchemeBase > +{ +public: + virtual ~DL_SignerBase() {} + + /// \brief Testing interface + /// \param k Integer + /// \param e Integer + /// \param r Integer + /// \param s Integer + void RawSign(const Integer &k, const Integer &e, Integer &r, Integer &s) const + { + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PrivateKey &key = this->GetKeyInterface(); + + r = params.ConvertElementToInteger(params.ExponentiateBase(k)); + alg.Sign(params, key.GetPrivateExponent(), k, e, r, s); + } + + void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const + { + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + ma.m_recoverableMessage.Assign(recoverableMessage, recoverableMessageLength); + this->GetMessageEncodingInterface().ProcessRecoverableMessage(ma.AccessHash(), + recoverableMessage, recoverableMessageLength, + ma.m_presignature, ma.m_presignature.size(), + ma.m_semisignature); + } + + size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const + { + this->GetMaterial().DoQuickSanityCheck(); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PrivateKey &key = this->GetKeyInterface(); + + SecByteBlock representative(this->MessageRepresentativeLength()); + this->GetMessageEncodingInterface().ComputeMessageRepresentative( + rng, + ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), this->GetHashIdentifier(), ma.m_empty, + representative, this->MessageRepresentativeBitLength()); + ma.m_empty = true; + Integer e(representative, representative.size()); + + // hash message digest into random number k to prevent reusing the same k on + // different messages after virtual machine rollback + if (rng.CanIncorporateEntropy()) + rng.IncorporateEntropy(representative, representative.size()); + + Integer k, ks; + const Integer& q = params.GetSubgroupOrder(); + if (alg.IsDeterministic()) + { + const Integer& x = key.GetPrivateExponent(); + const DeterministicSignatureAlgorithm& det = dynamic_cast(alg); + k = det.GenerateRandom(x, q, e); + } + else + { + k.Randomize(rng, 1, params.GetSubgroupOrder()-1); + } + + // Due to timing attack on nonce length by Jancar + // https://github.com/weidai11/cryptopp/issues/869 + ks = k + q; + if (ks.BitCount() == q.BitCount()) { + ks += q; + } + + Integer r, s; + r = params.ConvertElementToInteger(params.ExponentiateBase(ks)); + alg.Sign(params, key.GetPrivateExponent(), k, e, r, s); + + /* + Integer r, s; + if (this->MaxRecoverableLength() > 0) + r.Decode(ma.m_semisignature, ma.m_semisignature.size()); + else + r.Decode(ma.m_presignature, ma.m_presignature.size()); + alg.Sign(params, key.GetPrivateExponent(), ma.m_k, e, r, s); + */ + + const size_t rLen = alg.RLen(params); + r.Encode(signature, rLen); + s.Encode(signature+rLen, alg.SLen(params)); + + if (restart) + RestartMessageAccumulator(rng, ma); + + return this->SignatureLength(); + } + +protected: + void RestartMessageAccumulator(RandomNumberGenerator &rng, PK_MessageAccumulatorBase &ma) const + { + // k needs to be generated before hashing for signature schemes with recovery + // but to defend against VM rollbacks we need to generate k after hashing. + // so this code is commented out, since no DL-based signature scheme with recovery + // has been implemented in Crypto++ anyway + /* + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + ma.m_k.Randomize(rng, 1, params.GetSubgroupOrder()-1); + ma.m_presignature.New(params.GetEncodedElementSize(false)); + params.ConvertElementToInteger(params.ExponentiateBase(ma.m_k)).Encode(ma.m_presignature, ma.m_presignature.size()); + */ + CRYPTOPP_UNUSED(rng); CRYPTOPP_UNUSED(ma); + } +}; + +/// \brief Discret Log (DL) Verifier base class +/// \tparam T Field element type or class +/// \details Field element T can be Integer, ECP or EC2N. +template +class CRYPTOPP_NO_VTABLE DL_VerifierBase : public DL_SignatureSchemeBase > +{ +public: + virtual ~DL_VerifierBase() {} + + void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const + { + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + + // Validation due to https://github.com/weidai11/cryptopp/issues/981 + // We allow a caller to provide R and S in oversized buffer. R and S + // are read based on the field element size, and not the buffer size. + const size_t rLen = alg.RLen(params); + const size_t sLen = alg.SLen(params); + CRYPTOPP_ASSERT(signatureLength >= rLen + sLen); + if (signatureLength < rLen + sLen) + throw InvalidDataFormat("DL_VerifierBase: signature length is not valid."); + + ma.m_semisignature.Assign(signature, rLen); + ma.m_s.Decode(signature+rLen, sLen); + + this->GetMessageEncodingInterface().ProcessSemisignature(ma.AccessHash(), ma.m_semisignature, ma.m_semisignature.size()); + } + + bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const + { + this->GetMaterial().DoQuickSanityCheck(); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PublicKey &key = this->GetKeyInterface(); + + SecByteBlock representative(this->MessageRepresentativeLength()); + this->GetMessageEncodingInterface().ComputeMessageRepresentative(NullRNG(), ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), this->GetHashIdentifier(), ma.m_empty, + representative, this->MessageRepresentativeBitLength()); + ma.m_empty = true; + Integer e(representative, representative.size()); + + Integer r(ma.m_semisignature, ma.m_semisignature.size()); + return alg.Verify(params, key, e, r, ma.m_s); + } + + DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const + { + this->GetMaterial().DoQuickSanityCheck(); + + PK_MessageAccumulatorBase &ma = static_cast(messageAccumulator); + const DL_ElgamalLikeSignatureAlgorithm &alg = this->GetSignatureAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PublicKey &key = this->GetKeyInterface(); + + SecByteBlock representative(this->MessageRepresentativeLength()); + this->GetMessageEncodingInterface().ComputeMessageRepresentative( + NullRNG(), + ma.m_recoverableMessage, ma.m_recoverableMessage.size(), + ma.AccessHash(), this->GetHashIdentifier(), ma.m_empty, + representative, this->MessageRepresentativeBitLength()); + ma.m_empty = true; + Integer e(representative, representative.size()); + + ma.m_presignature.New(params.GetEncodedElementSize(false)); + Integer r(ma.m_semisignature, ma.m_semisignature.size()); + alg.RecoverPresignature(params, key, r, ma.m_s).Encode(ma.m_presignature, ma.m_presignature.size()); + + return this->GetMessageEncodingInterface().RecoverMessageFromSemisignature( + ma.AccessHash(), this->GetHashIdentifier(), + ma.m_presignature, ma.m_presignature.size(), + ma.m_semisignature, ma.m_semisignature.size(), + recoveredMessage); + } +}; + +/// \brief Discrete Log (DL) cryptosystem base implementation +/// \tparam PK field element type +/// \tparam KI public or private key interface +template +class CRYPTOPP_NO_VTABLE DL_CryptoSystemBase : public PK, public DL_Base +{ +public: + typedef typename DL_Base::Element Element; + + virtual ~DL_CryptoSystemBase() {} + + size_t MaxPlaintextLength(size_t ciphertextLength) const + { + unsigned int minLen = this->GetAbstractGroupParameters().GetEncodedElementSize(true); + return ciphertextLength < minLen ? 0 : GetSymmetricEncryptionAlgorithm().GetMaxSymmetricPlaintextLength(ciphertextLength - minLen); + } + + size_t CiphertextLength(size_t plaintextLength) const + { + size_t len = GetSymmetricEncryptionAlgorithm().GetSymmetricCiphertextLength(plaintextLength); + return len == 0 ? 0 : this->GetAbstractGroupParameters().GetEncodedElementSize(true) + len; + } + + bool ParameterSupported(const char *name) const + {return GetKeyDerivationAlgorithm().ParameterSupported(name) || GetSymmetricEncryptionAlgorithm().ParameterSupported(name);} + +protected: + virtual const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const =0; + virtual const DL_KeyDerivationAlgorithm & GetKeyDerivationAlgorithm() const =0; + virtual const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const =0; +}; + +/// \brief Discrete Log (DL) decryptor base implementation +/// \tparam T Field element type or class +/// \details Field element T can be Integer, ECP or EC2N. +template +class CRYPTOPP_NO_VTABLE DL_DecryptorBase : public DL_CryptoSystemBase > +{ +public: + typedef T Element; + + virtual ~DL_DecryptorBase() {} + + DecodingResult Decrypt(RandomNumberGenerator &rng, const byte *ciphertext, size_t ciphertextLength, byte *plaintext, const NameValuePairs ¶meters = g_nullNameValuePairs) const + { + try + { + CRYPTOPP_UNUSED(rng); + const DL_KeyAgreementAlgorithm &agreeAlg = this->GetKeyAgreementAlgorithm(); + const DL_KeyDerivationAlgorithm &derivAlg = this->GetKeyDerivationAlgorithm(); + const DL_SymmetricEncryptionAlgorithm &encAlg = this->GetSymmetricEncryptionAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PrivateKey &key = this->GetKeyInterface(); + + Element q = params.DecodeElement(ciphertext, true); + size_t elementSize = params.GetEncodedElementSize(true); + ciphertext += elementSize; + ciphertextLength -= elementSize; + + Element z = agreeAlg.AgreeWithStaticPrivateKey(params, q, true, key.GetPrivateExponent()); + + SecByteBlock derivedKey(encAlg.GetSymmetricKeyLength(encAlg.GetMaxSymmetricPlaintextLength(ciphertextLength))); + derivAlg.Derive(params, derivedKey, derivedKey.size(), z, q, parameters); + + return encAlg.SymmetricDecrypt(derivedKey, ciphertext, ciphertextLength, plaintext, parameters); + } + catch (DL_BadElement &) + { + return DecodingResult(); + } + } +}; + +/// \brief Discrete Log (DL) encryptor base implementation +/// \tparam T Field element type or class +/// \details Field element T can be Integer, ECP or EC2N. +template +class CRYPTOPP_NO_VTABLE DL_EncryptorBase : public DL_CryptoSystemBase > +{ +public: + typedef T Element; + + virtual ~DL_EncryptorBase() {} + + void Encrypt(RandomNumberGenerator &rng, const byte *plaintext, size_t plaintextLength, byte *ciphertext, const NameValuePairs ¶meters = g_nullNameValuePairs) const + { + const DL_KeyAgreementAlgorithm &agreeAlg = this->GetKeyAgreementAlgorithm(); + const DL_KeyDerivationAlgorithm &derivAlg = this->GetKeyDerivationAlgorithm(); + const DL_SymmetricEncryptionAlgorithm &encAlg = this->GetSymmetricEncryptionAlgorithm(); + const DL_GroupParameters ¶ms = this->GetAbstractGroupParameters(); + const DL_PublicKey &key = this->GetKeyInterface(); + + Integer x(rng, Integer::One(), params.GetMaxExponent()); + Element q = params.ExponentiateBase(x); + params.EncodeElement(true, q, ciphertext); + unsigned int elementSize = params.GetEncodedElementSize(true); + ciphertext += elementSize; + + Element z = agreeAlg.AgreeWithEphemeralPrivateKey(params, key.GetPublicPrecomputation(), x); + + SecByteBlock derivedKey(encAlg.GetSymmetricKeyLength(plaintextLength)); + derivAlg.Derive(params, derivedKey, derivedKey.size(), z, q, parameters); + + encAlg.SymmetricEncrypt(rng, derivedKey, plaintext, plaintextLength, ciphertext, parameters); + } +}; + +/// \brief Discrete Log (DL) scheme options +/// \tparam T1 algorithm information +/// \tparam T2 group parameters for the scheme +template +struct DL_SchemeOptionsBase +{ + typedef T1 AlgorithmInfo; + typedef T2 GroupParameters; + typedef typename GroupParameters::Element Element; +}; + +/// \brief Discrete Log (DL) key options +/// \tparam T1 algorithm information +/// \tparam T2 keys used in the scheme +template +struct DL_KeyedSchemeOptions : public DL_SchemeOptionsBase +{ + typedef T2 Keys; + typedef typename Keys::PrivateKey PrivateKey; + typedef typename Keys::PublicKey PublicKey; +}; + +/// \brief Discrete Log (DL) signature scheme options +/// \tparam T1 algorithm information +/// \tparam T2 keys used in the scheme +/// \tparam T3 signature algorithm +/// \tparam T4 message encoding method +/// \tparam T5 hash function +template +struct DL_SignatureSchemeOptions : public DL_KeyedSchemeOptions +{ + typedef T3 SignatureAlgorithm; + typedef T4 MessageEncodingMethod; + typedef T5 HashFunction; +}; + +/// \brief Discrete Log (DL) crypto scheme options +/// \tparam T1 algorithm information +/// \tparam T2 keys used in the scheme +/// \tparam T3 key agreement algorithm +/// \tparam T4 key derivation algorithm +/// \tparam T5 symmetric encryption algorithm +template +struct DL_CryptoSchemeOptions : public DL_KeyedSchemeOptions +{ + typedef T3 KeyAgreementAlgorithm; + typedef T4 KeyDerivationAlgorithm; + typedef T5 SymmetricEncryptionAlgorithm; +}; + +/// \brief Discrete Log (DL) base object implementation +/// \tparam BASE TODO +/// \tparam SCHEME_OPTIONS options for the scheme +/// \tparam KEY key used in the scheme +template +class CRYPTOPP_NO_VTABLE DL_ObjectImplBase : public AlgorithmImpl +{ +public: + typedef SCHEME_OPTIONS SchemeOptions; + typedef typename KEY::Element Element; + + virtual ~DL_ObjectImplBase() {} + + PrivateKey & AccessPrivateKey() {return m_key;} + PublicKey & AccessPublicKey() {return m_key;} + + // KeyAccessor + const KEY & GetKey() const {return m_key;} + KEY & AccessKey() {return m_key;} + +protected: + typename BASE::KeyInterface & AccessKeyInterface() {return m_key;} + const typename BASE::KeyInterface & GetKeyInterface() const {return m_key;} + + // for signature scheme + HashIdentifier GetHashIdentifier() const + { + typedef typename SchemeOptions::MessageEncodingMethod::HashIdentifierLookup HashLookup; + return HashLookup::template HashIdentifierLookup2::Lookup(); + } + size_t GetDigestSize() const + { + typedef typename SchemeOptions::HashFunction H; + return H::DIGESTSIZE; + } + +private: + KEY m_key; +}; + +/// \brief Discrete Log (DL) object implementation +/// \tparam BASE TODO +/// \tparam SCHEME_OPTIONS options for the scheme +/// \tparam KEY key used in the scheme +template +class CRYPTOPP_NO_VTABLE DL_ObjectImpl : public DL_ObjectImplBase +{ +public: + typedef typename KEY::Element Element; + + virtual ~DL_ObjectImpl() {} + +protected: + const DL_ElgamalLikeSignatureAlgorithm & GetSignatureAlgorithm() const + {return Singleton().Ref();} + const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const + {return Singleton().Ref();} + const DL_KeyDerivationAlgorithm & GetKeyDerivationAlgorithm() const + {return Singleton().Ref();} + const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const + {return Singleton().Ref();} + HashIdentifier GetHashIdentifier() const + {return HashIdentifier();} + const PK_SignatureMessageEncodingMethod & GetMessageEncodingInterface() const + {return Singleton().Ref();} +}; + +/// \brief Discrete Log (DL) signer implementation +/// \tparam SCHEME_OPTIONS options for the scheme +template +class DL_SignerImpl : public DL_ObjectImpl, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PrivateKey> +{ +public: + PK_MessageAccumulator * NewSignatureAccumulator(RandomNumberGenerator &rng) const + { + member_ptr p(new PK_MessageAccumulatorImpl); + this->RestartMessageAccumulator(rng, *p); + return p.release(); + } +}; + +/// \brief Discrete Log (DL) verifier implementation +/// \tparam SCHEME_OPTIONS options for the scheme +template +class DL_VerifierImpl : public DL_ObjectImpl, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PublicKey> +{ +public: + PK_MessageAccumulator * NewVerificationAccumulator() const + { + return new PK_MessageAccumulatorImpl; + } +}; + +/// \brief Discrete Log (DL) encryptor implementation +/// \tparam SCHEME_OPTIONS options for the scheme +template +class DL_EncryptorImpl : public DL_ObjectImpl, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PublicKey> +{ +}; + +/// \brief Discrete Log (DL) decryptor implementation +/// \tparam SCHEME_OPTIONS options for the scheme +template +class DL_DecryptorImpl : public DL_ObjectImpl, SCHEME_OPTIONS, typename SCHEME_OPTIONS::PrivateKey> +{ +}; + +// ******************************************************** + +/// \brief Discrete Log (DL) simple key agreement base implementation +/// \tparam T class or type +template +class CRYPTOPP_NO_VTABLE DL_SimpleKeyAgreementDomainBase : public SimpleKeyAgreementDomain +{ +public: + typedef T Element; + + virtual ~DL_SimpleKeyAgreementDomainBase() {} + + CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();} + unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);} + unsigned int PrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();} + unsigned int PublicKeyLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(true);} + + void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const + { + Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent()); + x.Encode(privateKey, PrivateKeyLength()); + } + + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const + { + CRYPTOPP_UNUSED(rng); + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, PrivateKeyLength()); + Element y = params.ExponentiateBase(x); + params.EncodeElement(true, y, publicKey); + } + + bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const + { + try + { + const DL_GroupParameters ¶ms = GetAbstractGroupParameters(); + Integer x(privateKey, PrivateKeyLength()); + Element w = params.DecodeElement(otherPublicKey, validateOtherPublicKey); + + Element z = GetKeyAgreementAlgorithm().AgreeWithStaticPrivateKey( + GetAbstractGroupParameters(), w, validateOtherPublicKey, x); + params.EncodeElement(false, z, agreedValue); + } + catch (DL_BadElement &) + { + return false; + } + return true; + } + + /// \brief Retrieves a reference to the group generator + /// \return const reference to the group generator + const Element &GetGenerator() const {return GetAbstractGroupParameters().GetSubgroupGenerator();} + +protected: + virtual const DL_KeyAgreementAlgorithm & GetKeyAgreementAlgorithm() const =0; + virtual DL_GroupParameters & AccessAbstractGroupParameters() =0; + const DL_GroupParameters & GetAbstractGroupParameters() const {return const_cast *>(this)->AccessAbstractGroupParameters();} +}; + +/// \brief Methods for avoiding "Small-Subgroup" attacks on Diffie-Hellman Key Agreement +/// \details Additional methods exist and include public key validation and choice of prime p. +/// \sa Methods for Avoiding the "Small-Subgroup" Attacks on the +/// Diffie-Hellman Key Agreement Method for S/MIME +enum CofactorMultiplicationOption { + /// \brief No cofactor multiplication applied + NO_COFACTOR_MULTIPLICTION, + /// \brief Cofactor multiplication compatible with ordinary Diffie-Hellman + /// \details Modifies the computation of ZZ by including j (the cofactor) in the computations and is + /// compatible with ordinary Diffie-Hellman. + COMPATIBLE_COFACTOR_MULTIPLICTION, + /// \brief Cofactor multiplication incompatible with ordinary Diffie-Hellman + /// \details Modifies the computation of ZZ by including j (the cofactor) in the computations but is + /// not compatible with ordinary Diffie-Hellman. + INCOMPATIBLE_COFACTOR_MULTIPLICTION}; + +typedef EnumToType NoCofactorMultiplication; +typedef EnumToType CompatibleCofactorMultiplication; +typedef EnumToType IncompatibleCofactorMultiplication; + +/// \brief Diffie-Hellman key agreement algorithm +template +class DL_KeyAgreementAlgorithm_DH : public DL_KeyAgreementAlgorithm +{ +public: + typedef ELEMENT Element; + + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() + {return COFACTOR_OPTION::ToEnum() == INCOMPATIBLE_COFACTOR_MULTIPLICTION ? "DHC" : "DH";} + + virtual ~DL_KeyAgreementAlgorithm_DH() {} + + Element AgreeWithEphemeralPrivateKey(const DL_GroupParameters ¶ms, const DL_FixedBasePrecomputation &publicPrecomputation, const Integer &privateExponent) const + { + return publicPrecomputation.Exponentiate(params.GetGroupPrecomputation(), + COFACTOR_OPTION::ToEnum() == INCOMPATIBLE_COFACTOR_MULTIPLICTION ? privateExponent*params.GetCofactor() : privateExponent); + } + + Element AgreeWithStaticPrivateKey(const DL_GroupParameters ¶ms, const Element &publicElement, bool validateOtherPublicKey, const Integer &privateExponent) const + { + if (COFACTOR_OPTION::ToEnum() == COMPATIBLE_COFACTOR_MULTIPLICTION) + { + const Integer &k = params.GetCofactor(); + return params.ExponentiateElement(publicElement, + ModularArithmetic(params.GetSubgroupOrder()).Divide(privateExponent, k)*k); + } + else if (COFACTOR_OPTION::ToEnum() == INCOMPATIBLE_COFACTOR_MULTIPLICTION) + return params.ExponentiateElement(publicElement, privateExponent*params.GetCofactor()); + else + { + CRYPTOPP_ASSERT(COFACTOR_OPTION::ToEnum() == NO_COFACTOR_MULTIPLICTION); + + if (!validateOtherPublicKey) + return params.ExponentiateElement(publicElement, privateExponent); + + if (params.FastSubgroupCheckAvailable()) + { + if (!params.ValidateElement(2, publicElement, NULLPTR)) + throw DL_BadElement(); + return params.ExponentiateElement(publicElement, privateExponent); + } + else + { + const Integer e[2] = {params.GetSubgroupOrder(), privateExponent}; + Element r[2]; + params.SimultaneousExponentiate(r, publicElement, e, 2); + if (!params.IsIdentity(r[0])) + throw DL_BadElement(); + return r[1]; + } + } + } +}; + +// ******************************************************** + +/// \brief Template implementing constructors for public key algorithm classes +template +class CRYPTOPP_NO_VTABLE PK_FinalTemplate : public BASE +{ +public: + PK_FinalTemplate() {} + + PK_FinalTemplate(const CryptoMaterial &key) + {this->AccessKey().AssignFrom(key);} + + PK_FinalTemplate(BufferedTransformation &bt) + {this->AccessKey().BERDecode(bt);} + + PK_FinalTemplate(const AsymmetricAlgorithm &algorithm) + {this->AccessKey().AssignFrom(algorithm.GetMaterial());} + + PK_FinalTemplate(const Integer &v1) + {this->AccessKey().Initialize(v1);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2) + {this->AccessKey().Initialize(v1, v2);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3) + {this->AccessKey().Initialize(v1, v2, v3);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {this->AccessKey().Initialize(v1, v2, v3, v4);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7);} + + template + PK_FinalTemplate(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7, v8);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2) + {this->AccessKey().Initialize(v1, v2);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3) + {this->AccessKey().Initialize(v1, v2, v3);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) + {this->AccessKey().Initialize(v1, v2, v3, v4);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7);} + + template + PK_FinalTemplate(T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5, const T6 &v6, const T7 &v7, const T8 &v8) + {this->AccessKey().Initialize(v1, v2, v3, v4, v5, v6, v7, v8);} +}; + +/// \brief Base class for public key encryption standard classes. +/// \details These classes are used to select from variants of algorithms. +/// Not all standards apply to all algorithms. +struct EncryptionStandard {}; + +/// \brief Base class for public key signature standard classes. +/// \details These classes are used to select from variants of algorithms. +/// Not all standards apply to all algorithms. +struct SignatureStandard {}; + +/// \brief Trapdoor Function (TF) encryption scheme +/// \tparam STANDARD standard +/// \tparam KEYS keys used in the encryption scheme +/// \tparam ALG_INFO algorithm information +template +class TF_ES; + +template > +class TF_ES : public KEYS +{ + typedef typename STANDARD::EncryptionMessageEncodingMethod MessageEncodingMethod; + +public: + /// see EncryptionStandard for a list of standards + typedef STANDARD Standard; + typedef TF_CryptoSchemeOptions SchemeOptions; + + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string(KEYS::StaticAlgorithmName()) + "/" + MessageEncodingMethod::StaticAlgorithmName();} + + /// implements PK_Decryptor interface + typedef PK_FinalTemplate > Decryptor; + /// implements PK_Encryptor interface + typedef PK_FinalTemplate > Encryptor; +}; + +/// \brief Trapdoor Function (TF) Signature Scheme +/// \tparam STANDARD standard +/// \tparam H hash function +/// \tparam KEYS keys used in the signature scheme +/// \tparam ALG_INFO algorithm information +template +class TF_SS; + +template > +class TF_SS : public KEYS +{ +public: + /// see SignatureStandard for a list of standards + typedef STANDARD Standard; + typedef typename Standard::SignatureMessageEncodingMethod MessageEncodingMethod; + typedef TF_SignatureSchemeOptions SchemeOptions; + + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string(KEYS::StaticAlgorithmName()) + "/" + MessageEncodingMethod::StaticAlgorithmName() + "(" + H::StaticAlgorithmName() + ")";} + + /// implements PK_Signer interface + typedef PK_FinalTemplate > Signer; + /// implements PK_Verifier interface + typedef PK_FinalTemplate > Verifier; +}; + +/// \brief Discrete Log (DL) signature scheme +/// \tparam KEYS keys used in the signature scheme +/// \tparam SA signature algorithm +/// \tparam MEM message encoding method +/// \tparam H hash function +/// \tparam ALG_INFO algorithm information +template +class DL_SS; + +template > +class DL_SS : public KEYS +{ + typedef DL_SignatureSchemeOptions SchemeOptions; + +public: + static std::string StaticAlgorithmName() {return SA::StaticAlgorithmName() + std::string("/EMSA1(") + H::StaticAlgorithmName() + ")";} + + /// implements PK_Signer interface + typedef PK_FinalTemplate > Signer; + /// implements PK_Verifier interface + typedef PK_FinalTemplate > Verifier; +}; + +/// \brief Discrete Log (DL) encryption scheme +/// \tparam KEYS keys used in the encryption scheme +/// \tparam AA key agreement algorithm +/// \tparam DA key derivation algorithm +/// \tparam EA encryption algorithm +/// \tparam ALG_INFO algorithm information +template +class DL_ES : public KEYS +{ + typedef DL_CryptoSchemeOptions SchemeOptions; + +public: + /// implements PK_Decryptor interface + typedef PK_FinalTemplate > Decryptor; + /// implements PK_Encryptor interface + typedef PK_FinalTemplate > Encryptor; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/pwdbased.h b/third_party/cryptoppwin/include/cryptopp/pwdbased.h new file mode 100644 index 00000000..49cf53c7 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/pwdbased.h @@ -0,0 +1,481 @@ +// pwdbased.h - originally written and placed in the public domain by Wei Dai +// Cutover to KeyDerivationFunction interface by Uri Blumenthal +// Marcel Raad and Jeffrey Walton in March 2018. + +/// \file pwdbased.h +/// \brief Password based key derivation functions + +#ifndef CRYPTOPP_PWDBASED_H +#define CRYPTOPP_PWDBASED_H + +#include "cryptlib.h" +#include "hrtimer.h" +#include "integer.h" +#include "argnames.h" +#include "algparam.h" +#include "hmac.h" + +NAMESPACE_BEGIN(CryptoPP) + +// ******************** PBKDF1 ******************** + +/// \brief PBKDF1 from PKCS #5 +/// \tparam T a HashTransformation class +/// \sa PasswordBasedKeyDerivationFunction, PKCS5_PBKDF1 +/// on the Crypto++ wiki +/// \since Crypto++ 2.0 +template +class PKCS5_PBKDF1 : public PasswordBasedKeyDerivationFunction +{ +public: + virtual ~PKCS5_PBKDF1() {} + + static std::string StaticAlgorithmName () { + const std::string name(std::string("PBKDF1(") + + std::string(T::StaticAlgorithmName()) + std::string(")")); + return name; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // KeyDerivationFunction interface + size_t MaxDerivedKeyLength() const { + return static_cast(T::DIGESTSIZE); + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + virtual size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params = g_nullNameValuePairs) const; + + /// \brief Derive a key from a secret seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param purpose a purpose byte + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param iterations the number of iterations + /// \param timeInSeconds the in seconds + /// \return the number of iterations performed + /// \throw InvalidDerivedKeyLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details If timeInSeconds is > 0.0 then DeriveKey will run for + /// the specified amount of time. If timeInSeconds is 0.0 then DeriveKey + /// will run for the specified number of iterations. + /// \details PKCS #5 says PBKDF1 should only take 8-byte salts. This implementation + /// allows salts of any length. + size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const; + +protected: + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } +}; + +template +size_t PKCS5_PBKDF1::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedKeyLength()) + return MaxDerivedKeyLength(); + return keylength; +} + +template +size_t PKCS5_PBKDF1::DeriveKey(byte *derived, size_t derivedLen, + const byte *secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + + byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0); + unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1); + + double timeInSeconds = 0.0f; + (void)params.GetValue("TimeInSeconds", timeInSeconds); + + ConstByteArrayParameter salt; + (void)params.GetValue(Name::Salt(), salt); + + return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds); +} + +template +size_t PKCS5_PBKDF1::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0); + CRYPTOPP_UNUSED(purpose); + + ThrowIfInvalidDerivedKeyLength(derivedLen); + + // Business logic + if (!iterations) { iterations = 1; } + + T hash; + hash.Update(secret, secretLen); + hash.Update(salt, saltLen); + + SecByteBlock buffer(hash.DigestSize()); + hash.Final(buffer); + + unsigned int i; + ThreadUserTimer timer; + + if (timeInSeconds) + timer.StartTimer(); + + for (i=1; iPKCS5_PBKDF2_HMAC +/// on the Crypto++ wiki +/// \since Crypto++ 2.0 +template +class PKCS5_PBKDF2_HMAC : public PasswordBasedKeyDerivationFunction +{ +public: + virtual ~PKCS5_PBKDF2_HMAC() {} + + static std::string StaticAlgorithmName () { + const std::string name(std::string("PBKDF2_HMAC(") + + std::string(T::StaticAlgorithmName()) + std::string(")")); + return name; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // KeyDerivationFunction interface + // should multiply by T::DIGESTSIZE, but gets overflow that way + size_t MaxDerivedKeyLength() const { + return 0xffffffffU; + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params = g_nullNameValuePairs) const; + + /// \brief Derive a key from a secret seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param purpose a purpose byte + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param iterations the number of iterations + /// \param timeInSeconds the in seconds + /// \return the number of iterations performed + /// \throw InvalidDerivedKeyLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details If timeInSeconds is > 0.0 then DeriveKey will run for + /// the specified amount of time. If timeInSeconds is 0.0 then DeriveKey + /// will run for the specified number of iterations. + size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const; + +protected: + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } +}; + +template +size_t PKCS5_PBKDF2_HMAC::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedKeyLength()) + return MaxDerivedKeyLength(); + return keylength; +} + +template +size_t PKCS5_PBKDF2_HMAC::DeriveKey(byte *derived, size_t derivedLen, + const byte *secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + + byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0); + unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1); + + double timeInSeconds = 0.0f; + (void)params.GetValue("TimeInSeconds", timeInSeconds); + + ConstByteArrayParameter salt; + (void)params.GetValue(Name::Salt(), salt); + + return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds); +} + +template +size_t PKCS5_PBKDF2_HMAC::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0); + CRYPTOPP_UNUSED(purpose); + + ThrowIfInvalidDerivedKeyLength(derivedLen); + + // Business logic + if (!iterations) { iterations = 1; } + + // DigestSize check due to https://github.com/weidai11/cryptopp/issues/855 + HMAC hmac(secret, secretLen); + if (hmac.DigestSize() == 0) + throw InvalidArgument("PKCS5_PBKDF2_HMAC: DigestSize cannot be 0"); + + SecByteBlock buffer(hmac.DigestSize()); + ThreadUserTimer timer; + + unsigned int i=1; + while (derivedLen > 0) + { + hmac.Update(salt, saltLen); + unsigned int j; + for (j=0; j<4; j++) + { + byte b = byte(i >> ((3-j)*8)); + hmac.Update(&b, 1); + } + hmac.Final(buffer); + +#if CRYPTOPP_MSC_VERSION + const size_t segmentLen = STDMIN(derivedLen, buffer.size()); + memcpy_s(derived, segmentLen, buffer, segmentLen); +#else + const size_t segmentLen = STDMIN(derivedLen, buffer.size()); + std::memcpy(derived, buffer, segmentLen); +#endif + + if (timeInSeconds) + { + timeInSeconds = timeInSeconds / ((derivedLen + buffer.size() - 1) / buffer.size()); + timer.StartTimer(); + } + + for (j=1; jPKCS12_PBKDF +/// on the Crypto++ wiki +/// \since Crypto++ 2.0 +template +class PKCS12_PBKDF : public PasswordBasedKeyDerivationFunction +{ +public: + virtual ~PKCS12_PBKDF() {} + + static std::string StaticAlgorithmName () { + const std::string name(std::string("PBKDF_PKCS12(") + + std::string(T::StaticAlgorithmName()) + std::string(")")); + return name; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // TODO - check this + size_t MaxDerivedKeyLength() const { + return static_cast(-1); + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params = g_nullNameValuePairs) const; + + /// \brief Derive a key from a secret seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param purpose a purpose byte + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param iterations the number of iterations + /// \param timeInSeconds the in seconds + /// \return the number of iterations performed + /// \throw InvalidDerivedKeyLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details If timeInSeconds is > 0.0 then DeriveKey will run for + /// the specified amount of time. If timeInSeconds is 0.0 then DeriveKey + /// will run for the specified number of iterations. + size_t DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const; + +protected: + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } +}; + +template +size_t PKCS12_PBKDF::GetValidDerivedLength(size_t keylength) const +{ + if (keylength > MaxDerivedKeyLength()) + return MaxDerivedKeyLength(); + return keylength; +} + +template +size_t PKCS12_PBKDF::DeriveKey(byte *derived, size_t derivedLen, + const byte *secret, size_t secretLen, const NameValuePairs& params) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + + byte purpose = (byte)params.GetIntValueWithDefault("Purpose", 0); + unsigned int iterations = (unsigned int)params.GetIntValueWithDefault("Iterations", 1); + + double timeInSeconds = 0.0f; + (void)params.GetValue("TimeInSeconds", timeInSeconds); + + // NULL or 0 length salt OK + ConstByteArrayParameter salt; + (void)params.GetValue(Name::Salt(), salt); + + return DeriveKey(derived, derivedLen, purpose, secret, secretLen, salt.begin(), salt.size(), iterations, timeInSeconds); +} + +template +size_t PKCS12_PBKDF::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const +{ + CRYPTOPP_ASSERT(secret /*&& secretLen*/); + CRYPTOPP_ASSERT(derived && derivedLen); + CRYPTOPP_ASSERT(derivedLen <= MaxDerivedKeyLength()); + CRYPTOPP_ASSERT(iterations > 0 || timeInSeconds > 0); + + ThrowIfInvalidDerivedKeyLength(derivedLen); + + // Business logic + if (!iterations) { iterations = 1; } + + const size_t v = T::BLOCKSIZE; // v is in bytes rather than bits as in PKCS #12 + const size_t DLen = v, SLen = RoundUpToMultipleOf(saltLen, v); + const size_t PLen = RoundUpToMultipleOf(secretLen, v), ILen = SLen + PLen; + SecByteBlock buffer(DLen + SLen + PLen); + byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S; + + if (D) // GCC analyzer + std::memset(D, purpose, DLen); + + size_t i; + for (i=0; i 0) + { + hash.CalculateDigest(Ai, buffer, buffer.size()); + + if (timeInSeconds) + { + timeInSeconds = timeInSeconds / ((derivedLen + Ai.size() - 1) / Ai.size()); + timer.StartTimer(); + } + + for (i=1; iByteQueue +/// on the Crypto++ wiki. +/// \since Crypto++ 2.0 +class CRYPTOPP_DLL ByteQueue : public Bufferless +{ +public: + virtual ~ByteQueue(); + + /// \brief Construct a ByteQueue + /// \param nodeSize the initial node size + /// \details Internally, ByteQueue uses a ByteQueueNode to store bytes, + /// and nodeSize determines the size of the ByteQueueNode. A value + /// of 0 indicates the ByteQueueNode should be automatically sized, + /// which means a value of 256 is used. + ByteQueue(size_t nodeSize=0); + + /// \brief Copy construct a ByteQueue + /// \param copy the other ByteQueue + ByteQueue(const ByteQueue ©); + + // BufferedTransformation + lword MaxRetrievable() const + {return CurrentSize();} + bool AnyRetrievable() const + {return !IsEmpty();} + + void IsolatedInitialize(const NameValuePairs ¶meters); + byte * CreatePutSpace(size_t &size); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + + size_t Get(byte &outByte); + size_t Get(byte *outString, size_t getMax); + + size_t Peek(byte &outByte) const; + size_t Peek(byte *outString, size_t peekMax) const; + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + /// \brief Set node size + /// \param nodeSize the new node size, in bytes + /// \details The default node size is 256. + void SetNodeSize(size_t nodeSize); + + /// \brief Determine data size + /// \return the data size, in bytes + lword CurrentSize() const; + + /// \brief Determine data availability + /// \return true if the ByteQueue has data, false otherwise + bool IsEmpty() const; + + /// \brief Empty the queue + void Clear(); + + /// \brief Insert data in the queue + /// \param inByte a byte to insert + /// \details Unget() inserts a byte at the head of the queue + void Unget(byte inByte); + + /// \brief Insert data in the queue + /// \param inString a byte array to insert + /// \param length the size of the byte array + /// \details Unget() inserts a byte array at the head of the queue + void Unget(const byte *inString, size_t length); + + /// \brief Peek data in the queue + /// \param contiguousSize the size of the data + /// \details Spy() peeks at data at the head of the queue. Spy() does + /// not remove data from the queue. + /// \details The data's size is returned in contiguousSize. + /// Spy() returns the size of the first byte array in the list. The + /// entire data may be larger since the queue is a linked list of + /// byte arrays. + const byte * Spy(size_t &contiguousSize) const; + + /// \brief Insert data in the queue + /// \param inString a byte array to insert + /// \param size the length of the byte array + /// \details LazyPut() inserts a byte array at the tail of the queue. + /// The data may not be copied at this point. Rather, the pointer + /// and size to external data are recorded. + /// \details Another call to Put() or LazyPut() will force the data to + /// be copied. When lazy puts are used, the data is copied when + /// FinalizeLazyPut() is called. + /// \sa LazyPutter + void LazyPut(const byte *inString, size_t size); + + /// \brief Insert data in the queue + /// \param inString a byte array to insert + /// \param size the length of the byte array + /// \details LazyPut() inserts a byte array at the tail of the queue. + /// The data may not be copied at this point. Rather, the pointer + /// and size to external data are recorded. + /// \details Another call to Put() or LazyPut() will force the data to + /// be copied. When lazy puts are used, the data is copied when + /// FinalizeLazyPut() is called. + /// \sa LazyPutter + void LazyPutModifiable(byte *inString, size_t size); + + /// \brief Remove data from the queue + /// \param size the length of the data + /// \throw InvalidArgument if there is no lazy data in the queue or if + /// size is larger than the lazy string + /// \details UndoLazyPut() truncates data inserted using LazyPut() by + /// modifying size. + /// \sa LazyPutter + void UndoLazyPut(size_t size); + + /// \brief Insert data in the queue + /// \details FinalizeLazyPut() copies external data inserted using + /// LazyPut() or LazyPutModifiable() into the tail of the queue. + /// \sa LazyPutter + void FinalizeLazyPut(); + + /// \brief Assign contents from another ByteQueue + /// \param rhs the other ByteQueue + /// \return reference to this ByteQueue + ByteQueue & operator=(const ByteQueue &rhs); + + /// \brief Bitwise compare two ByteQueue + /// \param rhs the other ByteQueue + /// \return true if the size and bits are equal, false otherwise + /// \details operator==() walks each ByteQueue comparing bytes in + /// each queue. operator==() is not constant time. + bool operator==(const ByteQueue &rhs) const; + + /// \brief Bitwise compare two ByteQueue + /// \param rhs the other ByteQueue + /// \return true if the size and bits are not equal, false otherwise + /// \details operator!=() is implemented in terms of operator==(). + /// operator==() is not constant time. + bool operator!=(const ByteQueue &rhs) const {return !operator==(rhs);} + + /// \brief Retrieve data from the queue + /// \param index of byte to retrieve + /// \return byte at the specified index + /// \details operator[]() does not perform bounds checking. + byte operator[](lword index) const; + + /// \brief Swap contents with another ByteQueue + /// \param rhs the other ByteQueue + void swap(ByteQueue &rhs); + + /// \brief A ByteQueue iterator + class Walker : public InputRejecting + { + public: + /// \brief Construct a ByteQueue Walker + /// \param queue a ByteQueue + Walker(const ByteQueue &queue) + : m_queue(queue), m_node(NULLPTR), m_position(0), m_offset(0), m_lazyString(NULLPTR), m_lazyLength(0) + {Initialize();} + + lword GetCurrentPosition() {return m_position;} + + lword MaxRetrievable() const + {return m_queue.CurrentSize() - m_position;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + + size_t Get(byte &outByte); + size_t Get(byte *outString, size_t getMax); + + size_t Peek(byte &outByte) const; + size_t Peek(byte *outString, size_t peekMax) const; + + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true); + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const; + + private: + const ByteQueue &m_queue; + const ByteQueueNode *m_node; + lword m_position; + size_t m_offset; + const byte *m_lazyString; + size_t m_lazyLength; + }; + + friend class Walker; + +protected: + void CleanupUsedNodes(); + void CopyFrom(const ByteQueue ©); + void Destroy(); + +private: + ByteQueueNode *m_head, *m_tail; + byte *m_lazyString; + size_t m_lazyLength; + size_t m_nodeSize; + bool m_lazyStringModifiable; + bool m_autoNodeSize; +}; + +/// \brief Helper class to finalize Puts on ByteQueue +/// \details LazyPutter ensures LazyPut is committed to the ByteQueue +/// in event of exception. During destruction, the LazyPutter class +/// calls FinalizeLazyPut. +class CRYPTOPP_DLL LazyPutter +{ +public: + virtual ~LazyPutter() { + try {m_bq.FinalizeLazyPut();} + catch(const Exception&) {CRYPTOPP_ASSERT(0);} + } + + /// \brief Construct a LazyPutter + /// \param bq the ByteQueue + /// \param inString a byte array to insert + /// \param size the length of the byte array + /// \details LazyPutter ensures LazyPut is committed to the ByteQueue + /// in event of exception. During destruction, the LazyPutter class + /// calls FinalizeLazyPut. + LazyPutter(ByteQueue &bq, const byte *inString, size_t size) + : m_bq(bq) {bq.LazyPut(inString, size);} + +protected: + LazyPutter(ByteQueue &bq) : m_bq(bq) {} + +private: + ByteQueue &m_bq; +}; + +/// \brief Helper class to finalize Puts on ByteQueue +/// \details LazyPutterModifiable ensures LazyPut is committed to the +/// ByteQueue in event of exception. During destruction, the +/// LazyPutterModifiable class calls FinalizeLazyPut. +class LazyPutterModifiable : public LazyPutter +{ +public: + /// \brief Construct a LazyPutterModifiable + /// \param bq the ByteQueue + /// \param inString a byte array to insert + /// \param size the length of the byte array + /// \details LazyPutterModifiable ensures LazyPut is committed to the + /// ByteQueue in event of exception. During destruction, the + /// LazyPutterModifiable class calls FinalizeLazyPut. + LazyPutterModifiable(ByteQueue &bq, byte *inString, size_t size) + : LazyPutter(bq) {bq.LazyPutModifiable(inString, size);} +}; + +NAMESPACE_END + +#ifndef __BORLANDC__ +NAMESPACE_BEGIN(std) +template<> inline void swap(CryptoPP::ByteQueue &a, CryptoPP::ByteQueue &b) +{ + a.swap(b); +} +NAMESPACE_END +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/rabbit.h b/third_party/cryptoppwin/include/cryptopp/rabbit.h new file mode 100644 index 00000000..0103091d --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/rabbit.h @@ -0,0 +1,112 @@ +// rabbit.h - written and placed in the public domain by Jeffrey Walton +// based on public domain code by Martin Boesgaard, Mette Vesterager, +// Thomas Pedersen, Jesper Christiansen and Ove Scavenius. +// +// The reference materials and source files are available at +// The eSTREAM Project, http://www.ecrypt.eu.org/stream/e2-rabbit.html. + +/// \file rabbit.h +/// \brief Classes for Rabbit stream cipher +/// \sa The +/// eSTREAM Project | Rabbit and +/// Crypto++ Wiki | Rabbit. +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_RABBIT_H +#define CRYPTOPP_RABBIT_H + +#include "strciphr.h" +#include "secblock.h" + +// The library does not have a way to describe an optional IV. Rabbit takes +// an optional IV so two classes are offered to bridge the gap. One provides +// Rabbit without an IV and the second provides Rabbit with an IV. + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Rabbit stream cipher information +/// \since Crypto++ 8.0 +struct RabbitInfo : public FixedKeyLength<16, SimpleKeyingInterface::NOT_RESYNCHRONIZABLE> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "Rabbit"; } +}; + +/// \brief Rabbit stream cipher information +/// \since Crypto++ 8.0 +struct RabbitWithIVInfo : public FixedKeyLength<16, SimpleKeyingInterface::UNIQUE_IV, 8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "RabbitWithIV"; } +}; + +/// \brief Rabbit stream cipher implementation +/// \since Crypto++ 8.0 +class RabbitPolicy : public AdditiveCipherConcretePolicy, public RabbitInfo +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + bool CanOperateKeystream() const { return true; } + bool CipherIsRandomAccess() const { return false; } + +private: + // Master and working states + FixedSizeSecBlock m_mx, m_mc, m_wx, m_wc; + // Workspace + FixedSizeSecBlock m_t; + word32 m_mcy, m_wcy; // carry +}; + +/// \brief Rabbit stream cipher implementation +/// \since Crypto++ 8.0 +class RabbitWithIVPolicy : public AdditiveCipherConcretePolicy, public RabbitWithIVInfo +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + bool CanOperateKeystream() const { return true; } + bool CipherIsRandomAccess() const { return false; } + +private: + // Master and working states + FixedSizeSecBlock m_mx, m_mc, m_wx, m_wc; + // Workspace + FixedSizeSecBlock m_t; + word32 m_mcy, m_wcy; // carry +}; + +/// \brief Rabbit stream cipher +/// \details Rabbit is a stream cipher developed by Martin Boesgaard, Mette Vesterager, +/// Thomas Pedersen, Jesper Christiansen and Ove Scavenius. Rabbit is one of the final four +/// Profile 1 (software) ciphers selected for the eSTREAM portfolio. +/// \details Crypto++ provides Rabbit and RabbitWithIV classes. Two classes are necessary +/// because the library lacks the means to describe and manage optional IVs. +/// \sa RabbitWithIV, The +/// eSTREAM Project | Rabbit and +/// Crypto++ Wiki | Rabbit. +/// \since Crypto++ 8.0 +struct Rabbit : public RabbitInfo, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, RabbitInfo> Encryption; + typedef Encryption Decryption; +}; + +/// \brief Rabbit stream cipher +/// \details Rabbit is a stream cipher developed by Martin Boesgaard, Mette Vesterager, +/// Thomas Pedersen, Jesper Christiansen and Ove Scavenius. Rabbit is one of the final four +/// Profile 1 (software) ciphers selected for the eSTREAM portfolio. +/// \details Crypto++ provides Rabbit and RabbitWithIV classes. Two classes are necessary +/// because the library lacks the means to describe and manage optional IVs. +/// \sa Rabbit, The +/// eSTREAM Project | Rabbit and +/// Crypto++ Wiki | Rabbit. +/// \since Crypto++ 8.0 +struct RabbitWithIV : public RabbitWithIVInfo, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, RabbitWithIVInfo> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_RABBIT_H diff --git a/third_party/cryptoppwin/include/cryptopp/rabin.h b/third_party/cryptoppwin/include/cryptopp/rabin.h new file mode 100644 index 00000000..f1271574 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/rabin.h @@ -0,0 +1,135 @@ +// rabin.h - originally written and placed in the public domain by Wei Dai + +/// \file rabin.h +/// \brief Classes for Rabin encryption and signature schemes + +#ifndef CRYPTOPP_RABIN_H +#define CRYPTOPP_RABIN_H + +#include "cryptlib.h" +#include "oaep.h" +#include "pssr.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Rabin trapdoor function using the public key +/// \since Crypto++ 2.0 +class RabinFunction : public TrapdoorFunction, public PublicKey +{ + typedef RabinFunction ThisClass; + +public: + + /// \brief Initialize a Rabin public key + /// \param n the modulus + /// \param r element r + /// \param s element s + void Initialize(const Integer &n, const Integer &r, const Integer &s) + {m_n = n; m_r = r; m_s = s;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + const Integer& GetModulus() const {return m_n;} + const Integer& GetQuadraticResidueModPrime1() const {return m_r;} + const Integer& GetQuadraticResidueModPrime2() const {return m_s;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetQuadraticResidueModPrime1(const Integer &r) {m_r = r;} + void SetQuadraticResidueModPrime2(const Integer &s) {m_s = s;} + +protected: + Integer m_n, m_r, m_s; +}; + +/// \brief Rabin trapdoor function using the private key +/// \since Crypto++ 2.0 +class InvertibleRabinFunction : public RabinFunction, public TrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleRabinFunction ThisClass; + +public: + + /// \brief Initialize a Rabin private key + /// \param n modulus + /// \param r element r + /// \param s element s + /// \param p first prime factor + /// \param q second prime factor + /// \param u q-1 mod p + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &r, const Integer &s, const Integer &p, const Integer &q, const Integer &u) + {m_n = n; m_r = r; m_s = s; m_p = p; m_q = q; m_u = u;} + + /// \brief Create a Rabin private key + /// \param rng a RandomNumberGenerator derived class + /// \param keybits the size of the key, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int keybits) + {GenerateRandomWithKeySize(rng, keybits);} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + Integer m_p, m_q, m_u; +}; + +/// \brief Rabin keys +struct Rabin +{ + static std::string StaticAlgorithmName() {return "Rabin-Crypto++Variant";} + typedef RabinFunction PublicKey; + typedef InvertibleRabinFunction PrivateKey; +}; + +/// \brief Rabin encryption scheme +/// \tparam STANDARD encryption standard +template +struct RabinES : public TF_ES +{ +}; + +/// \brief Rabin signature scheme +/// \tparam STANDARD signature standard +/// \tparam H hash transformation +template +struct RabinSS : public TF_SS +{ +}; + +// More typedefs for backwards compatibility +class SHA1; +typedef RabinES >::Decryptor RabinDecryptor; +typedef RabinES >::Encryptor RabinEncryptor; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/randpool.h b/third_party/cryptoppwin/include/cryptopp/randpool.h new file mode 100644 index 00000000..51227c35 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/randpool.h @@ -0,0 +1,104 @@ +// randpool.h - originally written and placed in the public domain by Wei Dai +// OldRandPool added by JW in August, 2017. + +/// \file randpool.h +/// \brief Class file for Randomness Pool +/// \details RandomPool can be used to generate cryptographic quality pseudorandom bytes +/// after seeding the pool with IncorporateEntropy(). Internally, the generator uses +/// AES-256 to produce the stream. Entropy is stirred in using SHA-256. +/// \details RandomPool used to follow the design of randpool in PGP 2.6.x. At version 5.5 +/// RandomPool was redesigned to reduce the risk of reusing random numbers after state +/// rollback (which may occur when running in a virtual machine like VMware or a hosted +/// environment). +/// \details If you need the pre-Crypto++ 5.5 generator then use OldRandomPool class. You +/// should migrate away from OldRandomPool at the earliest opportunity. Use RandomPool +/// or AutoSeededRandomPool instead. +/// \since Crypto++ 4.0 (PGP 2.6.x style), Crypto++ 5.5 (AES-256 based) + +#ifndef CRYPTOPP_RANDPOOL_H +#define CRYPTOPP_RANDPOOL_H + +#include "cryptlib.h" +#include "filters.h" +#include "secblock.h" +#include "smartptr.h" +#include "aes.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Randomness Pool based on AES-256 +/// \details RandomPool can be used to generate cryptographic quality pseudorandom bytes +/// after seeding the pool with IncorporateEntropy(). Internally, the generator uses +/// AES-256 to produce the stream. Entropy is stirred in using SHA-256. +/// \details RandomPool used to follow the design of randpool in PGP 2.6.x. At version 5.5 +/// RandomPool was redesigned to reduce the risk of reusing random numbers after state +/// rollback, which may occur when running in a virtual machine like VMware or a hosted +/// environment. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \details If you need the pre-Crypto++ 5.5 generator then use OldRandomPool class. You +/// should migrate away from OldRandomPool at the earliest opportunity. +/// \sa OldRandomPool +/// \since Crypto++ 4.0 (PGP 2.6.x style), Crypto++ 5.5 (AES-256 based) +class CRYPTOPP_DLL RandomPool : public RandomNumberGenerator, public NotCopyable +{ +public: + /// \brief Construct a RandomPool + RandomPool(); + + bool CanIncorporateEntropy() const {return true;} + void IncorporateEntropy(const byte *input, size_t length); + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size); + +private: + FixedSizeAlignedSecBlock m_seed; + FixedSizeAlignedSecBlock m_key; + member_ptr m_pCipher; + bool m_keySet; +}; + +/// \brief Randomness Pool based on PGP 2.6.x with MDC +/// \details If you need the pre-Crypto++ 5.5 generator then use OldRandomPool class. The +/// OldRandomPool also provides the modern interface, including CanIncorporateEntropy, +/// IncorporateEntropy and GenerateIntoBufferedTransformation. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \details You should migrate away from OldRandomPool at the earliest opportunity. Use a +/// modern random number generator or key derivation function, like AutoSeededRandomPool or +/// HKDF. +/// \warning This class uses an old style PGP 2.6.x with MDC. The generator risks reusing +/// random numbers after state rollback. You should migrate away from OldRandomPool at +/// the earliest opportunity. +/// \sa RandomPool, AutoSeededRandomPool, HKDF, P1363_KDF2, PKCS12_PBKDF, PKCS5_PBKDF2_HMAC +/// \since Crypto++ 6.0 +class CRYPTOPP_DLL OldRandomPool : public RandomNumberGenerator +{ +public: + /// \brief Construct an OldRandomPool + /// \param poolSize internal pool size of the generator + /// \details poolSize must be greater than 16 + OldRandomPool(unsigned int poolSize=384); + + // RandomNumberGenerator interface (Crypto++ 5.5 and above) + bool CanIncorporateEntropy() const {return true;} + void IncorporateEntropy(const byte *input, size_t length); + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size); + + byte GenerateByte(); + void GenerateBlock(byte *output, size_t size); + + // GenerateWord32 is overridden and provides Crypto++ 5.4 behavior. + // Taken from RandomNumberSource::GenerateWord32 in cryptlib.cpp. + word32 GenerateWord32 (word32 min=0, word32 max=0xffffffffUL); + +protected: + void Stir(); + +private: + SecByteBlock pool, key; + size_t addPos, getPos; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/rc2.h b/third_party/cryptoppwin/include/cryptopp/rc2.h new file mode 100644 index 00000000..1b296d27 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/rc2.h @@ -0,0 +1,90 @@ +// rc2.h - originally written and placed in the public domain by Wei Dai + +/// \file rc2.h +/// \brief Classes for the RC2 block cipher +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_RC2_H +#define CRYPTOPP_RC2_H + +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RC2 block cipher information +/// \since Crypto++ 3.0 +struct RC2_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 1, 128> +{ + CRYPTOPP_CONSTANT(DEFAULT_EFFECTIVE_KEYLENGTH = 1024); + CRYPTOPP_CONSTANT(MAX_EFFECTIVE_KEYLENGTH = 1024); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RC2";} +}; + +/// \brief RC2 block cipher +/// \sa RC2 on the Crypto Lounge. +/// \since Crypto++ 3.0 +class RC2 : public RC2_Info, public BlockCipherDocumentation +{ + /// \brief Class specific methods used to operate the cipher. + /// \details Implementations and overrides in \p Base apply to both \p ENCRYPTION and \p DECRYPTION directions + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + protected: + FixedSizeSecBlock K; // expanded key table + }; + + /// \brief Class specific methods used to operate the cipher in the forward direction. + /// \details Implementations and overrides in \p Enc apply to \p ENCRYPTION. + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Class specific methods used to operate the cipher in the reverse direction. + /// \details Implementations and overrides in \p Dec apply to \p DECRYPTION. + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + + /// \brief Class specific methods used to operate the cipher in the forward direction. + /// \details Implementations and overrides in \p Encryption apply to \p ENCRYPTION. + class Encryption : public BlockCipherFinal + { + public: + Encryption() {} + Encryption(const byte *key, size_t keyLen=DEFAULT_KEYLENGTH) + {SetKey(key, keyLen);} + Encryption(const byte *key, size_t keyLen, int effectiveKeyLen) + {SetKey(key, keyLen, MakeParameters("EffectiveKeyLength", effectiveKeyLen));} + }; + + /// \brief Class specific methods used to operate the cipher in the reverse direction. + /// \details Implementations and overrides in \p Decryption apply to \p DECRYPTION. + class Decryption : public BlockCipherFinal + { + public: + Decryption() {} + Decryption(const byte *key, size_t keyLen=DEFAULT_KEYLENGTH) + {SetKey(key, keyLen);} + Decryption(const byte *key, size_t keyLen, int effectiveKeyLen) + {SetKey(key, keyLen, MakeParameters("EffectiveKeyLength", effectiveKeyLen));} + }; +}; + +typedef RC2::Encryption RC2Encryption; +typedef RC2::Decryption RC2Decryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/rc5.h b/third_party/cryptoppwin/include/cryptopp/rc5.h new file mode 100644 index 00000000..541ffbc0 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/rc5.h @@ -0,0 +1,59 @@ +// rc5.h - originally written and placed in the public domain by Wei Dai + +/// \file rc5.h +/// \brief Classes for the RC5 block cipher + +#ifndef CRYPTOPP_RC5_H +#define CRYPTOPP_RC5_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RC5 block cipher information +/// \since Crypto++ 1.0 +struct RC5_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 0, 255>, public VariableRounds<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RC5";} + typedef word32 RC5_WORD; +}; + +/// \brief RC5 block cipher +/// \sa RC5 +/// \since Crypto++ 1.0 +class RC5 : public RC5_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + unsigned int r; // number of rounds + SecBlock sTable; // expanded key table + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef RC5::Encryption RC5Encryption; +typedef RC5::Decryption RC5Decryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/rc6.h b/third_party/cryptoppwin/include/cryptopp/rc6.h new file mode 100644 index 00000000..7b80d356 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/rc6.h @@ -0,0 +1,60 @@ +// rc6.h - originally written and placed in the public domain by Wei Dai + +/// \file rc6.h +/// \brief Classes for the RC6 block cipher +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_RC6_H +#define CRYPTOPP_RC6_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RC6 block cipher information +/// \since Crypto++ 3.0 +struct RC6_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8>, public VariableRounds<20> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RC6";} + typedef word32 RC6_WORD; +}; + +/// \brief RC6 block cipher +/// \sa RC6 +/// \since Crypto++ 3.0 +class RC6 : public RC6_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + unsigned int r; // number of rounds + SecBlock sTable; // expanded key table + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef RC6::Encryption RC6Encryption; +typedef RC6::Decryption RC6Decryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/rdrand.h b/third_party/cryptoppwin/include/cryptopp/rdrand.h new file mode 100644 index 00000000..d1f3c412 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/rdrand.h @@ -0,0 +1,145 @@ +// rdrand.h - written and placed in public domain by Jeffrey Walton and Uri Blumenthal. + +/// \file rdrand.h +/// \brief Classes for RDRAND and RDSEED +/// \since Crypto++ 5.6.3 + +#ifndef CRYPTOPP_RDRAND_H +#define CRYPTOPP_RDRAND_H + +#include "cryptlib.h" + +// This class file provides both RDRAND and RDSEED. They were added at +// Crypto++ 5.6.3. At compile time, it uses CRYPTOPP_BOOL_{X86|X32|X64} +// to select an implementation or "throw NotImplemented". At runtime the +// constructor will throw RDRAND_Err or RDSEED_Err if a generator is +// is not available. +// The original classes accepted a retry count. Retries were superfluous for +// RDRAND, and RDSEED encountered a failure about 1 in 256 bytes depending +// on the processor. Retries were removed at Crypto++ 6.0 because +// GenerateBlock unconditionally retries and always fulfills the request. + +// Throughput varies wildly depending on processor and manufacturer. A Core i5 or +// Core i7 RDRAND can generate at over 200 MiB/s. It is below theroetical +// maximum, but it takes about 5 instructions to generate, retry and store a +// result. A low-end Celeron may perform RDRAND at about 7 MiB/s. RDSEED +// performs at about 1/4 to 1/2 the rate of RDRAND. AMD RDRAND performed poorly +// during testing with Athlon X4 845. The Bulldozer v4 only performed at 1 MiB/s. + +// Microsoft added RDRAND in August 2012, VS2012; RDSEED in October 2013, VS2013. +// GCC added RDRAND in December 2010, GCC 4.6. LLVM added RDRAND in July 2012, +// Clang 3.2. Intel added RDRAND in September 2011, ICC 12.1. + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Exception thrown when a RDRAND generator encounters +/// a generator related error. +/// \since Crypto++ 5.6.3 +class RDRAND_Err : public Exception +{ +public: + RDRAND_Err(const std::string &operation) + : Exception(OTHER_ERROR, "RDRAND: " + operation + " operation failed") {} +}; + +/// \brief Hardware generated random numbers using RDRAND instruction +/// \sa MaurerRandomnessTest() for random bit generators +/// \since Crypto++ 5.6.3 +class RDRAND : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "RDRAND"; } + + virtual ~RDRAND() {} + + /// \brief Construct a RDRAND generator + /// \details According to DJ of Intel, the Intel RDRAND circuit does not underflow. + /// If it did hypothetically underflow, then it would return 0 for the random value. + /// AMD's RDRAND implementation appears to provide the same behavior. + /// \throw RDRAND_Err if the random number generator is not available + RDRAND(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + /// \details the RDSEED generator discards words, not bytes. If n is + /// not a multiple of a machine word, then it is rounded up to + /// that size. + virtual void DiscardBytes(size_t n); + + /// \brief Update RNG state with additional unpredictable values + /// \param input unused + /// \param length unused + /// \details The operation is a nop for this generator. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + // Override to avoid the base class' throw. + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + } + + std::string AlgorithmProvider() const { + return "RDRAND"; + } +}; + +/// \brief Exception thrown when a RDSEED generator encounters +/// a generator related error. +/// \since Crypto++ 5.6.3 +class RDSEED_Err : public Exception +{ +public: + RDSEED_Err(const std::string &operation) + : Exception(OTHER_ERROR, "RDSEED: " + operation + " operation failed") {} +}; + +/// \brief Hardware generated random numbers using RDSEED instruction +/// \sa MaurerRandomnessTest() for random bit generators +/// \since Crypto++ 5.6.3 +class RDSEED : public RandomNumberGenerator +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "RDSEED"; } + + virtual ~RDSEED() {} + + /// \brief Construct a RDSEED generator + /// \details Empirical testing under a 6th generation i7 (6200U) shows RDSEED fails + /// to fulfill requests at about once every for every 256 bytes requested. + /// The generator runs about 4 times slower than RDRAND. + /// \throw RDSEED_Err if the random number generator is not available + RDSEED(); + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + virtual void GenerateBlock(byte *output, size_t size); + + /// \brief Generate and discard n bytes + /// \param n the number of bytes to generate and discard + /// \details the RDSEED generator discards words, not bytes. If n is + /// not a multiple of a machine word, then it is rounded up to + /// that size. + virtual void DiscardBytes(size_t n); + + /// \brief Update RNG state with additional unpredictable values + /// \param input unused + /// \param length unused + /// \details The operation is a nop for this generator. + virtual void IncorporateEntropy(const byte *input, size_t length) + { + // Override to avoid the base class' throw. + CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(length); + } + + std::string AlgorithmProvider() const { + return "RDSEED"; + } +}; + +NAMESPACE_END + +#endif // CRYPTOPP_RDRAND_H diff --git a/third_party/cryptoppwin/include/cryptopp/resource.h b/third_party/cryptoppwin/include/cryptopp/resource.h new file mode 100644 index 00000000..ae07ae7f --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by cryptopp.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/rijndael.h b/third_party/cryptoppwin/include/cryptopp/rijndael.h new file mode 100644 index 00000000..272975aa --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/rijndael.h @@ -0,0 +1,109 @@ +// rijndael.h - originally written and placed in the public domain by Wei Dai + +/// \file rijndael.h +/// \brief Classes for Rijndael encryption algorithm +/// \details All key sizes are supported. The library only provides Rijndael with 128-bit blocks, +/// and not 192-bit or 256-bit blocks +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0, ARMv7 AES since Crypto++ 8.0 + +#ifndef CRYPTOPP_RIJNDAEL_H +#define CRYPTOPP_RIJNDAEL_H + +#include "seckey.h" +#include "secblock.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_RIJNDAEL_ASM 1 +#endif + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_ARM32 || \ + CRYPTOPP_BOOL_ARMV8 || CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 +# define CRYPTOPP_RIJNDAEL_ADVANCED_PROCESS_BLOCKS 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Rijndael block cipher information +/// \details All key sizes are supported. The library only provides Rijndael with 128-bit blocks, +/// and not 192-bit or 256-bit blocks +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0, ARMv7 AES since Crypto++ 8.0 +struct Rijndael_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8> +{ + CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "AES";} +}; + +/// \brief Rijndael block cipher +/// \details All key sizes are supported. The library only provides Rijndael with 128-bit blocks, +/// and not 192-bit or 256-bit blocks +/// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, +/// Power8 AES since Crypto++ 6.0, ARMv7 AES since Crypto++ 8.0 +/// \sa Rijndael +class CRYPTOPP_DLL Rijndael : public Rijndael_Info, public BlockCipherDocumentation +{ + /// \brief Rijndael block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + std::string AlgorithmProvider() const; + unsigned int OptimalDataAlignment() const; + + protected: + static void FillEncTable(); + static void FillDecTable(); + + // VS2005 workaround: have to put these on separate lines, or error C2487 is triggered in DLL build + static const byte Se[256]; + static const byte Sd[256]; + + static const word32 rcon[]; + + unsigned int m_rounds; + SecBlock > m_key; + mutable SecByteBlock m_aliasBlock; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key sizes are supported. + /// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks + /// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, + /// Power8 AES since Crypto++ 6.0, ARMv7 AES since Crypto++ 8.0 + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_RIJNDAEL_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key sizes are supported. + /// The library only provides Rijndael with 128-bit blocks, and not 192-bit or 256-bit blocks + /// \since Rijndael since Crypto++ 3.1, Intel AES-NI since Crypto++ 5.6.1, ARMv8 AES since Crypto++ 6.0, + /// Power8 AES since Crypto++ 6.0, ARMv7 AES since Crypto++ 8.0 + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_RIJNDAEL_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Rijndael::Encryption RijndaelEncryption; +typedef Rijndael::Decryption RijndaelDecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/ripemd.h b/third_party/cryptoppwin/include/cryptopp/ripemd.h new file mode 100644 index 00000000..cf700840 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/ripemd.h @@ -0,0 +1,65 @@ +// ripemd.h - originally written and placed in the public domain by Wei Dai + +/// \file +/// \brief Classes for RIPEMD message digest + +#ifndef CRYPTOPP_RIPEMD_H +#define CRYPTOPP_RIPEMD_H + +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RIPEMD-160 message digest +/// \details Digest size is 160-bits. +/// \sa RIPEMD-160 +/// \since Crypto++ 2.1 +class RIPEMD160 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RIPEMD-160";} +}; + +/// \brief RIPEMD-320 message digest +/// \details Digest size is 320-bits. +/// \sa RIPEMD-320 +/// \since Crypto++ 2.1 +class RIPEMD320 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RIPEMD-320";} +}; + +/// \brief RIPEMD-128 message digest +/// \details Digest size is 128-bits. +/// \warning RIPEMD-128 is considered insecure, and should not be used unless you absolutely need it for compatibility. +/// \sa RIPEMD-128 +/// \since Crypto++ 2.1 +class RIPEMD128 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RIPEMD-128";} +}; + +/// \brief RIPEMD-256 message digest +/// \details Digest size is 256-bits. +/// \warning RIPEMD-256 is considered insecure, and should not be used unless you absolutely need it for compatibility. +/// \sa RIPEMD-256 +/// \since Crypto++ 2.1 +class RIPEMD256 : public IteratedHashWithStaticTransform +{ +public: + static void InitState(HashWordType *state); + static void Transform(word32 *digest, const word32 *data); + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RIPEMD-256";} +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/rng.h b/third_party/cryptoppwin/include/cryptopp/rng.h new file mode 100644 index 00000000..74456acb --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/rng.h @@ -0,0 +1,111 @@ +// rng.h - originally written and placed in the public domain by Wei Dai + +/// \file rng.h +/// \brief Miscellaneous classes for RNGs +/// \details This file contains miscellaneous classes for RNGs, including LC_RNG(), +/// X917RNG() and MaurerRandomnessTest() +/// \sa osrng.h, randpool.h + +#ifndef CRYPTOPP_RNG_H +#define CRYPTOPP_RNG_H + +#include "cryptlib.h" +#include "filters.h" +#include "smartptr.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Linear Congruential Generator (LCG) +/// \details Originally propsed by William S. England. +/// \warning LC_RNG is suitable for simulations, where uniformaly distributed numbers are +/// required quickly. It should not be used for cryptographic purposes. +class LC_RNG : public RandomNumberGenerator +{ +public: + /// \brief Construct a Linear Congruential Generator (LCG) + /// \param init_seed the initial value for the generator + LC_RNG(word32 init_seed) + : seed(init_seed) {} + + void GenerateBlock(byte *output, size_t size); + + word32 GetSeed() {return seed;} + +private: + word32 seed; + + static const word32 m; + static const word32 q; + static const word16 a; + static const word16 r; +}; + +/// \brief ANSI X9.17 RNG +/// \details X917RNG is from ANSI X9.17 Appendix C, and it uses a 64-bit block cipher, like TripleDES. +/// If you use a 128-bit block cipher, like AES, then you are effectively using an ANSI X9.31 generator. +/// \details You should reseed the generator after a fork() to avoid multiple generators +/// with the same internal state. +/// \sa AutoSeededX917RNG, DefaultAutoSeededRNG +class CRYPTOPP_DLL X917RNG : public RandomNumberGenerator, public NotCopyable +{ +public: + /// \brief Construct a X917RNG + /// \param cipher the block cipher to use for the generator + /// \param seed a byte buffer to use as a seed + /// \param deterministicTimeVector additional entropy + /// \details cipher will be deleted by the destructor. seed must be at least + /// BlockSize() in length. deterministicTimeVector = 0 means obtain time vector + /// from the system. + /// \details When constructing a X917RNG, the generator must be keyed or an access + /// violation will occur because the time vector is encrypted using the block cipher. + /// To key the generator during constructions, perform the following: + ///
+	///  SecByteBlock key(AES::DEFAULT_KEYLENGTH), seed(AES::BLOCKSIZE);
+	///  OS_GenerateRandomBlock(false, key, key.size());
+	///  OS_GenerateRandomBlock(false, seed, seed.size());
+	///  X917RNG prng(new AES::Encryption(key, AES::DEFAULT_KEYLENGTH), seed, NULLPTR);
+ /// \sa AutoSeededX917RNG + X917RNG(BlockTransformation *cipher, const byte *seed, const byte *deterministicTimeVector = NULLPTR); + + void GenerateIntoBufferedTransformation(BufferedTransformation &target, const std::string &channel, lword size); + +private: + member_ptr m_cipher; + const unsigned int m_size; // S, blocksize of cipher + SecByteBlock m_datetime; // DT, buffer for enciphered timestamp + SecByteBlock m_randseed, m_lastBlock, m_deterministicTimeVector; +}; + +/// \brief Maurer's Universal Statistical Test for Random Bit Generators +/// \details This class implements Maurer's Universal Statistical Test for +/// Random Bit Generators. It is intended for measuring the randomness of +/// *PHYSICAL* RNGs. +/// \details For more details see Maurer's paper in Journal of Cryptology, 1992. +class MaurerRandomnessTest : public Bufferless +{ +public: + /// \brief Construct a MaurerRandomnessTest + MaurerRandomnessTest(); + + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + + /// \brief Provides the number of bytes of input is needed by the test + /// \return how many more bytes of input is needed by the test + // BytesNeeded() returns how many more bytes of input is needed by the test + // GetTestValue() should not be called before BytesNeeded()==0 + unsigned int BytesNeeded() const {return n >= (Q+K) ? 0 : Q+K-n;} + + // returns a number between 0.0 and 1.0, describing the quality of the + // random numbers entered + double GetTestValue() const; + +private: + enum {L=8, V=256, Q=2000, K=2000}; + double sum; + unsigned int n; + unsigned int tab[V]; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/rsa.h b/third_party/cryptoppwin/include/cryptopp/rsa.h new file mode 100644 index 00000000..1d45fb6e --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/rsa.h @@ -0,0 +1,288 @@ +// rsa.h - originally written and placed in the public domain by Wei Dai + +/// \file rsa.h +/// \brief Classes for the RSA cryptosystem +/// \details This file contains classes that implement the RSA +/// ciphers and signature schemes as defined in PKCS #1 v2.0. + +#ifndef CRYPTOPP_RSA_H +#define CRYPTOPP_RSA_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" +#include "pkcspad.h" +#include "oaep.h" +#include "emsa2.h" +#include "asn.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief RSA trapdoor function using the public key +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL RSAFunction : public TrapdoorFunction, public X509PublicKey +{ + typedef RSAFunction ThisClass; + +public: + /// \brief Initialize a RSA public key + /// \param n the modulus + /// \param e the public exponent + void Initialize(const Integer &n, const Integer &e) + {m_n = n; m_e = e;} + + // X509PublicKey + OID GetAlgorithmID() const; + void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePublicKey(BufferedTransformation &bt) const; + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // TrapdoorFunction + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return m_n;} + Integer ImageBound() const {return m_n;} + + // non-derived + const Integer & GetModulus() const {return m_n;} + const Integer & GetPublicExponent() const {return m_e;} + + void SetModulus(const Integer &n) {m_n = n;} + void SetPublicExponent(const Integer &e) {m_e = e;} + +protected: + Integer m_n, m_e; +}; + +/// \brief RSA trapdoor function using the private key +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL InvertibleRSAFunction : public RSAFunction, public TrapdoorFunctionInverse, public PKCS8PrivateKey +{ + typedef InvertibleRSAFunction ThisClass; + +public: + /// \brief Create a RSA private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \param e the desired public exponent + /// \details Initialize() creates a new keypair using a public exponent of 17. + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits, const Integer &e = 17); + + /// \brief Initialize a RSA private key + /// \param n modulus + /// \param e public exponent + /// \param d private exponent + /// \param p first prime factor + /// \param q second prime factor + /// \param dp d mod p + /// \param dq d mod q + /// \param u q-1 mod p + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &e, const Integer &d, const Integer &p, const Integer &q, const Integer &dp, const Integer &dq, const Integer &u) + {m_n = n; m_e = e; m_d = d; m_p = p; m_q = q; m_dp = dp; m_dq = dq; m_u = u;} + + /// \brief Initialize a RSA private key + /// \param n modulus + /// \param e public exponent + /// \param d private exponent + /// \details This Initialize() function overload initializes a private key from existing parameters. + /// Initialize() will factor n using d and populate {p,q,dp,dq,u}. + void Initialize(const Integer &n, const Integer &e, const Integer &d); + + // PKCS8PrivateKey + void BERDecode(BufferedTransformation &bt) + {PKCS8PrivateKey::BERDecode(bt);} + void DEREncode(BufferedTransformation &bt) const + {PKCS8PrivateKey::DEREncode(bt);} + void Load(BufferedTransformation &bt) + {PKCS8PrivateKey::BERDecode(bt);} + void Save(BufferedTransformation &bt) const + {PKCS8PrivateKey::DEREncode(bt);} + OID GetAlgorithmID() const {return RSAFunction::GetAlgorithmID();} + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; + + // TrapdoorFunctionInverse + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + + // GeneratableCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + // parameters: (ModulusSize, PublicExponent (default 17)) + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // non-derived interface + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetPrivateExponent() const {return m_d;} + const Integer& GetModPrime1PrivateExponent() const {return m_dp;} + const Integer& GetModPrime2PrivateExponent() const {return m_dq;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetPrivateExponent(const Integer &d) {m_d = d;} + void SetModPrime1PrivateExponent(const Integer &dp) {m_dp = dp;} + void SetModPrime2PrivateExponent(const Integer &dq) {m_dq = dq;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + +protected: + Integer m_d, m_p, m_q, m_dp, m_dq, m_u; +}; + +/// \brief RSA trapdoor function using the public key +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL RSAFunction_ISO : public RSAFunction +{ +public: + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return ++(m_n>>1);} +}; + +/// \brief RSA trapdoor function using the private key +/// \since Crypto++ 1.0 +class CRYPTOPP_DLL InvertibleRSAFunction_ISO : public InvertibleRSAFunction +{ +public: + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + Integer PreimageBound() const {return ++(m_n>>1);} +}; + +/// \brief RSA algorithm +/// \since Crypto++ 1.0 +struct CRYPTOPP_DLL RSA +{ + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "RSA";} + typedef RSAFunction PublicKey; + typedef InvertibleRSAFunction PrivateKey; +}; + +/// \brief RSA encryption algorithm +/// \tparam STANDARD signature standard +/// \sa RSA cryptosystem +/// \since Crypto++ 1.0 +template +struct RSAES : public TF_ES +{ +}; + +/// \brief RSA signature algorithm +/// \tparam STANDARD signature standard +/// \tparam H hash transformation +/// \details See documentation of PKCS1v15 for a list of hash functions that can be used with it. +/// \sa RSA signature scheme with appendix +/// \since Crypto++ 1.0 +template +struct RSASS : public TF_SS +{ +}; + +/// \brief RSA algorithm +/// \since Crypto++ 1.0 +struct CRYPTOPP_DLL RSA_ISO +{ + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "RSA-ISO";} + typedef RSAFunction_ISO PublicKey; + typedef InvertibleRSAFunction_ISO PrivateKey; +}; + +/// \brief RSA signature algorithm +/// \tparam H hash transformation +/// \since Crypto++ 1.0 +template +struct RSASS_ISO : public TF_SS +{ +}; + +/// \brief \ref RSAES "RSAES::Decryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +DOCUMENTED_TYPEDEF(RSAES::Decryptor, RSAES_PKCS1v15_Decryptor); +/// \brief \ref RSAES "RSAES::Encryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +DOCUMENTED_TYPEDEF(RSAES::Encryptor, RSAES_PKCS1v15_Encryptor); + +/// \brief \ref RSAES "RSAES>::Decryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +DOCUMENTED_TYPEDEF(RSAES >::Decryptor, RSAES_OAEP_SHA_Decryptor); +/// \brief \ref RSAES "RSAES>::Encryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +DOCUMENTED_TYPEDEF(RSAES >::Encryptor, RSAES_OAEP_SHA_Encryptor); + +/// \brief \ref RSAES "RSAES>::Decryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +/// \since Crypto++ 8.8 +DOCUMENTED_TYPEDEF(RSAES >::Decryptor, RSAES_OAEP_SHA256_Decryptor); +/// \brief \ref RSAES "RSAES>::Encryptor" typedef +/// \details RSA encryption scheme defined in PKCS #1 v2.0 +/// \since Crypto++ 8.8 +DOCUMENTED_TYPEDEF(RSAES >::Encryptor, RSAES_OAEP_SHA256_Encryptor); + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +/// \brief \ref RSASS "RSASS::Signer" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_SHA_Signer : public RSASS::Signer {}; +/// \brief \ref RSASS "RSASS::Verifier" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_SHA_Verifier : public RSASS::Verifier {}; + +/// \brief \ref RSASS "RSASS::Signer" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 8.8 +class RSASSA_PKCS1v15_SHA256_Signer : public RSASS::Signer {}; +/// \brief \ref RSASS "RSASS::Verifier" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 8.8 +class RSASSA_PKCS1v15_SHA256_Verifier : public RSASS::Verifier {}; + +namespace Weak { + +/// \brief \ref RSASS "RSASS::Signer" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_MD2_Signer : public RSASS::Signer {}; +/// \brief \ref RSASS "RSASS::Verifier" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_MD2_Verifier : public RSASS::Verifier {}; + +/// \brief \ref RSASS "RSASS::Signer" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_MD5_Signer : public RSASS::Signer {}; +/// \brief \ref RSASS "RSASS::Verifier" typedef +/// \details RSA signature schemes defined in PKCS #1 v2.0 +/// \since Crypto++ 1.0 +class RSASSA_PKCS1v15_MD5_Verifier : public RSASS::Verifier {}; +} + +#else +typedef RSASS::Signer RSASSA_PKCS1v15_SHA_Signer; +typedef RSASS::Verifier RSASSA_PKCS1v15_SHA_Verifier; + +typedef RSASS::Signer RSASSA_PKCS1v15_SHA256_Signer; +typedef RSASS::Verifier RSASSA_PKCS1v15_SHA256_Verifier; + +namespace Weak { + typedef RSASS::Signer RSASSA_PKCS1v15_MD2_Signer; + typedef RSASS::Verifier RSASSA_PKCS1v15_MD2_Verifier; + typedef RSASS::Signer RSASSA_PKCS1v15_MD5_Signer; + typedef RSASS::Verifier RSASSA_PKCS1v15_MD5_Verifier; +} +#endif // CRYPTOPP_DOXYGEN_PROCESSING + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/rw.h b/third_party/cryptoppwin/include/cryptopp/rw.h new file mode 100644 index 00000000..ca2cd30a --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/rw.h @@ -0,0 +1,146 @@ +// rw.h - originally written and placed in the public domain by Wei Dai + +/// \file rw.h +/// \brief Classes for Rabin-Williams signature scheme +/// \details The implementation provides Rabin-Williams signature schemes as defined in +/// IEEE P1363. It uses Bernstein's tweaked square roots in place of square roots to +/// speedup calculations. +/// \sa RSA signatures and Rabin–Williams +/// signatures: the state of the art (20080131), Section 6, The tweaks e and f. +/// \since Crypto++ 3.0 + +#ifndef CRYPTOPP_RW_H +#define CRYPTOPP_RW_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Rabin-Williams trapdoor function using the public key +/// \since Crypto++ 3.0, Tweaked roots using e and f since Crypto++ 5.6.4 +class CRYPTOPP_DLL RWFunction : public TrapdoorFunction, public PublicKey +{ + typedef RWFunction ThisClass; + +public: + + /// \brief Initialize a Rabin-Williams public key + /// \param n the modulus + void Initialize(const Integer &n) + {m_n = n;} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + void Save(BufferedTransformation &bt) const + {DEREncode(bt);} + void Load(BufferedTransformation &bt) + {BERDecode(bt);} + + Integer ApplyFunction(const Integer &x) const; + Integer PreimageBound() const {return ++(m_n>>1);} + Integer ImageBound() const {return m_n;} + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + const Integer& GetModulus() const {return m_n;} + void SetModulus(const Integer &n) {m_n = n;} + +protected: + Integer m_n; +}; + +/// \brief Rabin-Williams trapdoor function using the private key +/// \since Crypto++ 3.0, Tweaked roots using e and f since Crypto++ 5.6.4 +class CRYPTOPP_DLL InvertibleRWFunction : public RWFunction, public TrapdoorFunctionInverse, public PrivateKey +{ + typedef InvertibleRWFunction ThisClass; + +public: + /// \brief Construct an InvertibleRWFunction + InvertibleRWFunction() : m_precompute(false) {} + + /// \brief Initialize a Rabin-Williams private key + /// \param n modulus + /// \param p first prime factor + /// \param q second prime factor + /// \param u q-1 mod p + /// \details This Initialize() function overload initializes a private key from existing parameters. + void Initialize(const Integer &n, const Integer &p, const Integer &q, const Integer &u); + + /// \brief Create a Rabin-Williams private key + /// \param rng a RandomNumberGenerator derived class + /// \param modulusBits the size of the modulus, in bits + /// \details This function overload of Initialize() creates a new private key because it + /// takes a RandomNumberGenerator() as a parameter. If you have an existing keypair, + /// then use one of the other Initialize() overloads. + void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits) + {GenerateRandomWithKeySize(rng, modulusBits);} + + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + + void Save(BufferedTransformation &bt) const + {DEREncode(bt);} + void Load(BufferedTransformation &bt) + {BERDecode(bt);} + + Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const; + + // GeneratibleCryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + /*! parameters: (ModulusSize) */ + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg); + + const Integer& GetPrime1() const {return m_p;} + const Integer& GetPrime2() const {return m_q;} + const Integer& GetMultiplicativeInverseOfPrime2ModPrime1() const {return m_u;} + + void SetPrime1(const Integer &p) {m_p = p;} + void SetPrime2(const Integer &q) {m_q = q;} + void SetMultiplicativeInverseOfPrime2ModPrime1(const Integer &u) {m_u = u;} + + virtual bool SupportsPrecomputation() const {return true;} + virtual void Precompute(unsigned int unused = 0) {CRYPTOPP_UNUSED(unused); PrecomputeTweakedRoots();} + virtual void Precompute(unsigned int unused = 0) const {CRYPTOPP_UNUSED(unused); PrecomputeTweakedRoots();} + + virtual void LoadPrecomputation(BufferedTransformation &storedPrecomputation); + virtual void SavePrecomputation(BufferedTransformation &storedPrecomputation) const; + +protected: + void PrecomputeTweakedRoots() const; + +protected: + Integer m_p, m_q, m_u; + + mutable Integer m_pre_2_9p, m_pre_2_3q, m_pre_q_p; + mutable bool m_precompute; +}; + +/// \brief Rabin-Williams keys +/// \since Crypto++ 3.0 +struct RW +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "RW";} + typedef RWFunction PublicKey; + typedef InvertibleRWFunction PrivateKey; +}; + +/// \brief Rabin-Williams signature scheme +/// \tparam STANDARD signature standard +/// \tparam H hash transformation +/// \since Crypto++ 3.0 +template +struct RWSS : public TF_SS +{ +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/safer.h b/third_party/cryptoppwin/include/cryptopp/safer.h new file mode 100644 index 00000000..dacd8c3f --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/safer.h @@ -0,0 +1,98 @@ +// safer.h - originally written and placed in the public domain by Wei Dai + +/// \file safer.h +/// \brief Classes for the SAFER and SAFER-K block ciphers + +#ifndef CRYPTOPP_SAFER_H +#define CRYPTOPP_SAFER_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SAFER block cipher +class SAFER +{ +public: + /// \brief SAFER block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipher + { + public: + unsigned int OptimalDataAlignment() const {return 1;} + void UncheckedSetKey(const byte *userkey, unsigned int length, const NameValuePairs ¶ms); + + protected: + virtual bool Strengthened() const =0; + + SecByteBlock keySchedule; + static const byte exp_tab[256]; + static const byte log_tab[256]; + }; + + /// \brief SAFER block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief SAFER block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; +}; + +/// \brief SAFER block cipher default implementation +/// \tparam BASE SAFER::Enc or SAFER::Dec derived base class +/// \tparam INFO SAFER_Info derived class +/// \tparam STR flag indicating a strengthened implementation +/// \details SAFER-K is not strengthened; while SAFER-SK is strengthened. +template +class CRYPTOPP_NO_VTABLE SAFER_Impl : public BlockCipherImpl +{ +protected: + bool Strengthened() const {return STR;} +}; + +/// \brief SAFER-K block cipher information +struct SAFER_K_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 8, 16, 8>, public VariableRounds<10, 1, 13> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SAFER-K";} +}; + +/// \brief SAFER-K block cipher +/// \sa SAFER-K +class SAFER_K : public SAFER_K_Info, public SAFER, public BlockCipherDocumentation +{ +public: + typedef BlockCipherFinal > Encryption; + typedef BlockCipherFinal > Decryption; +}; + +/// \brief SAFER-SK block cipher information +struct SAFER_SK_Info : public FixedBlockSize<8>, public VariableKeyLength<16, 8, 16, 8>, public VariableRounds<10, 1, 13> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SAFER-SK";} +}; + +/// \brief SAFER-SK block cipher +/// \sa SAFER-SK +class SAFER_SK : public SAFER_SK_Info, public SAFER, public BlockCipherDocumentation +{ +public: + typedef BlockCipherFinal > Encryption; + typedef BlockCipherFinal > Decryption; +}; + +typedef SAFER_K::Encryption SAFER_K_Encryption; +typedef SAFER_K::Decryption SAFER_K_Decryption; + +typedef SAFER_SK::Encryption SAFER_SK_Encryption; +typedef SAFER_SK::Decryption SAFER_SK_Decryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/salsa.h b/third_party/cryptoppwin/include/cryptopp/salsa.h new file mode 100644 index 00000000..40df15d8 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/salsa.h @@ -0,0 +1,104 @@ +// salsa.h - originally written and placed in the public domain by Wei Dai + +/// \file salsa.h +/// \brief Classes for Salsa and Salsa20 stream ciphers + +#ifndef CRYPTOPP_SALSA_H +#define CRYPTOPP_SALSA_H + +#include "strciphr.h" +#include "secblock.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_SALSA_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Salsa20 core transform +/// \param data the data to transform +/// \param rounds the number of rounds +/// \details Several algorithms, like CryptoBox and Scrypt, require access to +/// the core Salsa20 transform. The current Crypto++ implementation does not +/// lend itself to disgorging the Salsa20 cipher from the Salsa20 core transform. +/// Instead Salsa20_Core is provided with customary accelerations. +void Salsa20_Core(word32* data, unsigned int rounds); + +/// \brief Salsa20 stream cipher information +/// \since Crypto++ 5.4 +struct Salsa20_Info : public VariableKeyLength<32, 16, 32, 16, SimpleKeyingInterface::UNIQUE_IV, 8> +{ + static std::string StaticAlgorithmName() {return "Salsa20";} +}; + +/// \brief Salsa20 stream cipher operation +/// \since Crypto++ 5.4 +class CRYPTOPP_NO_VTABLE Salsa20_Policy : public AdditiveCipherConcretePolicy +{ +protected: + Salsa20_Policy() : m_rounds(ROUNDS) {} + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return true;} + void SeekToIteration(lword iterationCount); + +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; +#endif + + std::string AlgorithmProvider() const; + + CRYPTOPP_CONSTANT(ROUNDS = 20); // Default rounds + FixedSizeAlignedSecBlock m_state; + int m_rounds; +}; + +/// \brief Salsa20 stream cipher +/// \details Salsa20 provides a variable number of rounds: 8, 12 or 20. The default number of rounds is 20. +/// \sa The Salsa20 +/// family of stream ciphers (20071225), +/// Snuffle 2005: the Salsa20 encryption +/// function and Salsa20 +/// \since Crypto++ 5.4 +struct Salsa20 : public Salsa20_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, Salsa20_Info> Encryption; + typedef Encryption Decryption; +}; + +/// \brief XSalsa20 stream cipher information +/// \since Crypto++ 5.4 +struct XSalsa20_Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 24> +{ + static std::string StaticAlgorithmName() {return "XSalsa20";} +}; + +/// \brief XSalsa20 stream cipher operation +/// \since Crypto++ 5.4 +class CRYPTOPP_NO_VTABLE XSalsa20_Policy : public Salsa20_Policy +{ +public: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + +protected: + FixedSizeSecBlock m_key; +}; + +/// \brief XSalsa20 stream cipher +/// \details XSalsa20 provides a variable number of rounds: 8, 12 or 20. The default number of rounds is 20. +/// \sa XSalsa20 +/// \since Crypto++ 5.4 +struct XSalsa20 : public XSalsa20_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, XSalsa20_Info> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/scrypt.h b/third_party/cryptoppwin/include/cryptopp/scrypt.h new file mode 100644 index 00000000..a275e993 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/scrypt.h @@ -0,0 +1,103 @@ +// scrypt.h - written and placed in public domain by Jeffrey Walton. +// Based on reference source code by Colin Percival. + +/// \file scrypt.h +/// \brief Classes for Scrypt from RFC 7914 +/// \sa Stronger Key Derivation via +/// Sequential Memory-Hard Functions, +/// The scrypt key derivation function +/// and RFC 7914, The scrypt Password-Based +/// Key Derivation Function +/// \since Crypto++ 7.0 + +#ifndef CRYPTOPP_SCRYPT_H +#define CRYPTOPP_SCRYPT_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Scrypt key derivation function +/// \details The Crypto++ implementation uses OpenMP to accelerate the derivation when +/// available. +/// \details The Crypto++ implementation of Scrypt is limited by C++ datatypes. For +/// example, the library is limited to a derived key length of SIZE_MAX, +/// and not (2^32 - 1) * 32. +/// \sa Stronger Key Derivation via +/// Sequential Memory-Hard Functions, +/// The scrypt key derivation function +/// and RFC 7914, The scrypt Password-Based +/// Key Derivation Function +/// \since Crypto++ 7.0 +class Scrypt : public KeyDerivationFunction +{ +public: + virtual ~Scrypt() {} + + static std::string StaticAlgorithmName () { + return "scrypt"; + } + + // KeyDerivationFunction interface + std::string AlgorithmName() const { + return StaticAlgorithmName(); + } + + // KeyDerivationFunction interface + size_t MaxDerivedKeyLength() const { + return static_cast(0)-1; + } + + // KeyDerivationFunction interface + size_t GetValidDerivedLength(size_t keylength) const; + + // KeyDerivationFunction interface + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const NameValuePairs& params) const; + + /// \brief Derive a key from a seed + /// \param derived the derived output buffer + /// \param derivedLen the size of the derived buffer, in bytes + /// \param secret the seed input buffer + /// \param secretLen the size of the secret buffer, in bytes + /// \param salt the salt input buffer + /// \param saltLen the size of the salt buffer, in bytes + /// \param cost the CPU/memory cost factor + /// \param blockSize the block size + /// \param parallelization the parallelization factor + /// \return the number of iterations performed + /// \throw InvalidDerivedKeyLength if derivedLen is invalid for the scheme + /// \details DeriveKey() provides a standard interface to derive a key from + /// a seed and other parameters. Each class that derives from KeyDerivationFunction + /// provides an overload that accepts most parameters used by the derivation function. + /// \details The CPU/Memory cost parameter ("N" in the documents) must be + /// larger than 1, a power of 2, and less than 2^(128 * r / 8). + /// \details The parameter blockSize ("r" in the documents) specifies the block + /// size. + /// \details The parallelization parameter ("p" in the documents) is a positive + /// integer less than or equal to ((2^32-1) * 32) / (128 * r). Due to Microsoft + /// and its OpenMP 2.0 implementation parallelization is limited to + /// std::numeric_limits::max(). + /// \details Scrypt always returns 1 because it only performs 1 iteration. Other + /// derivation functions, like PBKDF's, will return more interesting values. + /// \details The Crypto++ implementation of Scrypt is limited by C++ datatypes. For + /// example, the library is limited to a derived key length of SIZE_MAX, + /// and not (2^32 - 1) * 32. + size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, + const byte *salt, size_t saltLen, word64 cost=2, word64 blockSize=8, word64 parallelization=1) const; + +protected: + enum {defaultCost=2, defaultBlockSize=8, defaultParallelization=1}; + + // KeyDerivationFunction interface + const Algorithm & GetAlgorithm() const { + return *this; + } + + inline void ValidateParameters(size_t derivedlen, word64 cost, word64 blockSize, word64 parallelization) const; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SCRYPT_H diff --git a/third_party/cryptoppwin/include/cryptopp/seal.h b/third_party/cryptoppwin/include/cryptopp/seal.h new file mode 100644 index 00000000..750df966 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/seal.h @@ -0,0 +1,59 @@ +// seal.h - originally written and placed in the public domain by Wei Dai + +/// \file seal.h +/// \brief Classes for SEAL stream cipher +/// \since Crypto++ 2.2 + +#ifndef CRYPTOPP_SEAL_H +#define CRYPTOPP_SEAL_H + +#include "strciphr.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SEAL stream cipher information +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 2.2 +template +struct SEAL_Info : public FixedKeyLength<20, SimpleKeyingInterface::INTERNALLY_GENERATED_IV, 4> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return B::ToEnum() == LITTLE_ENDIAN_ORDER ? "SEAL-3.0-LE" : "SEAL-3.0-BE";} +}; + +/// \brief SEAL stream cipher operation +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 2.2 +template +class CRYPTOPP_NO_VTABLE SEAL_Policy : public AdditiveCipherConcretePolicy, public SEAL_Info +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length); + bool CipherIsRandomAccess() const {return true;} + void SeekToIteration(lword iterationCount); + +private: + FixedSizeSecBlock m_T; + FixedSizeSecBlock m_S; + SecBlock m_R; + + word32 m_startCount, m_iterationsPerCount; + word32 m_outsideCounter, m_insideCounter; +}; + +/// \brief SEAL stream cipher +/// \tparam B Endianness of the stream cipher +/// \sa SEAL +/// \since Crypto++ 2.2 +template +struct SEAL : public SEAL_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal, AdditiveCipherTemplate<> >, SEAL_Info > Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/secblock.h b/third_party/cryptoppwin/include/cryptopp/secblock.h new file mode 100644 index 00000000..1f200125 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/secblock.h @@ -0,0 +1,1310 @@ +// secblock.h - originally written and placed in the public domain by Wei Dai + +/// \file secblock.h +/// \brief Classes and functions for secure memory allocations. + +#ifndef CRYPTOPP_SECBLOCK_H +#define CRYPTOPP_SECBLOCK_H + +#include "config.h" +#include "allocate.h" +#include "misc.h" +#include "stdcpp.h" + +#if defined(CRYPTOPP_MSC_VERSION) +# pragma warning(push) +# pragma warning(disable: 4231 4275 4700) +# if (CRYPTOPP_MSC_VERSION >= 1400) +# pragma warning(disable: 6011 6386 28193) +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// ************** secure memory allocation *************** + +/// \brief Base class for all allocators used by SecBlock +/// \tparam T the class or type +template +class AllocatorBase +{ +public: + typedef T value_type; + typedef size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T * pointer; + typedef const T * const_pointer; + typedef T & reference; + typedef const T & const_reference; + + pointer address(reference r) const {return (&r);} + const_pointer address(const_reference r) const {return (&r); } + void construct(pointer p, const T& val) {new (p) T(val);} + void destroy(pointer p) {CRYPTOPP_UNUSED(p); p->~T();} + + /// \brief Returns the maximum number of elements the allocator can provide + /// \details ELEMS_MAX is the maximum number of elements the + /// Allocator can provide. The value of ELEMS_MAX is + /// SIZE_MAX/sizeof(T). std::numeric_limits was avoided + /// due to lack of constexpr-ness in C++03 and below. + /// \note In C++03 and below ELEMS_MAX is a static data member of type + /// size_type. In C++11 and above ELEMS_MAX is an enum + /// inheriting from size_type. In both cases ELEMS_MAX can be + /// used before objects are fully constructed, and it does not suffer the + /// limitations of class methods like max_size. + /// \sa Issue 346/CVE-2016-9939 + /// \since Crypto++ 6.0 +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + static const size_type ELEMS_MAX = ...; +#elif defined(CRYPTOPP_MSC_VERSION) && (CRYPTOPP_MSC_VERSION <= 1400) + static const size_type ELEMS_MAX = (~(size_type)0)/sizeof(T); +#elif defined(CRYPTOPP_CXX11_STRONG_ENUM) + enum : size_type {ELEMS_MAX = SIZE_MAX/sizeof(T)}; +#else + static const size_type ELEMS_MAX = SIZE_MAX/sizeof(T); +#endif + + /// \brief Returns the maximum number of elements the allocator can provide + /// \return the maximum number of elements the allocator can provide + /// \details Internally, preprocessor macros are used rather than std::numeric_limits + /// because the latter is not a constexpr. Some compilers, like Clang, do not + /// optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear + /// to optimize it well in either form. + CRYPTOPP_CONSTEXPR size_type max_size() const {return ELEMS_MAX;} + +#if defined(__SUNPRO_CC) + // https://github.com/weidai11/cryptopp/issues/770 + // and https://stackoverflow.com/q/53999461/608639 + CRYPTOPP_CONSTEXPR size_type max_size(size_type n) const {return SIZE_MAX/n;} +#endif + +#if defined(CRYPTOPP_CXX11_VARIADIC_TEMPLATES) || defined(CRYPTOPP_DOXYGEN_PROCESSING) + + /// \brief Constructs a new V using variadic arguments + /// \tparam V the type to be forwarded + /// \tparam Args the arguments to be forwarded + /// \param ptr pointer to type V + /// \param args variadic arguments + /// \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES + /// is defined. The define is controlled by compiler versions detected in config.h. + template + void construct(V* ptr, Args&&... args) {::new ((void*)ptr) V(std::forward(args)...);} + + /// \brief Destroys an V constructed with variadic arguments + /// \tparam V the type to be forwarded + /// \details This is a C++11 feature. It is available when CRYPTOPP_CXX11_VARIADIC_TEMPLATES + /// is defined. The define is controlled by compiler versions detected in config.h. + template + void destroy(V* ptr) {if (ptr) ptr->~V();} + +#endif + +protected: + + /// \brief Verifies the allocator can satisfy a request based on size + /// \param size the size of the allocation, in elements + /// \throw InvalidArgument + /// \details CheckSize verifies the number of elements requested is valid. + /// \details If size is greater than max_size(), then InvalidArgument is thrown. + /// The library throws InvalidArgument if the size is too large to satisfy. + /// \details Internally, preprocessor macros are used rather than std::numeric_limits + /// because the latter is not a constexpr. Some compilers, like Clang, do not + /// optimize it well under all circumstances. Compilers like GCC, ICC and MSVC appear + /// to optimize it well in either form. + /// \details The sizeof(T) != 1 in the condition attempts to help the + /// compiler optimize the check for byte types. Coverity findings for + /// CONSTANT_EXPRESSION_RESULT were generated without it. For byte types, + /// size never exceeded ELEMS_MAX but the code was not removed. + /// \note size is the count of elements, and not the number of bytes + static void CheckSize(size_t size) + { + // Squash MSC C4100 warning for size. Also see commit 42b7c4ea5673. + CRYPTOPP_UNUSED(size); + // C++ throws std::bad_alloc (C++03) or std::bad_array_new_length (C++11) here. + if (sizeof(T) != 1 && size > ELEMS_MAX) + throw InvalidArgument("AllocatorBase: requested size would cause integer overflow"); + } +}; + +#define CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T_type) \ + typedef typename AllocatorBase::value_type value_type;\ + typedef typename AllocatorBase::size_type size_type;\ + typedef typename AllocatorBase::difference_type difference_type;\ + typedef typename AllocatorBase::pointer pointer;\ + typedef typename AllocatorBase::const_pointer const_pointer;\ + typedef typename AllocatorBase::reference reference;\ + typedef typename AllocatorBase::const_reference const_reference; + +/// \brief Reallocation function +/// \tparam T the class or type +/// \tparam A the class or type's allocator +/// \param alloc the allocator +/// \param oldPtr the previous allocation +/// \param oldSize the size of the previous allocation +/// \param newSize the new, requested size +/// \param preserve flag that indicates if the old allocation should be preserved +/// \note oldSize and newSize are the count of elements, and not the +/// number of bytes. +template +typename A::pointer StandardReallocate(A& alloc, T *oldPtr, typename A::size_type oldSize, typename A::size_type newSize, bool preserve) +{ + // Avoid assert on pointer in reallocate. SecBlock regularly uses NULL + // pointers rather returning non-NULL 0-sized pointers. + if (oldSize == newSize) + return oldPtr; + + if (preserve) + { + typename A::pointer newPtr = alloc.allocate(newSize, NULLPTR); + const typename A::size_type copySize = STDMIN(oldSize, newSize) * sizeof(T); + + if (oldPtr && newPtr) + memcpy_s(newPtr, copySize, oldPtr, copySize); + + if (oldPtr) + alloc.deallocate(oldPtr, oldSize); + + return newPtr; + } + else + { + if (oldPtr) + alloc.deallocate(oldPtr, oldSize); + + return alloc.allocate(newSize, NULLPTR); + } +} + +/// \brief Allocates a block of memory with cleanup +/// \tparam T class or type +/// \tparam T_Align16 boolean that determines whether allocations should be aligned on a 16-byte boundary +/// \details If T_Align16 is true, then AllocatorWithCleanup calls AlignedAllocate() +/// for memory allocations. If T_Align16 is false, then AllocatorWithCleanup() calls +/// UnalignedAllocate() for memory allocations. +/// \details Template parameter T_Align16 is effectively controlled by cryptlib.h and mirrors +/// CRYPTOPP_BOOL_ALIGN16. CRYPTOPP_BOOL_ALIGN16 is often used as the template parameter. +template +class AllocatorWithCleanup : public AllocatorBase +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T) + + /// \brief Allocates a block of memory + /// \param ptr the size of the allocation + /// \param size the size of the allocation, in elements + /// \return a memory block + /// \throw InvalidArgument + /// \details allocate() first checks the size of the request. If it is non-0 + /// and less than max_size(), then an attempt is made to fulfill the request + /// using either AlignedAllocate() or UnalignedAllocate(). AlignedAllocate() is + /// used if T_Align16 is true. UnalignedAllocate() used if T_Align16 is false. + /// \details This is the C++ *Placement New* operator. ptr is not used, and the + /// function asserts in Debug builds if ptr is non-NULL. + /// \sa CallNewHandler() for the methods used to recover from a failed + /// allocation attempt. + /// \note size is the count of elements, and not the number of bytes + pointer allocate(size_type size, const void *ptr = NULLPTR) + { + CRYPTOPP_UNUSED(ptr); CRYPTOPP_ASSERT(ptr == NULLPTR); + this->CheckSize(size); + if (size == 0) + return NULLPTR; + +#if CRYPTOPP_BOOL_ALIGN16 + if (T_Align16) + return reinterpret_cast(AlignedAllocate(size*sizeof(T))); +#endif + + return reinterpret_cast(UnalignedAllocate(size*sizeof(T))); + } + + /// \brief Deallocates a block of memory + /// \param ptr the pointer for the allocation + /// \param size the size of the allocation, in elements + /// \details Internally, SecureWipeArray() is called before deallocating the + /// memory. Once the memory block is wiped or zeroized, AlignedDeallocate() + /// or UnalignedDeallocate() is called. + /// \details AlignedDeallocate() is used if T_Align16 is true. + /// UnalignedDeallocate() used if T_Align16 is false. + void deallocate(void *ptr, size_type size) + { + // Avoid assert on pointer in deallocate. SecBlock regularly uses NULL + // pointers rather returning non-NULL 0-sized pointers. + if (ptr) + { + SecureWipeArray(reinterpret_cast(ptr), size); + +#if CRYPTOPP_BOOL_ALIGN16 + if (T_Align16) + return AlignedDeallocate(ptr); +#endif + + UnalignedDeallocate(ptr); + } + } + + /// \brief Reallocates a block of memory + /// \param oldPtr the previous allocation + /// \param oldSize the size of the previous allocation + /// \param newSize the new, requested size + /// \param preserve flag that indicates if the old allocation should be preserved + /// \return pointer to the new memory block + /// \details Internally, reallocate() calls StandardReallocate(). + /// \details If preserve is true, then index 0 is used to begin copying the + /// old memory block to the new one. If the block grows, then the old array + /// is copied in its entirety. If the block shrinks, then only newSize + /// elements are copied from the old block to the new one. + /// \note oldSize and newSize are the count of elements, and not the + /// number of bytes. + pointer reallocate(T *oldPtr, size_type oldSize, size_type newSize, bool preserve) + { + CRYPTOPP_ASSERT((oldPtr && oldSize) || !(oldPtr || oldSize)); + return StandardReallocate(*this, oldPtr, oldSize, newSize, preserve); + } + + /// \brief Template class member Rebind + /// \tparam V bound class or type + /// \details Rebind allows a container class to allocate a different type of object + /// to store elements. For example, a std::list will allocate std::list_node to + /// store elements in the list. + /// \details VS.NET STL enforces the policy of "All STL-compliant allocators + /// have to provide a template class member called rebind". + template struct rebind { typedef AllocatorWithCleanup other; }; +#if (CRYPTOPP_MSC_VERSION >= 1500) + AllocatorWithCleanup() {} + template AllocatorWithCleanup(const AllocatorWithCleanup &) {} +#endif +}; + +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; +#if defined(CRYPTOPP_WORD128_AVAILABLE) +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; // for Integer +#endif +#if CRYPTOPP_BOOL_X86 +CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup; // for Integer +#endif + +/// \brief NULL allocator +/// \tparam T class or type +/// \details A NullAllocator is useful for fixed-size, stack based allocations +/// (i.e., static arrays used by FixedSizeAllocatorWithCleanup). +/// \details A NullAllocator always returns 0 for max_size(), and always returns +/// NULL for allocation requests. Though the allocator does not allocate at +/// runtime, it does perform a secure wipe or zeroization during cleanup. +template +class NullAllocator : public AllocatorBase +{ +public: + //LCOV_EXCL_START + CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T) + + // TODO: should this return NULL or throw bad_alloc? Non-Windows C++ standard + // libraries always throw. And late mode Windows throws. Early model Windows + // (circa VC++ 6.0) returned NULL. + pointer allocate(size_type n, const void* unused = NULLPTR) + { + CRYPTOPP_UNUSED(n); CRYPTOPP_UNUSED(unused); + CRYPTOPP_ASSERT(false); return NULLPTR; + } + + void deallocate(void *p, size_type n) + { + CRYPTOPP_UNUSED(p); CRYPTOPP_UNUSED(n); + CRYPTOPP_ASSERT(false); + } + + CRYPTOPP_CONSTEXPR size_type max_size() const {return 0;} + //LCOV_EXCL_STOP +}; + +/// \brief Static secure memory block with cleanup +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \tparam T_Align16 boolean that determines whether allocations should +/// be aligned on a 16-byte boundary +/// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- +/// based allocation at compile time. The class can grow its memory +/// block at runtime if a suitable allocator is available. If size +/// grows beyond S and a suitable allocator is available, then the +/// statically allocated array is obsoleted. +/// \note This allocator can't be used with standard collections because +/// they require that all objects of the same allocator type are equivalent. +template , bool T_Align16 = false> +class FixedSizeAllocatorWithCleanup : public AllocatorBase +{ + // The body of FixedSizeAllocatorWithCleanup is provided in the two + // partial specializations that follow. The two specializations + // pivot on the boolean template parameter T_Align16. +}; + +/// \brief Static secure memory block with cleanup +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- +/// based allocation at compile time. The class can grow its memory +/// block at runtime if a suitable allocator is available. If size +/// grows beyond S and a suitable allocator is available, then the +/// statically allocated array is obsoleted. +/// \note This allocator can't be used with standard collections because +/// they require that all objects of the same allocator type are equivalent. +template +class FixedSizeAllocatorWithCleanup : public AllocatorBase +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T) + + /// \brief Constructs a FixedSizeAllocatorWithCleanup + FixedSizeAllocatorWithCleanup() : m_allocated(false) {} + + /// \brief Allocates a block of memory + /// \param size the count elements in the memory block + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-based + /// allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \sa reallocate(), SecBlockWithHint + pointer allocate(size_type size) + { + CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); + + if (size <= S && !m_allocated) + { + m_allocated = true; + return GetAlignedArray(); + } + else + return m_fallbackAllocator.allocate(size); + } + + /// \brief Allocates a block of memory + /// \param size the count elements in the memory block + /// \param hint an unused hint + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + /// based allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \sa reallocate(), SecBlockWithHint + pointer allocate(size_type size, const void *hint) + { + CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); + + if (size <= S && !m_allocated) + { + m_allocated = true; + return GetAlignedArray(); + } + else + return m_fallbackAllocator.allocate(size, hint); + } + + /// \brief Deallocates a block of memory + /// \param ptr a pointer to the memory block to deallocate + /// \param size the count elements in the memory block + /// \details The memory block is wiped or zeroized before deallocation. + /// If the statically allocated memory block is active, then no + /// additional actions are taken after the wipe. + /// \details If a dynamic memory block is active, then the pointer and + /// size are passed to the allocator for deallocation. + void deallocate(void *ptr, size_type size) + { + // Avoid assert on pointer in deallocate. SecBlock regularly uses NULL + // pointers rather returning non-NULL 0-sized pointers. + if (ptr == GetAlignedArray()) + { + // If the m_allocated assert fires then the bit twiddling for + // GetAlignedArray() is probably incorrect for the platform. + // Be sure to check CRYPTOPP_ALIGN_DATA(8). The platform may + // not have a way to declaratively align data to 8. + CRYPTOPP_ASSERT(size <= S); + CRYPTOPP_ASSERT(m_allocated); + m_allocated = false; + SecureWipeArray(reinterpret_cast(ptr), size); + } + else + { + if (ptr) + m_fallbackAllocator.deallocate(ptr, size); + } + } + + /// \brief Reallocates a block of memory + /// \param oldPtr the previous allocation + /// \param oldSize the size of the previous allocation + /// \param newSize the new, requested size + /// \param preserve flag that indicates if the old allocation should + /// be preserved + /// \return pointer to the new memory block + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + /// based allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \note size is the count of elements, and not the number of bytes. + /// \sa reallocate(), SecBlockWithHint + pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve) + { + if (oldPtr == GetAlignedArray() && newSize <= S) + { + CRYPTOPP_ASSERT(oldSize <= S); + if (oldSize > newSize) + SecureWipeArray(oldPtr+newSize, oldSize-newSize); + return oldPtr; + } + + pointer newPtr = allocate(newSize, NULLPTR); + if (preserve && newSize) + { + const size_type copySize = STDMIN(oldSize, newSize); + if (newPtr && oldPtr) // GCC analyzer warning + memcpy_s(newPtr, sizeof(T)*newSize, oldPtr, sizeof(T)*copySize); + } + deallocate(oldPtr, oldSize); + return newPtr; + } + + CRYPTOPP_CONSTEXPR size_type max_size() const + { + return STDMAX(m_fallbackAllocator.max_size(), S); + } + +private: + +#if CRYPTOPP_BOOL_ALIGN16 + + // There be demons here... We cannot use CRYPTOPP_ALIGN_DATA(16) + // because linkers on 32-bit machines and some 64-bit machines + // align the stack to 8-bytes or less, and not 16-bytes as + // requested. We can only count on a smaller alignment. All + // toolchains tested appear to honor CRYPTOPP_ALIGN_DATA(8). Also + // see http://stackoverflow.com/a/1468656/608639. + // + // The 16-byte alignment is achieved by padding the requested + // size with extra elements so we have at least 8-bytes of slack + // to work with. Then the array pointer is moved to achieve a + // 16-byte alignment. + // + // The additional 8-bytes introduces a small secondary issue. + // The secondary issue is, a large T results in 0 = 8/sizeof(T). + // The library is OK but users may hit it. So we need to guard + // for a large T, and that is what the enum and PAD achieves. + T* GetAlignedArray() { + + // m_array is aligned on 8 byte boundaries due to + // CRYPTOPP_ALIGN_DATA(8). If m_array%16 is 0, then the buffer + // is 16-byte aligned and nothing needs to be done. if + // m_array%16 is 8, then the buffer is not 16-byte aligned and + // we need to add 8. 8 has that nice symmetric property. + // + // If we needed to use CRYPTOPP_ALIGN_DATA(4) due to toolchain + // limitations, then the calculation would be slightly more + // costly: ptr = m_array + (16 - (m_array % 16)) % 16; + CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); + int off = reinterpret_cast(m_array) % 16; + byte* ptr = reinterpret_cast(m_array) + off; + + // Verify the 16-byte alignment. This is the point + // of these extra gyrations. + CRYPTOPP_ASSERT(IsAlignedOn(ptr, 16)); + // Verify the lower bound. This is Issue 982/988. + CRYPTOPP_ASSERT( + reinterpret_cast(ptr) >= + reinterpret_cast(m_array) + ); + // Verify the upper bound. Allocated array with + // pad is large enough. + CRYPTOPP_ASSERT( + reinterpret_cast(ptr+S*sizeof(T)) <= + reinterpret_cast(m_array+(S+PAD)) + ); + + // void* to silence Clang warnings + return reinterpret_cast( + static_cast(ptr) + ); + } + + // PAD is elements, not bytes, and rounded up to ensure no overflow. + enum { Q = sizeof(T), PAD = (Q >= 8) ? 1 : (Q >= 4) ? 2 : (Q >= 2) ? 4 : 8 }; + // enum { Q = sizeof(T), PAD = (Q >= 16) ? 1 : (Q >= 8) ? 2 : (Q >= 4) ? 4 : (Q >= 2) ? 8 : 16 }; + CRYPTOPP_ALIGN_DATA(8) T m_array[S+PAD]; + +#else + + // CRYPTOPP_BOOL_ALIGN16 is 0. If we are here then the user + // probably compiled with CRYPTOPP_DISABLE_ASM. Normally we + // would use the natural alignment of T. The problem we are + // having is, some toolchains are changing the boundary for + // 64-bit arrays. 64-bit elements require 8-byte alignment, + // but the toolchain is laying the array out on a 4 byte + // boundary. See GH #992 for mystery alignment, + // https://github.com/weidai11/cryptopp/issues/992 + T* GetAlignedArray() {return m_array;} + CRYPTOPP_ALIGN_DATA(8) T m_array[S]; + +#endif + + A m_fallbackAllocator; + bool m_allocated; +}; + +/// \brief Static secure memory block with cleanup +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- +/// based allocation at compile time. The class can grow its memory +/// block at runtime if a suitable allocator is available. If size +/// grows beyond S and a suitable allocator is available, then the +/// statically allocated array is obsoleted. +/// \note This allocator can't be used with standard collections because +/// they require that all objects of the same allocator type are equivalent. +template +class FixedSizeAllocatorWithCleanup : public AllocatorBase +{ +public: + CRYPTOPP_INHERIT_ALLOCATOR_TYPES(T) + + /// \brief Constructs a FixedSizeAllocatorWithCleanup + FixedSizeAllocatorWithCleanup() : m_allocated(false) {} + + /// \brief Allocates a block of memory + /// \param size the count elements in the memory block + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack-based + /// allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \sa reallocate(), SecBlockWithHint + pointer allocate(size_type size) + { + CRYPTOPP_ASSERT(IsAlignedOn(m_array, 8)); + + if (size <= S && !m_allocated) + { + m_allocated = true; + return GetAlignedArray(); + } + else + return m_fallbackAllocator.allocate(size); + } + + /// \brief Allocates a block of memory + /// \param size the count elements in the memory block + /// \param hint an unused hint + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + /// based allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \sa reallocate(), SecBlockWithHint + pointer allocate(size_type size, const void *hint) + { + if (size <= S && !m_allocated) + { + m_allocated = true; + return GetAlignedArray(); + } + else + return m_fallbackAllocator.allocate(size, hint); + } + + /// \brief Deallocates a block of memory + /// \param ptr a pointer to the memory block to deallocate + /// \param size the count elements in the memory block + /// \details The memory block is wiped or zeroized before deallocation. + /// If the statically allocated memory block is active, then no + /// additional actions are taken after the wipe. + /// \details If a dynamic memory block is active, then the pointer and + /// size are passed to the allocator for deallocation. + void deallocate(void *ptr, size_type size) + { + // Avoid assert on pointer in deallocate. SecBlock regularly uses NULL + // pointers rather returning non-NULL 0-sized pointers. + if (ptr == GetAlignedArray()) + { + // If the m_allocated assert fires then + // something overwrote the flag. + CRYPTOPP_ASSERT(size <= S); + CRYPTOPP_ASSERT(m_allocated); + m_allocated = false; + SecureWipeArray((pointer)ptr, size); + } + else + { + if (ptr) + m_fallbackAllocator.deallocate(ptr, size); + m_allocated = false; + } + } + + /// \brief Reallocates a block of memory + /// \param oldPtr the previous allocation + /// \param oldSize the size of the previous allocation + /// \param newSize the new, requested size + /// \param preserve flag that indicates if the old allocation should + /// be preserved + /// \return pointer to the new memory block + /// \details FixedSizeAllocatorWithCleanup provides a fixed-size, stack- + /// based allocation at compile time. If size is less than or equal to + /// S, then a pointer to the static array is returned. + /// \details The class can grow its memory block at runtime if a suitable + /// allocator is available. If size grows beyond S and a suitable + /// allocator is available, then the statically allocated array is + /// obsoleted. If a suitable allocator is not available, as with a + /// NullAllocator, then the function returns NULL and a runtime error + /// eventually occurs. + /// \note size is the count of elements, and not the number of bytes. + /// \sa reallocate(), SecBlockWithHint + pointer reallocate(pointer oldPtr, size_type oldSize, size_type newSize, bool preserve) + { + if (oldPtr == GetAlignedArray() && newSize <= S) + { + CRYPTOPP_ASSERT(oldSize <= S); + if (oldSize > newSize) + SecureWipeArray(oldPtr+newSize, oldSize-newSize); + return oldPtr; + } + + pointer newPtr = allocate(newSize, NULLPTR); + if (preserve && newSize) + { + const size_type copySize = STDMIN(oldSize, newSize); + if (newPtr && oldPtr) // GCC analyzer warning + memcpy_s(newPtr, sizeof(T)*newSize, oldPtr, sizeof(T)*copySize); + } + deallocate(oldPtr, oldSize); + return newPtr; + } + + CRYPTOPP_CONSTEXPR size_type max_size() const + { + return STDMAX(m_fallbackAllocator.max_size(), S); + } + +private: + + // T_Align16 is false. Normally we would use the natural + // alignment of T. The problem we are having is, some toolchains + // are changing the boundary for 64-bit arrays. 64-bit elements + // require 8-byte alignment, but the toolchain is laying the array + // out on a 4 byte boundary. See GH #992 for mystery alignment, + // https://github.com/weidai11/cryptopp/issues/992 + T* GetAlignedArray() {return m_array;} + CRYPTOPP_ALIGN_DATA(8) T m_array[S]; + + A m_fallbackAllocator; + bool m_allocated; +}; + +/// \brief Secure memory block with allocator and cleanup +/// \tparam T a class or type +/// \tparam A AllocatorWithCleanup derived class for allocation and cleanup +/// \sa SecBlock +/// on the Crypto++ wiki. +/// \since Crypto++ 2.0 +template > +class SecBlock +{ +public: + typedef typename A::value_type value_type; + typedef typename A::pointer iterator; + typedef typename A::const_pointer const_iterator; + typedef typename A::size_type size_type; + + /// \brief Returns the maximum number of elements the block can hold + /// \details ELEMS_MAX is the maximum number of elements the + /// SecBlock can hold. The value of ELEMS_MAX is + /// SIZE_MAX/sizeof(T). std::numeric_limits was avoided + /// due to lack of constexpr-ness in C++03 and below. + /// \note In C++03 and below ELEMS_MAX is a static data member of type + /// size_type. In C++11 and above ELEMS_MAX is an enum + /// inheriting from size_type. In both cases ELEMS_MAX can be + /// used before objects are fully constructed, and it does not suffer the + /// limitations of class methods like max_size. + /// \sa Issue 346/CVE-2016-9939 + /// \since Crypto++ 6.0 +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) + static const size_type ELEMS_MAX = ...; +#elif defined(CRYPTOPP_MSC_VERSION) && (CRYPTOPP_MSC_VERSION <= 1400) + static const size_type ELEMS_MAX = (~(size_type)0)/sizeof(T); +#elif defined(CRYPTOPP_CXX11_STRONG_ENUM) + enum : size_type {ELEMS_MAX = A::ELEMS_MAX}; +#else + static const size_type ELEMS_MAX = SIZE_MAX/sizeof(T); +#endif + + /// \brief Construct a SecBlock with space for size elements. + /// \param size the size of the allocation, in elements + /// \throw std::bad_alloc + /// \details The elements are not initialized. + /// \since Crypto++ 2.0 + /// \note size is the count of elements, and not the number of bytes + explicit SecBlock(size_type size=0) + : m_mark(ELEMS_MAX), m_size(size), m_ptr(m_alloc.allocate(size, NULLPTR)) { } + + /// \brief Copy construct a SecBlock from another SecBlock + /// \param t the other SecBlock + /// \throw std::bad_alloc + /// \since Crypto++ 2.0 + SecBlock(const SecBlock &t) + : m_mark(t.m_mark), m_size(t.m_size), m_ptr(m_alloc.allocate(t.m_size, NULLPTR)) { + CRYPTOPP_ASSERT((!t.m_ptr && !m_size) || (t.m_ptr && m_size)); + if (m_ptr && t.m_ptr) + memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T)); + } + + /// \brief Construct a SecBlock from an array of elements. + /// \param ptr a pointer to an array of T + /// \param len the number of elements in the memory block + /// \throw std::bad_alloc + /// \details If ptr!=NULL and len!=0, then the block is initialized from the pointer + /// ptr. If ptr==NULL and len!=0, then the block is initialized to 0. + /// Otherwise, the block is empty and not initialized. + /// \since Crypto++ 2.0 + /// \note size is the count of elements, and not the number of bytes + SecBlock(const T *ptr, size_type len) + : m_mark(ELEMS_MAX), m_size(len), m_ptr(m_alloc.allocate(len, NULLPTR)) { + CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size)); + if (m_ptr && ptr) + memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T)); + else if (m_ptr && m_size) + std::memset(m_ptr, 0, m_size*sizeof(T)); + } + + ~SecBlock() + {m_alloc.deallocate(m_ptr, STDMIN(m_size, m_mark));} + +#ifdef __BORLANDC__ + /// \brief Cast operator + /// \return block pointer cast to non-const T * + /// \since Crypto++ 2.0 + operator T *() const + {return (T*)m_ptr;} +#else + /// \brief Cast operator + /// \return block pointer cast to const void * + /// \since Crypto++ 2.0 + operator const void *() const + {return m_ptr;} + + /// \brief Cast operator + /// \return block pointer cast to non-const void * + /// \since Crypto++ 2.0 + operator void *() + {return m_ptr;} + + /// \brief Cast operator + /// \return block pointer cast to const T * + /// \since Crypto++ 2.0 + operator const T *() const + {return m_ptr;} + + /// \brief Cast operator + /// \return block pointer cast to non-const T * + /// \since Crypto++ 2.0 + operator T *() + {return m_ptr;} +#endif + + /// \brief Provides an iterator pointing to the first element in the memory block + /// \return iterator pointing to the first element in the memory block + /// \since Crypto++ 2.0 + iterator begin() + {return m_ptr;} + /// \brief Provides a constant iterator pointing to the first element in the memory block + /// \return constant iterator pointing to the first element in the memory block + /// \since Crypto++ 2.0 + const_iterator begin() const + {return m_ptr;} + /// \brief Provides an iterator pointing beyond the last element in the memory block + /// \return iterator pointing beyond the last element in the memory block + /// \since Crypto++ 2.0 + iterator end() + {return m_ptr+m_size;} + /// \brief Provides a constant iterator pointing beyond the last element in the memory block + /// \return constant iterator pointing beyond the last element in the memory block + /// \since Crypto++ 2.0 + const_iterator end() const + {return m_ptr+m_size;} + + /// \brief Provides a pointer to the first element in the memory block + /// \return pointer to the first element in the memory block + /// \since Crypto++ 2.0 + typename A::pointer data() {return m_ptr;} + /// \brief Provides a pointer to the first element in the memory block + /// \return constant pointer to the first element in the memory block + /// \since Crypto++ 2.0 + typename A::const_pointer data() const {return m_ptr;} + + /// \brief Provides the count of elements in the SecBlock + /// \return number of elements in the memory block + /// \note the return value is the count of elements, and not the number of bytes + /// \since Crypto++ 2.0 + size_type size() const {return m_size;} + /// \brief Determines if the SecBlock is empty + /// \return true if number of elements in the memory block is 0, false otherwise + /// \since Crypto++ 2.0 + bool empty() const {return m_size == 0;} + + /// \brief Provides a byte pointer to the first element in the memory block + /// \return byte pointer to the first element in the memory block + /// \since Crypto++ 2.0 + byte * BytePtr() {return (byte *)m_ptr;} + /// \brief Return a byte pointer to the first element in the memory block + /// \return constant byte pointer to the first element in the memory block + /// \since Crypto++ 2.0 + const byte * BytePtr() const {return (const byte *)m_ptr;} + /// \brief Provides the number of bytes in the SecBlock + /// \return the number of bytes in the memory block + /// \note the return value is the number of bytes, and not count of elements. + /// \since Crypto++ 2.0 + size_type SizeInBytes() const {return m_size*sizeof(T);} + + /// \brief Set contents and size from an array + /// \param ptr a pointer to an array of T + /// \param len the number of elements in the memory block + /// \details The array pointed to by ptr must be distinct + /// from this SecBlock because Assign() calls New() and then std::memcpy(). + /// The call to New() will invalidate all pointers and iterators, like + /// the pointer returned from data(). + /// \details If the memory block is reduced in size, then the reclaimed + /// memory is set to 0. If an assignment occurs, then Assign() resets + /// the element count after the previous block is zeroized. + /// \since Crypto++ 2.0 + void Assign(const T *ptr, size_type len) + { + New(len); + if (m_ptr && ptr) // GCC analyzer warning + memcpy_s(m_ptr, m_size*sizeof(T), ptr, len*sizeof(T)); + m_mark = ELEMS_MAX; + } + + /// \brief Set contents from a value + /// \param count the number of values to copy + /// \param value the value, repeated count times + /// \details If the memory block is reduced in size, then the reclaimed + /// memory is set to 0. If an assignment occurs, then Assign() resets + /// the element count after the previous block is zeroized. + /// \since Crypto++ 6.0 + void Assign(size_type count, T value) + { + New(count); + for (size_t i=0; i &t) + { + if (this != &t) + { + New(t.m_size); + if (m_ptr && t.m_ptr) // GCC analyzer warning + memcpy_s(m_ptr, m_size*sizeof(T), t, t.m_size*sizeof(T)); + } + m_mark = ELEMS_MAX; + } + + /// \brief Append contents from an array + /// \param ptr a pointer to an array of T + /// \param len the number of elements in the memory block + /// \throw InvalidArgument if resulting size would overflow + /// \details The array pointed to by ptr must be distinct + /// from this SecBlock because Append() calls Grow() and then std::memcpy(). + /// The call to Grow() will invalidate all pointers and iterators, like + /// the pointer returned from data(). + /// \details Append() may be less efficient than a ByteQueue because + /// Append() must Grow() the internal array and then copy elements. + /// The ByteQueue can copy elements without growing. + /// \sa ByteQueue + /// \since Crypto++ 8.6 + void Append(const T *ptr, size_type len) + { + if (ELEMS_MAX - m_size < len) + throw InvalidArgument("SecBlock: buffer overflow"); + + const size_type oldSize = m_size; + Grow(m_size+len); + if (m_ptr && ptr) // GCC analyzer warning + memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), ptr, len*sizeof(T)); + m_mark = ELEMS_MAX; + } + + /// \brief Append contents from another SecBlock + /// \param t the other SecBlock + /// \throw InvalidArgument if resulting size would overflow + /// \details Internally, this SecBlock calls Grow() and then appends t. + /// \details Append() may be less efficient than a ByteQueue because + /// Append() must Grow() the internal array and then copy elements. + /// The ByteQueue can copy elements without growing. + /// \sa ByteQueue + /// \since Crypto++ 8.6 + void Append(const SecBlock &t) + { + if (ELEMS_MAX - m_size < t.m_size) + throw InvalidArgument("SecBlock: buffer overflow"); + + const size_type oldSize = m_size; + if (this != &t) // s += t + { + Grow(m_size+t.m_size); + if (m_ptr && t.m_ptr) // GCC analyzer warning + memcpy_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), t.m_ptr, t.m_size*sizeof(T)); + } + else // t += t + { + Grow(m_size*2); + if (m_ptr) // GCC analyzer warning + memmove_s(m_ptr+oldSize, (m_size-oldSize)*sizeof(T), m_ptr, oldSize*sizeof(T)); + } + m_mark = ELEMS_MAX; + } + + /// \brief Append contents from a value + /// \param count the number of values to copy + /// \param value the value, repeated count times + /// \throw InvalidArgument if resulting size would overflow + /// \details Internally, this SecBlock calls Grow() and then appends value. + /// \details Append() may be less efficient than a ByteQueue because + /// Append() must Grow() the internal array and then copy elements. + /// The ByteQueue can copy elements without growing. + /// \sa ByteQueue + /// \since Crypto++ 8.6 + void Append(size_type count, T value) + { + if (ELEMS_MAX - m_size < count) + throw InvalidArgument("SecBlock: buffer overflow"); + + const size_type oldSize = m_size; + Grow(m_size+count); + for (size_t i=oldSize; icount controls the number of + /// elements zeroized, which can be less than size or 0. + /// \details An internal variable, m_mark, is initialized to the maximum number + /// of elements. The maximum number of elements is ELEMS_MAX. Deallocation + /// triggers a zeroization, and the number of elements zeroized is + /// STDMIN(m_size, m_mark). After zeroization, the memory is returned to the + /// system. + /// \details The ASN.1 decoder uses SetMark() to set the element count to 0 + /// before throwing an exception. In this case, the attacker provides a large + /// BER encoded length (say 64MB) but only a small number of content octets + /// (say 16). If the allocator zeroized all 64MB, then a transient DoS could + /// occur as CPU cycles are spent zeroizing uninitialized memory. + /// \details Generally speaking, any operation which changes the size of the SecBlock + /// results in the mark being reset to ELEMS_MAX. In particular, if Assign(), + /// New(), Grow(), CleanNew(), CleanGrow() are called, then the count is reset to + /// ELEMS_MAX. The list is not exhaustive. + /// \since Crypto++ 6.0 + /// \sa Issue 346/CVE-2016-9939 + void SetMark(size_t count) {m_mark = count;} + + /// \brief Assign contents from another SecBlock + /// \param t the other SecBlock + /// \return reference to this SecBlock + /// \details Internally, operator=() calls Assign(). + /// \details If the memory block is reduced in size, then the reclaimed + /// memory is set to 0. If an assignment occurs, then Assign() resets + /// the element count after the previous block is zeroized. + /// \since Crypto++ 2.0 + SecBlock& operator=(const SecBlock &t) + { + // Assign guards for self-assignment + Assign(t); + return *this; + } + + /// \brief Append contents from another SecBlock + /// \param t the other SecBlock + /// \return reference to this SecBlock + /// \details Internally, operator+=() calls Append(). + /// \since Crypto++ 2.0 + SecBlock& operator+=(const SecBlock &t) + { + // Append guards for overflow + Append(t); + return *this; + } + + /// \brief Construct a SecBlock from this and another SecBlock + /// \param t the other SecBlock + /// \return a newly constructed SecBlock that is a concatenation of this + /// and t. + /// \details Internally, a new SecBlock is created from this and a + /// concatenation of t. + /// \since Crypto++ 2.0 + SecBlock operator+(const SecBlock &t) + { + CRYPTOPP_ASSERT((!m_ptr && !m_size) || (m_ptr && m_size)); + CRYPTOPP_ASSERT((!t.m_ptr && !t.m_size) || (t.m_ptr && t.m_size)); + if(!t.m_size) return SecBlock(*this); + + SecBlock result(m_size+t.m_size); + if (m_size) + memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T)); + if (result.m_ptr && t.m_ptr) // GCC analyzer warning + memcpy_s(result.m_ptr+m_size, (result.m_size-m_size)*sizeof(T), t.m_ptr, t.m_size*sizeof(T)); + return result; + } + + /// \brief Bitwise compare two SecBlocks + /// \param t the other SecBlock + /// \return true if the size and bits are equal, false otherwise + /// \details Uses a constant time compare if the arrays are equal size. + /// The constant time compare is VerifyBufsEqual() found in + /// misc.h. + /// \sa operator!=() + /// \since Crypto++ 2.0 + bool operator==(const SecBlock &t) const + { + return m_size == t.m_size && VerifyBufsEqual( + reinterpret_cast(m_ptr), + reinterpret_cast(t.m_ptr), m_size*sizeof(T)); + } + + /// \brief Bitwise compare two SecBlocks + /// \param t the other SecBlock + /// \return true if the size and bits are equal, false otherwise + /// \details Uses a constant time compare if the arrays are equal size. + /// The constant time compare is VerifyBufsEqual() found in + /// misc.h. + /// \details Internally, operator!=() returns the inverse of operator==(). + /// \sa operator==() + /// \since Crypto++ 2.0 + bool operator!=(const SecBlock &t) const + { + return !operator==(t); + } + + /// \brief Change size without preserving contents + /// \param newSize the new size of the memory block + /// \details Old content is not preserved. If the memory block is + /// reduced in size, then the reclaimed content is set to 0. If the + /// memory block grows in size, then the new memory is initialized + /// to 0. New() resets the element count after the previous block + /// is zeroized. + /// \details Internally, this SecBlock calls reallocate(). + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + /// \since Crypto++ 2.0 + void New(size_type newSize) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false); + m_size = newSize; + m_mark = ELEMS_MAX; + } + + /// \brief Change size without preserving contents + /// \param newSize the new size of the memory block + /// \details Old content is not preserved. If the memory block is + /// reduced in size, then the reclaimed content is set to 0. If the + /// memory block grows in size, then the new memory is initialized + /// to 0. CleanNew() resets the element count after the previous + /// block is zeroized. + /// \details Internally, this SecBlock calls New(). + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + /// \since Crypto++ 2.0 + void CleanNew(size_type newSize) + { + New(newSize); + if (m_ptr) {memset_z(m_ptr, 0, m_size*sizeof(T));} + m_mark = ELEMS_MAX; + } + + /// \brief Change size and preserve contents + /// \param newSize the new size of the memory block + /// \details Old content is preserved. New content is not initialized. + /// \details Internally, this SecBlock calls reallocate() when size must + /// increase. If the size does not increase, then CleanGrow() does not + /// take action. If the size must change, then use resize(). CleanGrow() + /// resets the element count after the previous block is zeroized. + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + /// \since Crypto++ 2.0 + void Grow(size_type newSize) + { + if (newSize > m_size) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + m_size = newSize; + } + m_mark = ELEMS_MAX; + } + + /// \brief Change size and preserve contents + /// \param newSize the new size of the memory block + /// \details Old content is preserved. New content is initialized to 0. + /// \details Internally, this SecBlock calls reallocate() when size must + /// increase. If the size does not increase, then CleanGrow() does not + /// take action. If the size must change, then use resize(). CleanGrow() + /// resets the element count after the previous block is zeroized. + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + /// \since Crypto++ 2.0 + void CleanGrow(size_type newSize) + { + if (newSize > m_size) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + memset_z(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T)); + m_size = newSize; + } + m_mark = ELEMS_MAX; + } + + /// \brief Change size and preserve contents + /// \param newSize the new size of the memory block + /// \details Old content is preserved. If the memory block grows in size, then + /// new memory is not initialized. resize() resets the element count after + /// the previous block is zeroized. + /// \details Internally, this SecBlock calls reallocate(). + /// \sa New(), CleanNew(), Grow(), CleanGrow(), resize() + /// \since Crypto++ 2.0 + void resize(size_type newSize) + { + m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true); + m_size = newSize; + m_mark = ELEMS_MAX; + } + + /// \brief Swap contents with another SecBlock + /// \param b the other SecBlock + /// \details Internally, std::swap() is called on m_alloc, m_size and m_ptr. + /// \since Crypto++ 2.0 + void swap(SecBlock &b) + { + // Swap must occur on the allocator in case its FixedSize that spilled into the heap. + std::swap(m_alloc, b.m_alloc); + std::swap(m_mark, b.m_mark); + std::swap(m_size, b.m_size); + std::swap(m_ptr, b.m_ptr); + } + +protected: + A m_alloc; + size_type m_mark, m_size; + T *m_ptr; +}; + +#ifdef CRYPTOPP_DOXYGEN_PROCESSING +/// \brief \ref SecBlock "SecBlock" typedef. +class SecByteBlock : public SecBlock {}; +/// \brief \ref SecBlock "SecBlock" typedef. +class SecWordBlock : public SecBlock {}; +/// \brief SecBlock using \ref AllocatorWithCleanup "AllocatorWithCleanup" typedef +class AlignedSecByteBlock : public SecBlock > {}; +#else +typedef SecBlock SecByteBlock; +typedef SecBlock SecWordBlock; +typedef SecBlock > AlignedSecByteBlock; +#endif + +// No need for move semantics on derived class *if* the class does not add any +// data members; see http://stackoverflow.com/q/31755703, and Rule of {0|3|5}. + +/// \brief Fixed size stack-based SecBlock +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \tparam A AllocatorBase derived class for allocation and cleanup +template > +class FixedSizeSecBlock : public SecBlock +{ +public: + /// \brief Construct a FixedSizeSecBlock + explicit FixedSizeSecBlock() : SecBlock(S) {} +}; + +/// \brief Fixed size stack-based SecBlock with 16-byte alignment +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \tparam T_Align16 boolean that determines whether allocations should be +/// aligned on a 16-byte boundary +template +class FixedSizeAlignedSecBlock : public FixedSizeSecBlock, T_Align16> > +{ +}; + +/// \brief Stack-based SecBlock that grows into the heap +/// \tparam T class or type +/// \tparam S fixed-size of the stack-based memory block, in elements +/// \tparam A AllocatorBase derived class for allocation and cleanup +template > > +class SecBlockWithHint : public SecBlock +{ +public: + /// construct a SecBlockWithHint with a count of elements + explicit SecBlockWithHint(size_t size) : SecBlock(size) {} +}; + +template +inline bool operator==(const CryptoPP::AllocatorWithCleanup&, const CryptoPP::AllocatorWithCleanup&) {return (true);} +template +inline bool operator!=(const CryptoPP::AllocatorWithCleanup&, const CryptoPP::AllocatorWithCleanup&) {return (false);} + +NAMESPACE_END + +NAMESPACE_BEGIN(std) + +/// \brief Swap two SecBlocks +/// \tparam T class or type +/// \tparam A AllocatorBase derived class for allocation and cleanup +/// \param a the first SecBlock +/// \param b the second SecBlock +template +inline void swap(CryptoPP::SecBlock &a, CryptoPP::SecBlock &b) +{ + a.swap(b); +} + +#if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES)) +// working for STLport 5.1.3 and MSVC 6 SP5 +template +inline CryptoPP::AllocatorWithCleanup<_Tp2>& +__stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*) +{ + return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a); +} +#endif + +NAMESPACE_END + +#if defined(CRYPTOPP_MSC_VERSION) +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/secblockfwd.h b/third_party/cryptoppwin/include/cryptopp/secblockfwd.h new file mode 100644 index 00000000..2d68c41e --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/secblockfwd.h @@ -0,0 +1,29 @@ +// secblockfwd.h - written and placed in the public domain by Jeffrey Walton + +/// \file secblockfwd.h +/// \brief Forward declarations for SecBlock +/// \details secblock.h and misc.h have a circular dependency. secblockfwd.h +/// allows the library to sidestep the circular dependency, and reference +/// SecBlock classes without the full implementation. +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_SECBLOCKFWD_H +#define CRYPTOPP_SECBLOCKFWD_H + +#include "config.h" + +NAMESPACE_BEGIN(CryptoPP) + +template +class SecBlock; + +template +class AllocatorWithCleanup; + +typedef SecBlock > SecByteBlock; +typedef SecBlock > SecWordBlock; +typedef SecBlock > AlignedSecByteBlock; + +NAMESPACE_END + +#endif // CRYPTOPP_SECBLOCKFWD_H diff --git a/third_party/cryptoppwin/include/cryptopp/seckey.h b/third_party/cryptoppwin/include/cryptopp/seckey.h new file mode 100644 index 00000000..2fc6bedc --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/seckey.h @@ -0,0 +1,444 @@ +// seckey.h - originally written and placed in the public domain by Wei Dai + +/// \file seckey.h +/// \brief Classes and functions for implementing secret key algorithms. + +#ifndef CRYPTOPP_SECKEY_H +#define CRYPTOPP_SECKEY_H + +#include "config.h" +#include "cryptlib.h" +#include "misc.h" +#include "simple.h" +#include "stdcpp.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4189 4296) +#endif + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Inverts the cipher's direction +/// \param dir the cipher's direction +/// \return DECRYPTION if \ref CipherDir "dir" is ENCRYPTION, DECRYPTION otherwise +inline CipherDir ReverseCipherDir(CipherDir dir) +{ + return (dir == ENCRYPTION) ? DECRYPTION : ENCRYPTION; +} + +/// \brief Inherited by algorithms with fixed block size +/// \tparam N the blocksize of the algorithm +template +class FixedBlockSize +{ +public: + /// \brief The block size of the algorithm provided as a constant. + CRYPTOPP_CONSTANT(BLOCKSIZE = N); +}; + +// ************** rounds *************** + +/// \brief Inherited by algorithms with fixed number of rounds +/// \tparam R the number of rounds used by the algorithm +template +class FixedRounds +{ +public: + /// \brief The number of rounds for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(ROUNDS = R); +}; + +/// \brief Inherited by algorithms with variable number of rounds +/// \tparam D Default number of rounds +/// \tparam N Minimum number of rounds +/// \tparam M Maximum number of rounds +template // use INT_MAX here because enums are treated as signed ints +class VariableRounds +{ +public: + /// \brief The default number of rounds for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(DEFAULT_ROUNDS = D); + /// \brief The minimum number of rounds for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(MIN_ROUNDS = N); + /// \brief The maximum number of rounds for the algorithm provided as a constant. + CRYPTOPP_CONSTANT(MAX_ROUNDS = M); + /// \brief The default number of rounds for the algorithm based on key length + /// provided by a static function. + /// \param keylength the size of the key, in bytes + /// \details keylength is unused in the default implementation. + CRYPTOPP_STATIC_CONSTEXPR unsigned int StaticGetDefaultRounds(size_t keylength) + { + return CRYPTOPP_UNUSED(keylength), static_cast(DEFAULT_ROUNDS); + } + +protected: + /// \brief Validates the number of rounds for an algorithm. + /// \param rounds the candidate number of rounds + /// \param alg an Algorithm object used if the number of rounds are invalid + /// \throw InvalidRounds if the number of rounds are invalid + /// \details ThrowIfInvalidRounds() validates the number of rounds and throws if invalid. + inline void ThrowIfInvalidRounds(int rounds, const Algorithm *alg) + { + if (M == INT_MAX) // Coverity and result_independent_of_operands + { + if (rounds < MIN_ROUNDS) + throw InvalidRounds(alg ? alg->AlgorithmName() : std::string("VariableRounds"), rounds); + } + else + { + if (rounds < MIN_ROUNDS || rounds > MAX_ROUNDS) + throw InvalidRounds(alg ? alg->AlgorithmName() : std::string("VariableRounds"), rounds); + } + } + + /// \brief Validates the number of rounds for an algorithm + /// \param param the candidate number of rounds + /// \param alg an Algorithm object used if the number of rounds are invalid + /// \return the number of rounds for the algorithm + /// \throw InvalidRounds if the number of rounds are invalid + /// \details GetRoundsAndThrowIfInvalid() validates the number of rounds and throws if invalid. + inline unsigned int GetRoundsAndThrowIfInvalid(const NameValuePairs ¶m, const Algorithm *alg) + { + int rounds = param.GetIntValueWithDefault("Rounds", DEFAULT_ROUNDS); + ThrowIfInvalidRounds(rounds, alg); + return static_cast(rounds); + } +}; + +// ************** key length *************** + +/// \brief Inherited by keyed algorithms with fixed key length +/// \tparam N Default key length, in bytes +/// \tparam IV_REQ the \ref SimpleKeyingInterface::IV_Requirement "IV requirements" +/// \tparam IV_L default IV length, in bytes +/// \sa SimpleKeyingInterface +template +class FixedKeyLength +{ +public: + /// \brief The default key length used by the algorithm provided as a constant + /// \details KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(KEYLENGTH=N); + /// \brief The minimum key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MIN_KEYLENGTH=N); + /// \brief The maximum key length used by the algorithm provided as a constant + /// \details MAX_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MAX_KEYLENGTH=N); + /// \brief The default key length used by the algorithm provided as a constant + /// \details DEFAULT_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH=N); + /// \brief The default IV requirements for the algorithm provided as a constant + /// \details The default value is NOT_RESYNCHRONIZABLE. See IV_Requirement + /// in cryptlib.h for allowed values. + CRYPTOPP_CONSTANT(IV_REQUIREMENT = IV_REQ); + /// \brief The default IV length used by the algorithm provided as a constant + /// \details IV_LENGTH is provided in bytes, not bits. The default implementation uses 0. + CRYPTOPP_CONSTANT(IV_LENGTH = IV_L); + /// \brief The default key length for the algorithm provided by a static function. + /// \param keylength the size of the key, in bytes + /// \details The default implementation returns KEYLENGTH. keylength is unused + /// in the default implementation. + CRYPTOPP_STATIC_CONSTEXPR size_t CRYPTOPP_API StaticGetValidKeyLength(size_t keylength) + { + return CRYPTOPP_UNUSED(keylength), static_cast(KEYLENGTH); + } +}; + +/// \brief Inherited by keyed algorithms with variable key length +/// \tparam D Default key length, in bytes +/// \tparam N Minimum key length, in bytes +/// \tparam M Maximum key length, in bytes +/// \tparam Q Default key length multiple, in bytes. The default multiple is 1. +/// \tparam IV_REQ the \ref SimpleKeyingInterface::IV_Requirement "IV requirements" +/// \tparam IV_L default IV length, in bytes. The default length is 0. +/// \sa SimpleKeyingInterface +template +class VariableKeyLength +{ + // Make these private to avoid Doxygen documenting them in all derived classes + CRYPTOPP_COMPILE_ASSERT(Q > 0); + CRYPTOPP_COMPILE_ASSERT(N % Q == 0); + CRYPTOPP_COMPILE_ASSERT(M % Q == 0); + CRYPTOPP_COMPILE_ASSERT(N < M); + CRYPTOPP_COMPILE_ASSERT(D >= N); + CRYPTOPP_COMPILE_ASSERT(M >= D); + +public: + /// \brief The minimum key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MIN_KEYLENGTH=N); + /// \brief The maximum key length used by the algorithm provided as a constant + /// \details MAX_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MAX_KEYLENGTH=M); + /// \brief The default key length used by the algorithm provided as a constant + /// \details DEFAULT_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH=D); + /// \brief The key length multiple used by the algorithm provided as a constant + /// \details MAX_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(KEYLENGTH_MULTIPLE=Q); + /// \brief The default IV requirements for the algorithm provided as a constant + /// \details The default value is NOT_RESYNCHRONIZABLE. See IV_Requirement + /// in cryptlib.h for allowed values. + CRYPTOPP_CONSTANT(IV_REQUIREMENT=IV_REQ); + /// \brief The default initialization vector length for the algorithm provided as a constant + /// \details IV_LENGTH is provided in bytes, not bits. The default implementation uses 0. + CRYPTOPP_CONSTANT(IV_LENGTH=IV_L); + /// \brief Provides a valid key length for the algorithm provided by a static function. + /// \param keylength the size of the key, in bytes + /// \details If keylength is less than MIN_KEYLENGTH, then the function returns + /// MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, then the function + /// returns MAX_KEYLENGTH. If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns keylength rounded + /// \a down to the next smaller multiple of KEYLENGTH_MULTIPLE. + /// \details keylength is provided in bytes, not bits. + CRYPTOPP_STATIC_CONSTEXPR size_t CRYPTOPP_API StaticGetValidKeyLength(size_t keylength) + { + return (keylength <= N) ? N : + (keylength >= M) ? M : + (keylength+Q-1) - (keylength+Q-1)%Q; + } +}; + +/// \brief Provides key lengths based on another class's key length +/// \tparam T another FixedKeyLength or VariableKeyLength class +/// \tparam IV_REQ the \ref SimpleKeyingInterface::IV_Requirement "IV requirements" +/// \tparam IV_L default IV length, in bytes +/// \sa SimpleKeyingInterface +template +class SameKeyLengthAs +{ +public: + /// \brief The minimum key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MIN_KEYLENGTH=T::MIN_KEYLENGTH); + /// \brief The maximum key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(MAX_KEYLENGTH=T::MAX_KEYLENGTH); + /// \brief The default key length used by the algorithm provided as a constant + /// \details MIN_KEYLENGTH is provided in bytes, not bits + CRYPTOPP_CONSTANT(DEFAULT_KEYLENGTH=T::DEFAULT_KEYLENGTH); + /// \brief The default IV requirements for the algorithm provided as a constant + /// \details The default value is NOT_RESYNCHRONIZABLE. See IV_Requirement + /// in cryptlib.h for allowed values. + CRYPTOPP_CONSTANT(IV_REQUIREMENT=IV_REQ); + /// \brief The default initialization vector length for the algorithm provided as a constant + /// \details IV_LENGTH is provided in bytes, not bits. The default implementation uses 0. + CRYPTOPP_CONSTANT(IV_LENGTH=IV_L); + /// \brief Provides a valid key length for the algorithm provided by a static function. + /// \param keylength the size of the key, in bytes + /// \details If keylength is less than MIN_KEYLENGTH, then the function returns + /// MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, then the function + /// returns MAX_KEYLENGTH. If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns keylength rounded + /// \a down to the next smaller multiple of KEYLENGTH_MULTIPLE. + /// \details keylength is provided in bytes, not bits. + CRYPTOPP_STATIC_CONSTEXPR size_t CRYPTOPP_API StaticGetValidKeyLength(size_t keylength) + {return T::StaticGetValidKeyLength(keylength);} +}; + +// ************** implementation helper for SimpleKeyingInterface *************** + +/// \brief Provides a base implementation of SimpleKeyingInterface +/// \tparam BASE a SimpleKeyingInterface derived class +/// \tparam INFO a SimpleKeyingInterface derived class +/// \details SimpleKeyingInterfaceImpl() provides a default implementation for ciphers providing a keying interface. +/// Functions are virtual and not eligible for C++11 constexpr-ness. +/// \sa Algorithm(), SimpleKeyingInterface() +template +class CRYPTOPP_NO_VTABLE SimpleKeyingInterfaceImpl : public BASE +{ +public: + /// \brief The minimum key length used by the algorithm + /// \return minimum key length used by the algorithm, in bytes + size_t MinKeyLength() const + {return INFO::MIN_KEYLENGTH;} + + /// \brief The maximum key length used by the algorithm + /// \return maximum key length used by the algorithm, in bytes + size_t MaxKeyLength() const + {return static_cast(INFO::MAX_KEYLENGTH);} + + /// \brief The default key length used by the algorithm + /// \return default key length used by the algorithm, in bytes + size_t DefaultKeyLength() const + {return INFO::DEFAULT_KEYLENGTH;} + + /// \brief Provides a valid key length for the algorithm + /// \param keylength the size of the key, in bytes + /// \return the valid key length, in bytes + /// \details keylength is provided in bytes, not bits. If keylength is less than MIN_KEYLENGTH, + /// then the function returns MIN_KEYLENGTH. If keylength is greater than MAX_KEYLENGTH, + /// then the function returns MAX_KEYLENGTH. if If keylength is a multiple of KEYLENGTH_MULTIPLE, + /// then keylength is returned. Otherwise, the function returns a \a lower multiple of + /// KEYLENGTH_MULTIPLE. + size_t GetValidKeyLength(size_t keylength) const {return INFO::StaticGetValidKeyLength(keylength);} + + /// \brief The default IV requirements for the algorithm + /// \details The default value is NOT_RESYNCHRONIZABLE. See IV_Requirement + /// in cryptlib.h for allowed values. + SimpleKeyingInterface::IV_Requirement IVRequirement() const + {return static_cast(INFO::IV_REQUIREMENT);} + + /// \brief The initialization vector length for the algorithm + /// \details IVSize is provided in bytes, not bits. The default implementation uses + /// IV_LENGTH, which is 0. + unsigned int IVSize() const + {return INFO::IV_LENGTH;} +}; + +/// \brief Provides a base implementation of Algorithm and SimpleKeyingInterface for block ciphers +/// \tparam INFO a SimpleKeyingInterface derived class +/// \tparam BASE a SimpleKeyingInterface derived class +/// \details BlockCipherImpl() provides a default implementation for block ciphers using AlgorithmImpl() +/// and SimpleKeyingInterfaceImpl(). Functions are virtual and not eligible for C++11 constexpr-ness. +/// \sa Algorithm(), SimpleKeyingInterface(), AlgorithmImpl(), SimpleKeyingInterfaceImpl() +template +class CRYPTOPP_NO_VTABLE BlockCipherImpl : public AlgorithmImpl > > +{ +public: + /// Provides the block size of the algorithm + /// \return the block size of the algorithm, in bytes + unsigned int BlockSize() const {return this->BLOCKSIZE;} +}; + +/// \brief Provides class member functions to key a block cipher +/// \tparam DIR a CipherDir +/// \tparam BASE a BlockCipherImpl derived class +template +class BlockCipherFinal : public ClonableImpl, BASE> +{ +public: + /// \brief Construct a default BlockCipherFinal + /// \details The cipher is not keyed. + BlockCipherFinal() {} + + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the cipher + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + BlockCipherFinal(const byte *key) + {this->SetKey(key, this->DEFAULT_KEYLENGTH);} + + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the cipher + /// \param length the length of the byte array + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + BlockCipherFinal(const byte *key, size_t length) + {this->SetKey(key, length);} + + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the cipher + /// \param length the length of the byte array + /// \param rounds the number of rounds + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKeyWithRounds. + BlockCipherFinal(const byte *key, size_t length, unsigned int rounds) + {this->SetKeyWithRounds(key, length, rounds);} + + /// \brief Provides the direction of the cipher + /// \return true if DIR is ENCRYPTION, false otherwise + /// \sa GetCipherDirection(), IsPermutation() + bool IsForwardTransformation() const {return DIR == ENCRYPTION;} +}; + +/// \brief Provides a base implementation of Algorithm and SimpleKeyingInterface for message authentication codes +/// \tparam INFO a SimpleKeyingInterface derived class +/// \tparam BASE a SimpleKeyingInterface derived class +/// \details MessageAuthenticationCodeImpl() provides a default implementation for message authentication codes +/// using AlgorithmImpl() and SimpleKeyingInterfaceImpl(). Functions are virtual and not subject to C++11 +/// constexpr. +/// \sa Algorithm(), SimpleKeyingInterface(), AlgorithmImpl(), SimpleKeyingInterfaceImpl() +template +class MessageAuthenticationCodeImpl : public AlgorithmImpl, INFO> +{ +}; + +/// \brief Provides class member functions to key a message authentication code +/// \tparam BASE a BlockCipherImpl derived class +/// \details A default implementation for MessageAuthenticationCode +template +class MessageAuthenticationCodeFinal : public ClonableImpl, MessageAuthenticationCodeImpl > +{ +public: + /// \brief Construct a default MessageAuthenticationCodeFinal + /// \details The message authentication code is not keyed. + MessageAuthenticationCodeFinal() {} + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the algorithm + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + MessageAuthenticationCodeFinal(const byte *key) + {this->SetKey(key, this->DEFAULT_KEYLENGTH);} + /// \brief Construct a BlockCipherFinal + /// \param key a byte array used to key the algorithm + /// \param length the length of the byte array + /// \details key must be at least DEFAULT_KEYLENGTH in length. Internally, the function calls + /// SimpleKeyingInterface::SetKey. + MessageAuthenticationCodeFinal(const byte *key, size_t length) + {this->SetKey(key, length);} +}; + +// ************** documentation *************** + +/// \brief Provides Encryption and Decryption typedefs used by derived classes to +/// implement a block cipher +/// \details These objects usually should not be used directly. See CipherModeDocumentation +/// instead. Each class derived from this one defines two types, Encryption and Decryption, +/// both of which implement the BlockCipher interface. +struct BlockCipherDocumentation +{ + /// implements the BlockCipher interface + typedef BlockCipher Encryption; + /// implements the BlockCipher interface + typedef BlockCipher Decryption; +}; + +/// \brief Provides Encryption and Decryption typedefs used by derived classes to +/// implement a symmetric cipher +/// \details Each class derived from this one defines two types, Encryption and Decryption, +/// both of which implement the SymmetricCipher interface. Two types of classes derive +/// from this class: stream ciphers and block cipher modes. Stream ciphers can be used +/// alone, cipher mode classes need to be used with a block cipher. See CipherModeDocumentation +/// for more for information about using cipher modes and block ciphers. +struct SymmetricCipherDocumentation +{ + /// implements the SymmetricCipher interface + typedef SymmetricCipher Encryption; + /// implements the SymmetricCipher interface + typedef SymmetricCipher Decryption; +}; + +/// \brief Provides Encryption and Decryption typedefs used by derived classes to +/// implement an authenticated encryption cipher +/// \details Each class derived from this one defines two types, Encryption and Decryption, +/// both of which implement the AuthenticatedSymmetricCipher interface. +struct AuthenticatedSymmetricCipherDocumentation +{ + /// implements the AuthenticatedSymmetricCipher interface + typedef AuthenticatedSymmetricCipher Encryption; + /// implements the AuthenticatedSymmetricCipher interface + typedef AuthenticatedSymmetricCipher Decryption; +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +// Issue 340 +#if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/seed.h b/third_party/cryptoppwin/include/cryptopp/seed.h new file mode 100644 index 00000000..63ee028b --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/seed.h @@ -0,0 +1,44 @@ +// seed.h - originally written and placed in the public domain by Wei Dai + +/// \file seed.h +/// \brief Classes for the SEED block cipher +/// \since Crypto++ 5.6.0 + +#ifndef CRYPTOPP_SEED_H +#define CRYPTOPP_SEED_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SEED block cipher information +/// \since Crypto++ 5.6.0 +struct SEED_Info : public FixedBlockSize<16>, public FixedKeyLength<16>, public FixedRounds<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SEED";} +}; + +/// \brief SEED block cipher +/// \sa SEED +/// \since Crypto++ 5.6.0 +class SEED : public SEED_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + protected: + FixedSizeSecBlock m_k; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/serpent.h b/third_party/cryptoppwin/include/cryptopp/serpent.h new file mode 100644 index 00000000..3fa3379a --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/serpent.h @@ -0,0 +1,72 @@ +// serpent.h - originally written and placed in the public domain by Wei Dai + +/// \file serpent.h +/// \brief Classes for the Serpent block cipher +/// \sa A +/// Candidate Block Cipher for the Advanced Encryption Standard + +#ifndef CRYPTOPP_SERPENT_H +#define CRYPTOPP_SERPENT_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Serpent block cipher information +/// \since Crypto++ 3.1 +struct Serpent_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8>, public FixedRounds<32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Serpent";} +}; + +/// \brief Serpent block cipher +/// \sa Serpent on the +/// Crypto++ wiki, A +/// Candidate Block Cipher for the Advanced Encryption Standard +/// \since Crypto++ 3.1 +class Serpent : public Serpent_Info, public BlockCipherDocumentation +{ + /// \brief Serpen block cipher base implementation + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 3.1 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeSecBlock m_key; + }; + + /// \brief Serpent encryption transformation + /// \details Enc provides the encryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 3.1 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Serpent decryption transformation + /// \details Dec provides the decryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 3.1 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Serpent::Encryption SerpentEncryption; +typedef Serpent::Decryption SerpentDecryption; + +NAMESPACE_END + +#endif // CRYPTOPP_SERPENT_H diff --git a/third_party/cryptoppwin/include/cryptopp/serpentp.h b/third_party/cryptoppwin/include/cryptopp/serpentp.h new file mode 100644 index 00000000..124b08c5 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/serpentp.h @@ -0,0 +1,439 @@ +// private header for Serpent and Sosemanuk + +#ifndef CRYPTOPP_SERPENTP_H +#define CRYPTOPP_SERPENTP_H + +NAMESPACE_BEGIN(CryptoPP) + +// linear transformation +#define LT(i,a,b,c,d,e) {\ + a = rotlConstant<13>(a); \ + c = rotlConstant<3>(c); \ + d = rotlConstant<7>(d ^ c ^ (a << 3)); \ + b = rotlConstant<1>(b ^ a ^ c); \ + a = rotlConstant<5>(a ^ b ^ d); \ + c = rotlConstant<22>(c ^ d ^ (b << 7));} + +// inverse linear transformation +#define ILT(i,a,b,c,d,e) {\ + c = rotrConstant<22>(c); \ + a = rotrConstant<5>(a); \ + c ^= d ^ (b << 7); \ + a ^= b ^ d; \ + b = rotrConstant<1>(b); \ + d = rotrConstant<7>(d) ^ c ^ (a << 3); \ + b ^= a ^ c; \ + c = rotrConstant<3>(c); \ + a = rotrConstant<13>(a);} + +// order of output from S-box functions +#define beforeS0(f) f(0,a,b,c,d,e) +#define afterS0(f) f(1,b,e,c,a,d) +#define afterS1(f) f(2,c,b,a,e,d) +#define afterS2(f) f(3,a,e,b,d,c) +#define afterS3(f) f(4,e,b,d,c,a) +#define afterS4(f) f(5,b,a,e,c,d) +#define afterS5(f) f(6,a,c,b,e,d) +#define afterS6(f) f(7,a,c,d,b,e) +#define afterS7(f) f(8,d,e,b,a,c) + +// order of output from inverse S-box functions +#define beforeI7(f) f(8,a,b,c,d,e) +#define afterI7(f) f(7,d,a,b,e,c) +#define afterI6(f) f(6,a,b,c,e,d) +#define afterI5(f) f(5,b,d,e,c,a) +#define afterI4(f) f(4,b,c,e,a,d) +#define afterI3(f) f(3,a,b,e,c,d) +#define afterI2(f) f(2,b,d,e,c,a) +#define afterI1(f) f(1,a,b,c,e,d) +#define afterI0(f) f(0,a,d,b,e,c) + +// The instruction sequences for the S-box functions +// come from Dag Arne Osvik's paper "Speeding up Serpent". + +#define S0(i, r0, r1, r2, r3, r4) \ + { \ + r3 ^= r0; \ + r4 = r1; \ + r1 &= r3; \ + r4 ^= r2; \ + r1 ^= r0; \ + r0 |= r3; \ + r0 ^= r4; \ + r4 ^= r3; \ + r3 ^= r2; \ + r2 |= r1; \ + r2 ^= r4; \ + r4 = ~r4; \ + r4 |= r1; \ + r1 ^= r3; \ + r1 ^= r4; \ + r3 |= r0; \ + r1 ^= r3; \ + r4 ^= r3; \ + } + +#define I0(i, r0, r1, r2, r3, r4) \ + { \ + r2 = ~r2; \ + r4 = r1; \ + r1 |= r0; \ + r4 = ~r4; \ + r1 ^= r2; \ + r2 |= r4; \ + r1 ^= r3; \ + r0 ^= r4; \ + r2 ^= r0; \ + r0 &= r3; \ + r4 ^= r0; \ + r0 |= r1; \ + r0 ^= r2; \ + r3 ^= r4; \ + r2 ^= r1; \ + r3 ^= r0; \ + r3 ^= r1; \ + r2 &= r3; \ + r4 ^= r2; \ + } + +#define S1(i, r0, r1, r2, r3, r4) \ + { \ + r0 = ~r0; \ + r2 = ~r2; \ + r4 = r0; \ + r0 &= r1; \ + r2 ^= r0; \ + r0 |= r3; \ + r3 ^= r2; \ + r1 ^= r0; \ + r0 ^= r4; \ + r4 |= r1; \ + r1 ^= r3; \ + r2 |= r0; \ + r2 &= r4; \ + r0 ^= r1; \ + r1 &= r2; \ + r1 ^= r0; \ + r0 &= r2; \ + r0 ^= r4; \ + } + +#define I1(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r1; \ + r1 ^= r3; \ + r3 &= r1; \ + r4 ^= r2; \ + r3 ^= r0; \ + r0 |= r1; \ + r2 ^= r3; \ + r0 ^= r4; \ + r0 |= r2; \ + r1 ^= r3; \ + r0 ^= r1; \ + r1 |= r3; \ + r1 ^= r0; \ + r4 = ~r4; \ + r4 ^= r1; \ + r1 |= r0; \ + r1 ^= r0; \ + r1 |= r4; \ + r3 ^= r1; \ + } + +#define S2(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r0; \ + r0 &= r2; \ + r0 ^= r3; \ + r2 ^= r1; \ + r2 ^= r0; \ + r3 |= r4; \ + r3 ^= r1; \ + r4 ^= r2; \ + r1 = r3; \ + r3 |= r4; \ + r3 ^= r0; \ + r0 &= r1; \ + r4 ^= r0; \ + r1 ^= r3; \ + r1 ^= r4; \ + r4 = ~r4; \ + } + +#define I2(i, r0, r1, r2, r3, r4) \ + { \ + r2 ^= r3; \ + r3 ^= r0; \ + r4 = r3; \ + r3 &= r2; \ + r3 ^= r1; \ + r1 |= r2; \ + r1 ^= r4; \ + r4 &= r3; \ + r2 ^= r3; \ + r4 &= r0; \ + r4 ^= r2; \ + r2 &= r1; \ + r2 |= r0; \ + r3 = ~r3; \ + r2 ^= r3; \ + r0 ^= r3; \ + r0 &= r1; \ + r3 ^= r4; \ + r3 ^= r0; \ + } + +#define S3(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r0; \ + r0 |= r3; \ + r3 ^= r1; \ + r1 &= r4; \ + r4 ^= r2; \ + r2 ^= r3; \ + r3 &= r0; \ + r4 |= r1; \ + r3 ^= r4; \ + r0 ^= r1; \ + r4 &= r0; \ + r1 ^= r3; \ + r4 ^= r2; \ + r1 |= r0; \ + r1 ^= r2; \ + r0 ^= r3; \ + r2 = r1; \ + r1 |= r3; \ + r1 ^= r0; \ + } + +#define I3(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 ^= r1; \ + r1 &= r2; \ + r1 ^= r0; \ + r0 &= r4; \ + r4 ^= r3; \ + r3 |= r1; \ + r3 ^= r2; \ + r0 ^= r4; \ + r2 ^= r0; \ + r0 |= r3; \ + r0 ^= r1; \ + r4 ^= r2; \ + r2 &= r3; \ + r1 |= r3; \ + r1 ^= r2; \ + r4 ^= r0; \ + r2 ^= r4; \ + } + +#define S4(i, r0, r1, r2, r3, r4) \ + { \ + r1 ^= r3; \ + r3 = ~r3; \ + r2 ^= r3; \ + r3 ^= r0; \ + r4 = r1; \ + r1 &= r3; \ + r1 ^= r2; \ + r4 ^= r3; \ + r0 ^= r4; \ + r2 &= r4; \ + r2 ^= r0; \ + r0 &= r1; \ + r3 ^= r0; \ + r4 |= r1; \ + r4 ^= r0; \ + r0 |= r3; \ + r0 ^= r2; \ + r2 &= r3; \ + r0 = ~r0; \ + r4 ^= r2; \ + } + +#define I4(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 &= r3; \ + r2 ^= r1; \ + r1 |= r3; \ + r1 &= r0; \ + r4 ^= r2; \ + r4 ^= r1; \ + r1 &= r2; \ + r0 = ~r0; \ + r3 ^= r4; \ + r1 ^= r3; \ + r3 &= r0; \ + r3 ^= r2; \ + r0 ^= r1; \ + r2 &= r0; \ + r3 ^= r0; \ + r2 ^= r4; \ + r2 |= r3; \ + r3 ^= r0; \ + r2 ^= r1; \ + } + +#define S5(i, r0, r1, r2, r3, r4) \ + { \ + r0 ^= r1; \ + r1 ^= r3; \ + r3 = ~r3; \ + r4 = r1; \ + r1 &= r0; \ + r2 ^= r3; \ + r1 ^= r2; \ + r2 |= r4; \ + r4 ^= r3; \ + r3 &= r1; \ + r3 ^= r0; \ + r4 ^= r1; \ + r4 ^= r2; \ + r2 ^= r0; \ + r0 &= r3; \ + r2 = ~r2; \ + r0 ^= r4; \ + r4 |= r3; \ + r2 ^= r4; \ + } + +#define I5(i, r0, r1, r2, r3, r4) \ + { \ + r1 = ~r1; \ + r4 = r3; \ + r2 ^= r1; \ + r3 |= r0; \ + r3 ^= r2; \ + r2 |= r1; \ + r2 &= r0; \ + r4 ^= r3; \ + r2 ^= r4; \ + r4 |= r0; \ + r4 ^= r1; \ + r1 &= r2; \ + r1 ^= r3; \ + r4 ^= r2; \ + r3 &= r4; \ + r4 ^= r1; \ + r3 ^= r0; \ + r3 ^= r4; \ + r4 = ~r4; \ + } + +#define S6(i, r0, r1, r2, r3, r4) \ + { \ + r2 = ~r2; \ + r4 = r3; \ + r3 &= r0; \ + r0 ^= r4; \ + r3 ^= r2; \ + r2 |= r4; \ + r1 ^= r3; \ + r2 ^= r0; \ + r0 |= r1; \ + r2 ^= r1; \ + r4 ^= r0; \ + r0 |= r3; \ + r0 ^= r2; \ + r4 ^= r3; \ + r4 ^= r0; \ + r3 = ~r3; \ + r2 &= r4; \ + r2 ^= r3; \ + } + +#define I6(i, r0, r1, r2, r3, r4) \ + { \ + r0 ^= r2; \ + r4 = r2; \ + r2 &= r0; \ + r4 ^= r3; \ + r2 = ~r2; \ + r3 ^= r1; \ + r2 ^= r3; \ + r4 |= r0; \ + r0 ^= r2; \ + r3 ^= r4; \ + r4 ^= r1; \ + r1 &= r3; \ + r1 ^= r0; \ + r0 ^= r3; \ + r0 |= r2; \ + r3 ^= r1; \ + r4 ^= r0; \ + } + +#define S7(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 &= r1; \ + r2 ^= r3; \ + r3 &= r1; \ + r4 ^= r2; \ + r2 ^= r1; \ + r1 ^= r0; \ + r0 |= r4; \ + r0 ^= r2; \ + r3 ^= r1; \ + r2 ^= r3; \ + r3 &= r0; \ + r3 ^= r4; \ + r4 ^= r2; \ + r2 &= r0; \ + r4 = ~r4; \ + r2 ^= r4; \ + r4 &= r0; \ + r1 ^= r3; \ + r4 ^= r1; \ + } + +#define I7(i, r0, r1, r2, r3, r4) \ + { \ + r4 = r2; \ + r2 ^= r0; \ + r0 &= r3; \ + r2 = ~r2; \ + r4 |= r3; \ + r3 ^= r1; \ + r1 |= r0; \ + r0 ^= r2; \ + r2 &= r4; \ + r1 ^= r2; \ + r2 ^= r0; \ + r0 |= r2; \ + r3 &= r4; \ + r0 ^= r3; \ + r4 ^= r1; \ + r3 ^= r4; \ + r4 |= r0; \ + r3 ^= r2; \ + r4 ^= r2; \ + } + +// key xor +#define KX(r, a, b, c, d, e) {\ + a ^= k[4 * r + 0]; \ + b ^= k[4 * r + 1]; \ + c ^= k[4 * r + 2]; \ + d ^= k[4 * r + 3];} + +#define LK(r, a, b, c, d, e) {\ + a = k[(8-r)*4 + 0]; \ + b = k[(8-r)*4 + 1]; \ + c = k[(8-r)*4 + 2]; \ + d = k[(8-r)*4 + 3];} + +#define SK(r, a, b, c, d, e) {\ + k[(8-r)*4 + 4] = a; \ + k[(8-r)*4 + 5] = b; \ + k[(8-r)*4 + 6] = c; \ + k[(8-r)*4 + 7] = d;} + +void Serpent_KeySchedule(word32 *k, unsigned int rounds, const byte *userKey, size_t keylen); + +NAMESPACE_END + +#endif // CRYPTOPP_SERPENTP_H diff --git a/third_party/cryptoppwin/include/cryptopp/sha.h b/third_party/cryptoppwin/include/cryptopp/sha.h new file mode 100644 index 00000000..d4a09d7d --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/sha.h @@ -0,0 +1,210 @@ +// sha.h - originally written and placed in the public domain by Wei Dai + +/// \file sha.h +/// \brief Classes for SHA-1 and SHA-2 family of message digests +/// \since SHA1 since Crypto++ 1.0, SHA2 since Crypto++ 4.0, ARMv8 SHA since +/// Crypto++ 6.0, Intel SHA since Crypto++ 6.0, Power8 SHA since Crypto++ 6.1 + +#ifndef CRYPTOPP_SHA_H +#define CRYPTOPP_SHA_H + +#include "config.h" +#include "iterhash.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_SHA_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHA-1 message digest +/// \sa SHA-1 +/// \since SHA1 since Crypto++ 1.0, SHA2 since Crypto++ 4.0, ARMv8 SHA since +/// Crypto++ 6.0, Intel SHA since Crypto++ 6.0 +class CRYPTOPP_DLL SHA1 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA1 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data); + /// \brief The algorithm name + /// \return C-style string "SHA-1" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-1";} + // Algorithm class + std::string AlgorithmProvider() const; + +protected: + size_t HashMultipleBlocks(const HashWordType *input, size_t length); +}; + +/// \brief SHA-256 message digest +/// \sa SHA-256 +/// \since SHA2 since Crypto++ 4.0, ARMv8 SHA since Crypto++ 6.0, +/// Intel SHA since Crypto++ 6.0, Power8 SHA since Crypto++ 6.1 +class CRYPTOPP_DLL SHA256 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA256 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data); + /// \brief The algorithm name + /// \return C-style string "SHA-256" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-256";} + + // Algorithm class + std::string AlgorithmProvider() const; + +protected: + size_t HashMultipleBlocks(const HashWordType *input, size_t length); +}; + +/// \brief SHA-224 message digest +/// \sa SHA-224 +/// \since SHA2 since Crypto++ 4.0, ARMv8 SHA since Crypto++ 6.0, +/// Intel SHA since Crypto++ 6.0, Power8 SHA since Crypto++ 6.1 +class CRYPTOPP_DLL SHA224 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA224 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data) {SHA256::Transform(digest, data);} + /// \brief The algorithm name + /// \return C-style string "SHA-224" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-224";} + + // Algorithm class + std::string AlgorithmProvider() const; + +protected: + size_t HashMultipleBlocks(const HashWordType *input, size_t length); +}; + +/// \brief SHA-512 message digest +/// \sa SHA-512 +/// \since SHA2 since Crypto++ 4.0, Power8 SHA since Crypto++ 6.1 +class CRYPTOPP_DLL SHA512 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA512 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data); + /// \brief The algorithm name + /// \return C-style string "SHA-512" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-512";} + + // Algorithm class + std::string AlgorithmProvider() const; +}; + +/// \brief SHA-384 message digest +/// \sa SHA-384 +/// \since SHA2 since Crypto++ 4.0, Power8 SHA since Crypto++ 6.1 +class CRYPTOPP_DLL SHA384 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SHA384 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array must be 16-byte aligned for SSE2. + static void CRYPTOPP_API InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform operates the hash on data. When the call is invoked + /// digest holds initial state. Upon return digest holds the hash + /// or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState and Transform. External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + /// \note On Intel platforms the state array and data must be 16-byte aligned for SSE2. + static void CRYPTOPP_API Transform(HashWordType *digest, const HashWordType *data) {SHA512::Transform(digest, data);} + /// \brief The algorithm name + /// \return C-style string "SHA-384" + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "SHA-384";} + + // Algorithm class + std::string AlgorithmProvider() const; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/sha1_armv4.h b/third_party/cryptoppwin/include/cryptopp/sha1_armv4.h new file mode 100644 index 00000000..97f36717 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/sha1_armv4.h @@ -0,0 +1,23 @@ +/* Header file for use with Cryptogam's ARMv4 SHA1. */ +/* Also see http://www.openssl.org/~appro/cryptogams/ */ +/* https://wiki.openssl.org/index.php/Cryptogams_SHA. */ + +#ifndef CRYPTOGAMS_SHA1_ARMV4_H +#define CRYPTOGAMS_SHA1_ARMV4_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Crypto++ modified sha1_block_data_order to pass caps as a parameter. */ +/* Also see https://github.com/weidai11/cryptopp/issues/846. */ +void cryptogams_sha1_block_data_order(void *state, const void *data, size_t blocks); + +/* Cryptogams arm caps */ +#define CRYPTOGAMS_ARMV7_NEON (1<<0) + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTOGAMS_SHA1_ARMV4_H */ diff --git a/third_party/cryptoppwin/include/cryptopp/sha256_armv4.h b/third_party/cryptoppwin/include/cryptopp/sha256_armv4.h new file mode 100644 index 00000000..5a4b88e2 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/sha256_armv4.h @@ -0,0 +1,23 @@ +/* Header file for use with Cryptogam's ARMv4 SHA1. */ +/* Also see http://www.openssl.org/~appro/cryptogams/ */ +/* https://wiki.openssl.org/index.php/Cryptogams_SHA. */ + +#ifndef CRYPTOGAMS_SHA256_ARMV4_H +#define CRYPTOGAMS_SHA256_ARMV4_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Crypto++ modified cryptogams_sha256_block_data_order to pass caps as a parameter. */ +/* Also see https://github.com/weidai11/cryptopp/issues/846. */ +void cryptogams_sha256_block_data_order(void *state, const void *data, size_t blocks); + +/* Cryptogams arm caps */ +#define CRYPTOGAMS_ARMV7_NEON (1<<0) + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTOGAMS_SHA256_ARMV4_H */ diff --git a/third_party/cryptoppwin/include/cryptopp/sha3.h b/third_party/cryptoppwin/include/cryptopp/sha3.h new file mode 100644 index 00000000..97fce4b6 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/sha3.h @@ -0,0 +1,106 @@ +// sha3.h - originally written and placed in the public domain by Wei Dai + +/// \file sha3.h +/// \brief Classes for SHA3 message digests +/// \details The Crypto++ implementation conforms to the FIPS 202 version of SHA3 using F1600 with XOF d=0x06. +/// Previous behavior (XOF d=0x01) is available in Keccak classes. +/// \sa SHA-3, +/// SHA-3 STANDARD (FIPS 202). +/// \since Crypto++ 5.6.2 + +#ifndef CRYPTOPP_SHA3_H +#define CRYPTOPP_SHA3_H + +#include "cryptlib.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHA3 message digest base class +/// \details The Crypto++ implementation conforms to FIPS 202 version of SHA3 using F1600 with XOF d=0x06. +/// Previous behavior (XOF d=0x01) is available in Keccak classes. +/// \details SHA3 is the base class for SHA3_224, SHA3_256, SHA3_384 and SHA3_512. +/// Library users should instantiate a derived class, and only use SHA3 +/// as a base class reference or pointer. +/// \sa Keccak, SHA3_224, SHA3_256, SHA3_384 and SHA3_512. +/// \since Crypto++ 5.6.2 +class SHA3 : public HashTransformation +{ +protected: + /// \brief Construct a SHA3 + /// \param digestSize the digest size, in bytes + /// \details SHA3 is the base class for SHA3_224, SHA3_256, SHA3_384 and SHA3_512. + /// Library users should instantiate a derived class, and only use SHA3 + /// as a base class reference or pointer. + /// \details This constructor was moved to protected at Crypto++ 8.1 + /// because users were attempting to create Keccak objects with it. + /// \since Crypto++ 5.6.2 + SHA3(unsigned int digestSize) : m_digestSize(digestSize) {Restart();} + +public: + unsigned int DigestSize() const {return m_digestSize;} + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + void Update(const byte *input, size_t length); + void Restart(); + void TruncatedFinal(byte *hash, size_t size); + +protected: + inline unsigned int r() const {return BlockSize();} + + FixedSizeSecBlock m_state; + unsigned int m_digestSize, m_counter; +}; + +/// \brief SHA3 message digest template +/// \tparam T_DigestSize the size of the digest, in bytes +/// \since Crypto++ 5.6.2 +template +class SHA3_Final : public SHA3 +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = T_DigestSize); + CRYPTOPP_CONSTANT(BLOCKSIZE = 200 - 2 * DIGESTSIZE); + static std::string StaticAlgorithmName() + { return "SHA3-" + IntToString(DIGESTSIZE * 8); } + + /// \brief Construct a SHA3-X message digest + SHA3_Final() : SHA3(DIGESTSIZE) {} + + /// \brief Provides the block size of the compression function + /// \return block size of the compression function, in bytes + /// \details BlockSize() will return 0 if the hash is not block based + /// or does not have an equivalent block size. For example, Keccak + /// and SHA-3 do not have a block size, but they do have an equivalent + /// block size called rate expressed as r. + unsigned int BlockSize() const { return BLOCKSIZE; } + + std::string AlgorithmName() const { return StaticAlgorithmName(); } + +private: +#if !defined(__BORLANDC__) + // ensure there was no underflow in the math + CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE < 200); +#endif +}; + +/// \brief SHA3-224 message digest +/// \since Crypto++ 5.6.2 +class SHA3_224 : public SHA3_Final<28> {}; + +/// \brief SHA3-256 message digest +/// \since Crypto++ 5.6.2 +class SHA3_256 : public SHA3_Final<32> {}; + +/// \brief SHA3-384 message digest +/// \since Crypto++ 5.6.2 +class SHA3_384 : public SHA3_Final<48> {}; + +/// \brief SHA3-512 message digest +/// \since Crypto++ 5.6.2 +class SHA3_512 : public SHA3_Final<64> {}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/sha512_armv4.h b/third_party/cryptoppwin/include/cryptopp/sha512_armv4.h new file mode 100644 index 00000000..cead986b --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/sha512_armv4.h @@ -0,0 +1,23 @@ +/* Header file for use with Cryptogam's ARMv4 SHA512. */ +/* Also see http://www.openssl.org/~appro/cryptogams/ */ +/* https://wiki.openssl.org/index.php/Cryptogams_SHA. */ + +#ifndef CRYPTOGAMS_SHA512_ARMV4_H +#define CRYPTOGAMS_SHA512_ARMV4_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Crypto++ modified cryptogams_sha512_block_data_order to pass caps as a parameter. */ +/* Also see https://github.com/weidai11/cryptopp/issues/846. */ +void cryptogams_sha512_block_data_order(void *state, const void *data, size_t blocks); + +/* Cryptogams arm caps */ +#define CRYPTOGAMS_ARMV7_NEON (1<<0) + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTOGAMS_SHA512_ARMV4_H */ diff --git a/third_party/cryptoppwin/include/cryptopp/shacal2.h b/third_party/cryptoppwin/include/cryptopp/shacal2.h new file mode 100644 index 00000000..9f729582 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/shacal2.h @@ -0,0 +1,66 @@ +// shacal.h - originally written and placed in the public domain by Wei Dai + +/// \file shacal2.h +/// \brief Classes for the SHACAL-2 block cipher +/// \since Crypto++ 5.2, Intel SHA since Crypto++ 6.0 + +#ifndef CRYPTOPP_SHACAL2_H +#define CRYPTOPP_SHACAL2_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHACAL2 block cipher information +struct SHACAL2_Info : public FixedBlockSize<32>, public VariableKeyLength<16, 16, 64> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SHACAL-2";} +}; + +/// \brief SHACAL2 block cipher +/// \since Crypto++ 5.2, Intel SHA since Crypto++ 6.0 +/// \sa SHACAL-2 +class SHACAL2 : public SHACAL2_Info, public BlockCipherDocumentation +{ + /// \brief SHACAL2 block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + std::string AlgorithmProvider() const; + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeAlignedSecBlock m_key; + + static const word32 K[64]; + }; + + /// \brief SHACAL2 block cipher transformation functions + /// \details Encryption transformation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief SHACAL2 block cipher transformation functions + /// \details Decryption transformation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SHACAL2::Encryption SHACAL2Encryption; +typedef SHACAL2::Decryption SHACAL2Decryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/shake.h b/third_party/cryptoppwin/include/cryptopp/shake.h new file mode 100644 index 00000000..4d52132d --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/shake.h @@ -0,0 +1,161 @@ +// shake.h - written and placed in the public domain by Jeffrey Walton + +/// \file shake.h +/// \brief Classes for SHAKE message digests +/// \details The library provides byte oriented SHAKE128 and SHAKE256 using F1600. +/// FIPS 202 allows nearly unlimited output sizes, but Crypto++ limits the output +/// size to UINT_MAX due underlying data types. +/// \sa Keccak, SHA3, SHAKE128, SHAKE256, +/// FIPS 202, +/// SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions +/// \since Crypto++ 8.1 + +#ifndef CRYPTOPP_SHAKE_H +#define CRYPTOPP_SHAKE_H + +#include "cryptlib.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHAKE message digest base class +/// \details SHAKE is the base class for SHAKE128 and SHAKE258. +/// Library users should instantiate a derived class, and only use SHAKE +/// as a base class reference or pointer. +/// \sa Keccak, SHA3, SHAKE128, SHAKE256, +/// FIPS 202, +/// SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions +/// \since Crypto++ 8.1 +class SHAKE : public HashTransformation +{ +protected: + /// \brief Construct a SHAKE + /// \param digestSize the digest size, in bytes + /// \details SHAKE is the base class for SHAKE128 and SHAKE256. + /// Library users should instantiate a derived class, and only use SHAKE + /// as a base class reference or pointer. + /// \details This constructor was moved to protected at Crypto++ 8.1 + /// because users were attempting to create Keccak objects with it. + /// \since Crypto++ 8.1 + SHAKE(unsigned int digestSize) : m_digestSize(digestSize) {Restart();} + +public: + unsigned int DigestSize() const {return m_digestSize;} + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + void Update(const byte *input, size_t length); + void Restart(); + void TruncatedFinal(byte *hash, size_t size); + +protected: + inline unsigned int r() const {return BlockSize();} + + // SHAKE-128 and SHAKE-256 effectively allow unlimited + // output length. However, we use an unsigned int so + // we are limited in practice to UINT_MAX. + void ThrowIfInvalidTruncatedSize(size_t size) const; + + FixedSizeSecBlock m_state; + unsigned int m_digestSize, m_counter; +}; + +/// \brief SHAKE message digest template +/// \tparam T_Strength the strength of the digest +/// \since Crypto++ 8.1 +template +class SHAKE_Final : public SHAKE +{ +public: + CRYPTOPP_CONSTANT(DIGESTSIZE = (T_Strength == 128 ? 32 : 64)); + CRYPTOPP_CONSTANT(BLOCKSIZE = (T_Strength == 128 ? 1344/8 : 1088/8)); + static std::string StaticAlgorithmName() + { return "SHAKE-" + IntToString(T_Strength); } + + /// \brief Construct a SHAKE-X message digest + /// \details SHAKE128 and SHAKE256 don't need the output size in advance + /// because the output size does not affect the digest. TruncatedFinal + /// produces the correct digest for any output size. However, cSHAKE + /// requires the output size in advance because the algorithm uses + /// output size as a parameter to the hash function. + SHAKE_Final(unsigned int outputSize=DIGESTSIZE) : SHAKE(outputSize) {} + + /// \brief Provides the block size of the compression function + /// \return block size of the compression function, in bytes + /// \details BlockSize() will return 0 if the hash is not block based + /// or does not have an equivalent block size. For example, Keccak + /// and SHA-3 do not have a block size, but they do have an equivalent + /// to block size called rate expressed as r. + unsigned int BlockSize() const { return BLOCKSIZE; } + + std::string AlgorithmName() const { return StaticAlgorithmName(); } + +private: +#if !defined(__BORLANDC__) + // ensure there was no underflow in the math + CRYPTOPP_COMPILE_ASSERT(BLOCKSIZE < 200); +#endif +}; + +/// \brief SHAKE128 message digest +/// \details The library provides byte oriented SHAKE128 using F1600. +/// FIPS 202 allows nearly unlimited output sizes, but Crypto++ limits +/// the output size to UINT_MAX due underlying data types. +/// \sa Keccak, SHA3, SHAKE256, +/// FIPS 202, +/// SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions +/// \since Crypto++ 8.1 +class SHAKE128 : public SHAKE_Final<128> +{ +public: + /// \brief Construct a SHAKE128 message digest + /// \details SHAKE128 and SHAKE256 don't need the output size in advance + /// because the output size does not affect the digest. TruncatedFinal + /// produces the correct digest for any output size. However, cSHAKE + /// requires the output size in advance because the algorithm uses + /// output size as a parameter to the hash function. + /// \since Crypto++ 8.1 + SHAKE128() {} + + /// \brief Construct a SHAKE128 message digest + /// \details SHAKE128 and SHAKE256 don't need the output size in advance + /// because the output size does not affect the digest. TruncatedFinal + /// produces the correct digest for any output size. However, cSHAKE + /// requires the output size in advance because the algorithm uses + /// output size as a parameter to the hash function. + /// \since Crypto++ 8.1 + SHAKE128(unsigned int outputSize) : SHAKE_Final<128>(outputSize) {} +}; + +/// \brief SHAKE256 message digest +/// \details The library provides byte oriented SHAKE256 using F1600. +/// FIPS 202 allows nearly unlimited output sizes, but Crypto++ limits +/// the output size to UINT_MAX due underlying data types. +/// \sa Keccak, SHA3, SHAKE128, +/// FIPS 202, +/// SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions +/// \since Crypto++ 8.1 +class SHAKE256 : public SHAKE_Final<256> +{ +public: + /// \brief Construct a SHAKE256 message digest + /// \details SHAKE128 and SHAKE256 don't need the output size in advance + /// because the output size does not affect the digest. TruncatedFinal + /// produces the correct digest for any output size. However, cSHAKE + /// requires the output size in advance because the algorithm uses + /// output size as a parameter to the hash function. + /// \since Crypto++ 8.1 + SHAKE256() {} + + /// \brief Construct a SHAKE256 message digest + /// \details SHAKE128 and SHAKE256 don't need the output size in advance + /// because the output size does not affect the digest. TruncatedFinal + /// produces the correct digest for any output size. However, cSHAKE + /// requires the output size in advance because the algorithm uses + /// output size as a parameter to the hash function. + /// \since Crypto++ 8.1 + SHAKE256(unsigned int outputSize) : SHAKE_Final<256>(outputSize) {} +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/shark.h b/third_party/cryptoppwin/include/cryptopp/shark.h new file mode 100644 index 00000000..8c73d26b --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/shark.h @@ -0,0 +1,77 @@ +// shark.h - originally written and placed in the public domain by Wei Dai + +/// \file shark.h +/// \brief Classes for the SHARK block cipher +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_SHARK_H +#define CRYPTOPP_SHARK_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SHARK block cipher information +/// \since Crypto++ 2.1 +struct SHARK_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public VariableRounds<6, 2> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SHARK-E";} +}; + +/// \brief SHARK block cipher +/// SHARK-E +/// \since Crypto++ 2.1 +class SHARK : public SHARK_Info, public BlockCipherDocumentation +{ + /// \brief SHARK block cipher default operation + /// \since Crypto++ 2.1 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶m); + + protected: + unsigned int m_rounds; + SecBlock m_roundKeys; + }; + + /// \brief SHARK block cipher encryption operation + /// \since Crypto++ 2.1 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + // used by Base to do key setup + void InitForKeySetup(); + + private: + static const byte sbox[256]; + static const word64 cbox[8][256]; + }; + + /// \brief SHARK block cipher decryption operation + /// \since Crypto++ 2.1 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + + private: + static const byte sbox[256]; + static const word64 cbox[8][256]; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SHARK::Encryption SHARKEncryption; +typedef SHARK::Decryption SHARKDecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/simeck.h b/third_party/cryptoppwin/include/cryptopp/simeck.h new file mode 100644 index 00000000..7e76f70a --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/simeck.h @@ -0,0 +1,162 @@ +// simeck.h - written and placed in the public domain by Gangqiang Yang and Jeffrey Walton. +// Based on "The Simeck Family of Lightweight Block Ciphers" by Gangqiang Yang, +// Bo Zhu, Valentin Suder, Mark D. Aagaard, and Guang Gong + +/// \file simeck.h +/// \brief Classes for the SIMECK block cipher +/// \sa SIMECK, +/// The Simeck +/// Family of Lightweight Block Ciphers +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_SIMECK_H +#define CRYPTOPP_SIMECK_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SIMECK block cipher information +/// \since Crypto++ 8.0 +struct SIMECK32_Info : public FixedBlockSize<4>, public FixedKeyLength<8>, public FixedRounds<32> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize + return "SIMECK-32"; + } +}; + +/// \brief SIMECK block cipher information +/// \since Crypto++ 8.0 +struct SIMECK64_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public FixedRounds<44> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize + return "SIMECK-64"; + } +}; + +/// \brief SIMECK 32-bit block cipher +/// \details SIMECK32 provides 32-bit block size. The valid key size is 64-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa SIMECK64, SIMECK, +/// The Simeck Family of +/// Lightweight Block Ciphers +/// \since Crypto++ 8.0 +class CRYPTOPP_NO_VTABLE SIMECK32 : public SIMECK32_Info, public BlockCipherDocumentation +{ +public: + /// \brief SIMECK block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + std::string AlgorithmProvider() const; + + FixedSizeSecBlock m_rk; + mutable FixedSizeSecBlock m_t; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SIMECK32::Encryption SIMECK32Encryption; +typedef SIMECK32::Decryption SIMECK32Decryption; + +/// \brief SIMECK 64-bit block cipher +/// \details SIMECK64 provides 64-bit block size. The valid key size is 128-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa SIMECK32, SIMECK, +/// The Simeck Family of +/// Lightweight Block Ciphers +/// \since Crypto++ 8.0 +class CRYPTOPP_NO_VTABLE SIMECK64 : public SIMECK64_Info, public BlockCipherDocumentation +{ +public: + /// \brief SIMECK block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + std::string AlgorithmProvider() const; + + FixedSizeSecBlock m_rk; + mutable FixedSizeSecBlock m_t; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_SIMECK_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + +#if CRYPTOPP_SIMECK_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SIMECK64::Encryption SIMECK64Encryption; +typedef SIMECK64::Decryption SIMECK64Decryption; + +NAMESPACE_END + +#endif // CRYPTOPP_SIMECK_H diff --git a/third_party/cryptoppwin/include/cryptopp/simon.h b/third_party/cryptoppwin/include/cryptopp/simon.h new file mode 100644 index 00000000..35bb67f3 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/simon.h @@ -0,0 +1,206 @@ +// simon.h - written and placed in the public domain by Jeffrey Walton + +/// \file simon.h +/// \brief Classes for the Simon block cipher +/// \details Simon is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \sa The SIMON and SPECK Families of +/// Lightweight Block Ciphers, +/// The Simon and Speck GitHub and +/// SIMON on the Crypto++ wiki. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SIMON_H +#define CRYPTOPP_SIMON_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || \ + CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8 || \ + CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 +# ifndef CRYPTOPP_DISABLE_SIMON_SIMD +# define CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS 1 +# endif +#endif + +// Yet another SunStudio/SunCC workaround. Failed self tests +// in SSE code paths on i386 for SunStudio 12.3 and below. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120) +# undef CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SIMON block cipher information +/// \tparam L block size of the cipher, in bytes +/// \tparam D default key length, in bytes +/// \tparam N minimum key length, in bytes +/// \tparam M maximum key length, in bytes +/// \since Crypto++ 6.0 +template +struct SIMON_Info : public FixedBlockSize, VariableKeyLength +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "SIMON-" + IntToString(L*8); + } +}; + +/// \brief SIMON block cipher base class +/// \tparam W the word type +/// \details User code should use SIMON64 or SIMON128 +/// \sa SIMON64, SIMON128, SIMON on the Crypto++ wiki +/// \since Crypto++ 6.0 +template +struct SIMON_Base +{ + virtual ~SIMON_Base() {} + SIMON_Base() : m_kwords(0), m_rounds(0) {} + + typedef SecBlock > AlignedSecBlock; + mutable AlignedSecBlock m_wspace; // workspace + AlignedSecBlock m_rkeys; // round keys + unsigned int m_kwords; // number of key words + unsigned int m_rounds; // number of rounds +}; + +/// \brief SIMON 64-bit block cipher +/// \details Simon is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \details SIMON64 provides 64-bit block size. The valid key sizes are 96-bit and 128-bit. +/// \sa SIMON64, SIMON128, The SIMON and SIMON +/// Families of Lightweight Block Ciphers, +/// The Simon and Speck GitHub, SIMON on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SIMON64 : public SIMON_Info<8, 12, 12, 16>, public BlockCipherDocumentation +{ +public: + /// \brief SIMON64 block cipher base implementation + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : protected SIMON_Base, public BlockCipherImpl > + { + public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details AlgorithmName returns the algorithm's name as a + /// member function. + std::string AlgorithmName() const { + return StaticAlgorithmName() + (m_kwords == 0 ? "" : + "(" + IntToString(m_kwords*sizeof(word32)*8) + ")"); + } + + std::string AlgorithmProvider() const; + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const; + + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief SIMON64 encryption transformation + /// \details Enc provides the encryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief SIMON64 decryption transformation + /// \details Dec provides the decryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief SIMON 128-bit block cipher +/// \details Simon is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \details SIMON128 provides 128-bit block size. The valid key sizes are 128-bit, 192-bit and 256-bit. +/// \sa SIMON64, SIMON128, The SIMON and SIMON +/// Families of Lightweight Block Ciphers, +/// The Simon and Speck GitHub, SIMON on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SIMON128 : public SIMON_Info<16, 16, 16, 32>, public BlockCipherDocumentation +{ +public: + /// \brief SIMON128 block cipher base implementation + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : protected SIMON_Base, public BlockCipherImpl > + { + public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details AlgorithmName returns the algorithm's name as a + /// member function. + std::string AlgorithmName() const { + return StaticAlgorithmName() + (m_kwords == 0 ? "" : + "(" + IntToString(m_kwords*sizeof(word64)*8) + ")"); + } + + std::string AlgorithmProvider() const; + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const; + + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief SIMON128 encryption transformation + /// \details Enc provides the encryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief SIMON128 decryption transformation + /// \details Dec provides the decryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SIMON128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SIMON_H diff --git a/third_party/cryptoppwin/include/cryptopp/simple.h b/third_party/cryptoppwin/include/cryptopp/simple.h new file mode 100644 index 00000000..885c6781 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/simple.h @@ -0,0 +1,506 @@ +// simple.h - originally written and placed in the public domain by Wei Dai + +/// \file simple.h +/// \brief Classes providing basic library services. + +#ifndef CRYPTOPP_SIMPLE_H +#define CRYPTOPP_SIMPLE_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189) +#endif + +#include "cryptlib.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Base class for identifying algorithm +/// \tparam BASE base class from which to derive +/// \tparam DERIVED class which to clone +template +class CRYPTOPP_NO_VTABLE ClonableImpl : public BASE +{ +public: + /// \brief Create a copy of this object + /// \return a copy of this object + /// \details The caller is responsible for freeing the object. + Clonable * Clone() const {return new DERIVED(*static_cast(this));} +}; + +/// \brief Base class information +/// \tparam BASE an Algorithm derived class +/// \tparam ALGORITHM_INFO an Algorithm derived class +/// \details AlgorithmImpl provides StaticAlgorithmName from the template parameter BASE +template +class CRYPTOPP_NO_VTABLE AlgorithmImpl : public BASE +{ +public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static member function. + /// The name is taken from information provided by BASE. + static std::string CRYPTOPP_API StaticAlgorithmName() {return ALGORITHM_INFO::StaticAlgorithmName();} + /// \brief The algorithm name + /// \return the algorithm name + /// \details AlgorithmName returns the algorithm's name as a member function. + /// The name is acquired by calling StaticAlgorithmName. + std::string AlgorithmName() const {return ALGORITHM_INFO::StaticAlgorithmName();} +}; + +/// \brief Exception thrown when an invalid key length is encountered +class CRYPTOPP_DLL InvalidKeyLength : public InvalidArgument +{ +public: + /// \brief Construct an InvalidKeyLength + /// \param algorithm the Algorithm associated with the exception + /// \param length the key size associated with the exception + explicit InvalidKeyLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid key length") {} +}; + +/// \brief Exception thrown when an invalid number of rounds is encountered +class CRYPTOPP_DLL InvalidRounds : public InvalidArgument +{ +public: + /// \brief Construct an InvalidRounds + /// \param algorithm the Algorithm associated with the exception + /// \param rounds the number of rounds associated with the exception + explicit InvalidRounds(const std::string &algorithm, unsigned int rounds) : InvalidArgument(algorithm + ": " + IntToString(rounds) + " is not a valid number of rounds") {} +}; + +/// \brief Exception thrown when an invalid block size is encountered +class CRYPTOPP_DLL InvalidBlockSize : public InvalidArgument +{ +public: + /// \brief Construct an InvalidBlockSize + /// \param algorithm the Algorithm associated with the exception + /// \param length the block size associated with the exception + explicit InvalidBlockSize(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid block size") {} +}; + +/// \brief Exception thrown when an invalid derived key length is encountered +class CRYPTOPP_DLL InvalidDerivedKeyLength : public InvalidArgument +{ +public: + /// \brief Construct an InvalidDerivedKeyLength + /// \param algorithm the Algorithm associated with the exception + /// \param length the size associated with the exception + explicit InvalidDerivedKeyLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid derived key length") {} +}; + +/// \brief Exception thrown when an invalid personalization string length is encountered +class CRYPTOPP_DLL InvalidPersonalizationLength : public InvalidArgument +{ +public: + /// \brief Construct an InvalidPersonalizationLength + /// \param algorithm the Algorithm associated with the exception + /// \param length the personalization size associated with the exception + explicit InvalidPersonalizationLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid salt length") {} +}; + +/// \brief Exception thrown when an invalid salt length is encountered +class CRYPTOPP_DLL InvalidSaltLength : public InvalidArgument +{ +public: + /// \brief Construct an InvalidSaltLength + /// \param algorithm the Algorithm associated with the exception + /// \param length the salt size associated with the exception + explicit InvalidSaltLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid salt length") {} +}; + +// ***************************** + +/// \brief Base class for bufferless filters +/// \tparam T the class or type +template +class CRYPTOPP_NO_VTABLE Bufferless : public T +{ +public: + /// \brief Flushes data buffered by this object, without signal propagation + /// \param hardFlush indicates whether all data should be flushed + /// \param blocking specifies whether the object should block when processing input + /// \note hardFlush must be used with care + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); return false;} +}; + +/// \brief Base class for unflushable filters +/// \tparam T the class or type +template +class CRYPTOPP_NO_VTABLE Unflushable : public T +{ +public: + /// \brief Flush buffered input and/or output, with signal propagation + /// \param completeFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the Flush() + /// signal should be passed + /// \param blocking specifies whether the object should block when processing + /// input + /// \details propagation count includes this object. Setting propagation to + /// 1 means this object only. Setting propagation to -1 + /// means unlimited propagation. + /// \note Hard flushes must be used with care. It means try to process and + /// output everything, even if there may not be enough data to complete the + /// action. For example, hard flushing a HexDecoder would cause an error if + /// you do it after inputing an odd number of hex encoded characters. + /// \note For some types of filters, like ZlibDecompressor, hard flushes can + /// only be done at "synchronization points". These synchronization points + /// are positions in the data stream that are created by hard flushes on the + /// corresponding reverse filters, in this example ZlibCompressor. This is + /// useful when zlib compressed data is moved across a network in packets + /// and compression state is preserved across packets, as in the SSH2 protocol. + bool Flush(bool completeFlush, int propagation=-1, bool blocking=true) + {return ChannelFlush(DEFAULT_CHANNEL, completeFlush, propagation, blocking);} + + /// \brief Flushes data buffered by this object, without signal propagation + /// \param hardFlush indicates whether all data should be flushed + /// \param blocking specifies whether the object should block when processing input + /// \note hardFlush must be used with care + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); CRYPTOPP_ASSERT(false); return false;} + + /// \brief Flush buffered input and/or output on a channel + /// \param channel the channel to flush the data + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the ChannelFlush() + /// signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true of the Flush was successful + /// \details propagation count includes this object. Setting propagation to + /// 1 means this object only. Setting propagation to -1 means + /// unlimited propagation. + bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true) + { + if (hardFlush && !InputBufferIsEmpty()) + throw CannotFlush("Unflushable: this object has buffered input that cannot be flushed"); + else + { + BufferedTransformation *attached = this->AttachedTransformation(); + return attached && propagation ? attached->ChannelFlush(channel, hardFlush, propagation-1, blocking) : false; + } + } + +protected: + virtual bool InputBufferIsEmpty() const {return false;} +}; + +/// \brief Base class for input rejecting filters +/// \tparam T the class or type +/// \details T should be a BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE InputRejecting : public T +{ +public: + struct InputRejected : public NotImplemented + {InputRejected() : NotImplemented("BufferedTransformation: this object doesn't allow input") {}}; + + /// \name INPUT + //@{ + + /// \brief Input a byte array for processing + /// \param inString the byte array to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \throw InputRejected + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + /// \details Internally, the default implementation throws InputRejected. + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();} + //@} + + /// \name SIGNALS + //@{ + + /// \brief Flushes data buffered by this object, without signal propagation + /// \param hardFlush indicates whether all data should be flushed + /// \param blocking specifies whether the object should block when processing input + /// \note hardFlush must be used with care + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); return false;} + + /// \brief Marks the end of a series of messages, without signal propagation + /// \param blocking specifies whether the object should block when completing the processing on + /// the current series of messages + /// \return true if the message was successful, false otherwise + bool IsolatedMessageSeriesEnd(bool blocking) + {CRYPTOPP_UNUSED(blocking); throw InputRejected();} + + /// \brief Input multiple bytes for processing on a channel. + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + size_t ChannelPut2(const std::string &channel, const byte *inString, size_t length, int messageEnd, bool blocking) + {CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); + CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();} + + /// \brief Marks the end of a series of messages on a channel + /// \param channel the channel to signal the end of a series of messages + /// \param messageEnd the number of attached transformations the ChannelMessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true if the message was successful, false otherwise + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + bool ChannelMessageSeriesEnd(const std::string& channel, int messageEnd, bool blocking) + {CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();} + //@} +}; + +/// \brief Interface for custom flush signals propagation +/// \tparam T BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE CustomFlushPropagation : public T +{ +public: + /// \name SIGNALS + //@{ + + /// \brief Flush buffered input and/or output, with signal propagation + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the Flush() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note Hard flushes must be used with care. It means try to process and output everything, even if + /// there may not be enough data to complete the action. For example, hard flushing a HexDecoder + /// would cause an error if you do it after inputing an odd number of hex encoded characters. + /// \note For some types of filters, like ZlibDecompressor, hard flushes can only + /// be done at "synchronization points". These synchronization points are positions in the data + /// stream that are created by hard flushes on the corresponding reverse filters, in this + /// example ZlibCompressor. This is useful when zlib compressed data is moved across a + /// network in packets and compression state is preserved across packets, as in the SSH2 protocol. + virtual bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) =0; + + //@} + +private: + bool IsolatedFlush(bool hardFlush, bool blocking) + {CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); CRYPTOPP_ASSERT(false); return false;} +}; + +/// \brief Interface for custom flush signals +/// \tparam T BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE CustomSignalPropagation : public CustomFlushPropagation +{ +public: + /// \brief Initialize or reinitialize this object, with signal propagation + /// \param parameters a set of NameValuePairs to initialize or reinitialize this object + /// \param propagation the number of attached transformations the Initialize() signal should be passed + /// \details Initialize() is used to initialize or reinitialize an object using a variable number of + /// arbitrarily typed arguments. The function avoids the need for multiple constructors providing + /// all possible combintations of configurable parameters. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + virtual void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1) =0; + +private: + void IsolatedInitialize(const NameValuePairs ¶meters) + {CRYPTOPP_UNUSED(parameters); CRYPTOPP_ASSERT(false);} +}; + +/// \brief Multiple channels support for custom signal processing +/// \tparam T the class or type +/// \details T should be a BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE Multichannel : public CustomFlushPropagation +{ +public: + bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) + {return this->ChannelFlush(DEFAULT_CHANNEL, hardFlush, propagation, blocking);} + + /// \brief Marks the end of a series of messages, with signal propagation + /// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \details Each object that receives the signal will perform its processing, decrement + /// propagation, and then pass the signal on to attached transformations if the value is not 0. + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + /// \note There should be a MessageEnd() immediately before MessageSeriesEnd(). + bool MessageSeriesEnd(int propagation=-1, bool blocking=true) + {return this->ChannelMessageSeriesEnd(DEFAULT_CHANNEL, propagation, blocking);} + + /// \brief Request space which can be written into by the caller + /// \param size the requested size of the buffer + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink, cannot create a space because its fixed. In the case of + /// an ArraySink, the pointer to the array is returned and the size is remaining size. + byte * CreatePutSpace(size_t &size) + {return this->ChannelCreatePutSpace(DEFAULT_CHANNEL, size);} + + /// \brief Input multiple bytes for processing + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + /// \details Derived classes must implement Put2(). + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {return this->ChannelPut2(DEFAULT_CHANNEL, inString, length, messageEnd, blocking);} + + /// \brief Input multiple bytes that may be modified by callee. + /// \param inString the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + /// \details Internally, PutModifiable2() calls Put2(). + size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking) + {return this->ChannelPutModifiable2(DEFAULT_CHANNEL, inString, length, messageEnd, blocking);} + + // void ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1) + // {PropagateMessageSeriesEnd(propagation, channel);} + + /// \brief Request space which can be written into by the caller + /// \param channel the channel to process the data + /// \param size the requested size of the buffer + /// \return a pointer to a memory block with length size + /// \details The purpose of this method is to help avoid extra memory allocations. + /// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made, + /// size is the requested size of the buffer. When the call returns, size is the size of + /// the array returned to the caller. + /// \details The base class implementation sets size to 0 and returns NULL. + /// \note Some objects, like ArraySink(), cannot create a space because its fixed. In the case of + /// an ArraySink(), the pointer to the array is returned and the size is remaining size. + byte * ChannelCreatePutSpace(const std::string &channel, size_t &size) + {CRYPTOPP_UNUSED(channel); size = 0; return NULLPTR;} + + /// \brief Input multiple bytes that may be modified by callee on a channel + /// \param channel the channel to process the data. + /// \param inString the byte buffer to process + /// \param length the size of the string, in bytes + /// \return true if all bytes were processed, false otherwise. + bool ChannelPutModifiable(const std::string &channel, byte *inString, size_t length) + {this->ChannelPut(channel, inString, length); return false;} + + /// \brief Input multiple bytes for processing on a channel. + /// \param channel the channel to process the data. + /// \param begin the byte buffer to process. + /// \param length the size of the string, in bytes. + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one. + /// \param blocking specifies whether the object should block when processing input. + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + virtual size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) =0; + + /// \brief Input multiple bytes that may be modified by callee on a channel + /// \param channel the channel to process the data + /// \param begin the byte buffer to process + /// \param length the size of the string, in bytes + /// \param messageEnd means how many filters to signal MessageEnd() to, including this one + /// \param blocking specifies whether the object should block when processing input + /// \return the number of bytes that remain to be processed (i.e., bytes not processed) + size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking) + {return ChannelPut2(channel, begin, length, messageEnd, blocking);} + + /// \brief Flush buffered input and/or output on a channel + /// \param channel the channel to flush the data + /// \param hardFlush is used to indicate whether all data should be flushed + /// \param propagation the number of attached transformations the ChannelFlush() signal should be passed + /// \param blocking specifies whether the object should block when processing input + /// \return true of the Flush was successful + /// \details propagation count includes this object. Setting propagation to 1 means this + /// object only. Setting propagation to -1 means unlimited propagation. + virtual bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true) =0; +}; + +/// \brief Provides auto signaling support +/// \tparam T BufferedTransformation derived class +template +class CRYPTOPP_NO_VTABLE AutoSignaling : public T +{ +public: + /// \brief Construct an AutoSignaling + /// \param propagation the propagation count + AutoSignaling(int propagation=-1) : m_autoSignalPropagation(propagation) {} + + /// \brief Set propagation of automatically generated and transferred signals + /// \param propagation then new value + /// \details Setting propagation to 0 means do not automatically generate signals. Setting + /// propagation to -1 means unlimited propagation. + void SetAutoSignalPropagation(int propagation) + {m_autoSignalPropagation = propagation;} + + /// \brief Retrieve automatic signal propagation value + /// \return the number of attached transformations the signal is propagated to. 0 indicates + /// the signal is only witnessed by this object + int GetAutoSignalPropagation() const + {return m_autoSignalPropagation;} + +private: + int m_autoSignalPropagation; +}; + +/// \brief Acts as a Source for pre-existing, static data +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Store : public AutoSignaling > +{ +public: + /// \brief Construct a Store + Store() : m_messageEnd(false) {} + + void IsolatedInitialize(const NameValuePairs ¶meters) + { + m_messageEnd = false; + StoreInitialize(parameters); + } + + unsigned int NumberOfMessages() const {return m_messageEnd ? 0 : 1;} + bool GetNextMessage(); + unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const; + +protected: + virtual void StoreInitialize(const NameValuePairs ¶meters) =0; + + bool m_messageEnd; +}; + +/// \brief Implementation of BufferedTransformation's attachment interface +/// \details Sink is a cornerstone of the Pipeline trinity. Data flows from +/// Sources, through Filters, and then terminates in Sinks. The difference +/// between a Source and Filter is a Source \a pumps data, while a Filter does +/// not. The difference between a Filter and a Sink is a Filter allows an +/// attached transformation, while a Sink does not. +/// \details A Sink does not produce any retrievable output. +/// \details See the discussion of BufferedTransformation in cryptlib.h for +/// more details. +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Sink : public BufferedTransformation +{ +public: + size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) + {CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(transferBytes); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); transferBytes = 0; return 0;} + size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const + {CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(begin); CRYPTOPP_UNUSED(end); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); return 0;} +}; + +/// \brief Acts as an input discarding Filter or Sink +/// \details The BitBucket discards all input and returns 0 to the caller +/// to indicate all data was processed. +class CRYPTOPP_DLL BitBucket : public Bufferless +{ +public: + std::string AlgorithmName() const {return "BitBucket";} + void IsolatedInitialize(const NameValuePairs ¶ms) + {CRYPTOPP_UNUSED(params);} + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) + {CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); return 0;} +}; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/siphash.h b/third_party/cryptoppwin/include/cryptopp/siphash.h new file mode 100644 index 00000000..5eb53216 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/siphash.h @@ -0,0 +1,314 @@ +// siphash.h - written and placed in public domain by Jeffrey Walton. + +/// \file siphash.h +/// \brief Classes for SipHash message authentication code +/// \details SipHash computes a 64-bit or 128-bit message authentication code from a variable-length +/// message and 128-bit secret key. It was designed to be efficient even for short inputs, with +/// performance comparable to non-cryptographic hash functions. +/// \details To create a SipHash-2-4 object with a 64-bit MAC use code similar to the following. +///
  SecByteBlock key(16);
+///   prng.GenerateBlock(key, key.size());
+///
+///   SipHash<2,4,false> hash(key, key.size());
+///   hash.Update(...);
+///   hash.Final(...);
+/// \details To create a SipHash-2-4 object with a 128-bit MAC use code similar to the following. +///
  SecByteBlock key(16);
+///   prng.GenerateBlock(key, key.size());
+///
+///   SipHash<2,4,true> hash(key, key.size());
+///   hash.Update(...);
+///   hash.Final(...);
+/// \sa Jean-Philippe Aumasson and Daniel J. Bernstein SipHash: +/// a fast short-input PRF +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SIPHASH_H +#define CRYPTOPP_SIPHASH_H + +#include "cryptlib.h" +#include "secblock.h" +#include "seckey.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SipHash message authentication code information +/// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size +template +class SipHash_Info : public FixedKeyLength<16> +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SipHash";} + CRYPTOPP_CONSTANT(DIGESTSIZE = (T_128bit ? 16 : 8)); +}; + +/// \brief SipHash message authentication code base class +/// \tparam C the number of compression rounds +/// \tparam D the number of finalization rounds +/// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size +template +class SipHash_Base : public MessageAuthenticationCode, public SipHash_Info +{ +public: + static std::string StaticAlgorithmName() { + return std::string(SipHash_Info::StaticAlgorithmName())+"-"+IntToString(C)+"-"+IntToString(D); + } + + virtual ~SipHash_Base() {} + + SipHash_Base() : m_idx(0) {} + + virtual unsigned int DigestSize() const + {return SipHash_Info::DIGESTSIZE;} + virtual size_t MinKeyLength() const + {return SipHash_Info::MIN_KEYLENGTH;} + virtual size_t MaxKeyLength() const + {return SipHash_Info::MAX_KEYLENGTH;} + virtual size_t DefaultKeyLength() const + {return SipHash_Info::DEFAULT_KEYLENGTH;} + virtual size_t GetValidKeyLength(size_t keylength) const + {CRYPTOPP_UNUSED(keylength); return SipHash_Info::DEFAULT_KEYLENGTH;} + virtual IV_Requirement IVRequirement() const + {return SimpleKeyingInterface::NOT_RESYNCHRONIZABLE;} + virtual unsigned int IVSize() const + {return 0;} + virtual unsigned int OptimalBlockSize() const + {return sizeof(word64);} + virtual unsigned int OptimalDataAlignment () const + {return GetAlignmentOf();} + + virtual void Update(const byte *input, size_t length); + virtual void TruncatedFinal(byte *digest, size_t digestSize); + +protected: + + virtual void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + virtual void Restart(); + + inline void SIPROUND() + { + m_v[0] += m_v[1]; + m_v[1] = rotlConstant<13>(m_v[1]); + m_v[1] ^= m_v[0]; + m_v[0] = rotlConstant<32>(m_v[0]); + m_v[2] += m_v[3]; + m_v[3] = rotlConstant<16>(m_v[3]); + m_v[3] ^= m_v[2]; + m_v[0] += m_v[3]; + m_v[3] = rotlConstant<21>(m_v[3]); + m_v[3] ^= m_v[0]; + m_v[2] += m_v[1]; + m_v[1] = rotlConstant<17>(m_v[1]); + m_v[1] ^= m_v[2]; + m_v[2] = rotlConstant<32>(m_v[2]); + } + +private: + FixedSizeSecBlock m_v; + FixedSizeSecBlock m_k; + FixedSizeSecBlock m_b; + + // Tail bytes + FixedSizeSecBlock m_acc; + size_t m_idx; +}; + +/// \brief SipHash message authentication code +/// \tparam C the number of compression rounds +/// \tparam D the number of finalization rounds +/// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size +/// \details SipHash computes a 64-bit or 128-bit message authentication code from a variable-length +/// message and 128-bit secret key. It was designed to be efficient even for short inputs, with +/// performance comparable to non-cryptographic hash functions. +/// \details To create a SipHash-2-4 object with a 64-bit MAC use code similar to the following. +///
  SecByteBlock key(16);
+///   prng.GenerateBlock(key, key.size());
+///
+///   SipHash<2,4,false> hash(key, key.size());
+///   hash.Update(...);
+///   hash.Final(...);
+/// \details To create a SipHash-2-4 object with a 128-bit MAC use code similar to the following. +///
  SecByteBlock key(16);
+///   prng.GenerateBlock(key, key.size());
+///
+///   SipHash<2,4,true> hash(key, key.size());
+///   hash.Update(...);
+///   hash.Final(...);
+/// \sa Jean-Philippe Aumasson and Daniel J. Bernstein SipHash: +/// a fast short-input PRF +/// \since Crypto++ 6.0 +template +class SipHash : public SipHash_Base +{ +public: + /// \brief Create a SipHash + SipHash() + {this->UncheckedSetKey(NULLPTR, 0, g_nullNameValuePairs);} + /// \brief Create a SipHash + /// \param key a byte array used to key the cipher + /// \param length the size of the byte array, in bytes + SipHash(const byte *key, unsigned int length) + {this->ThrowIfInvalidKeyLength(length); + this->UncheckedSetKey(key, length, g_nullNameValuePairs);} +}; + +template +void SipHash_Base::Update(const byte *input, size_t length) +{ + CRYPTOPP_ASSERT((input && length) || !length); + if (!length) return; + + if (m_idx) + { + size_t head = STDMIN(size_t(8U-m_idx), length); + std::memcpy(m_acc+m_idx, input, head); + m_idx += head; input += head; length -= head; + + if (m_idx == 8) + { + word64 m = GetWord(true, LITTLE_ENDIAN_ORDER, m_acc); + m_v[3] ^= m; + for (unsigned int i = 0; i < C; ++i) + SIPROUND(); + + m_v[0] ^= m; + m_b[0] += 8; + + m_idx = 0; + } + } + + while (length >= 8) + { + word64 m = GetWord(false, LITTLE_ENDIAN_ORDER, input); + m_v[3] ^= m; + for (unsigned int i = 0; i < C; ++i) + SIPROUND(); + + m_v[0] ^= m; + m_b[0] += 8; + + input += 8; + length -= 8; + } + + CRYPTOPP_ASSERT(length < 8); + size_t tail = length % 8; + if (tail) + { + std::memcpy(m_acc+m_idx, input, tail); + m_idx += tail; + } +} + +template +void SipHash_Base::TruncatedFinal(byte *digest, size_t digestSize) +{ + CRYPTOPP_ASSERT(digest); // Pointer is valid + + ThrowIfInvalidTruncatedSize(digestSize); + + // The high octet holds length and is digested mod 256 + m_b[0] += m_idx; m_b[0] <<= 56U; + switch (m_idx) + { + case 7: + m_b[0] |= ((word64)m_acc[6]) << 48; + // fall through + case 6: + m_b[0] |= ((word64)m_acc[5]) << 40; + // fall through + case 5: + m_b[0] |= ((word64)m_acc[4]) << 32; + // fall through + case 4: + m_b[0] |= ((word64)m_acc[3]) << 24; + // fall through + case 3: + m_b[0] |= ((word64)m_acc[2]) << 16; + // fall through + case 2: + m_b[0] |= ((word64)m_acc[1]) << 8; + // fall through + case 1: + m_b[0] |= ((word64)m_acc[0]); + // fall through + case 0: + break; + } + + m_v[3] ^= m_b[0]; + + for (unsigned int i=0; i::DIGESTSIZE)); + Restart(); +} + +template +void SipHash_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) +{ + CRYPTOPP_UNUSED(params); + if (key && length) + { + m_k[0] = GetWord(false, LITTLE_ENDIAN_ORDER, key); + m_k[1] = GetWord(false, LITTLE_ENDIAN_ORDER, key+8); + } + else + { + // Avoid Coverity finding + m_k[0] = m_k[1] = 0; + } + Restart(); +} + +template +void SipHash_Base::Restart () +{ + m_v[0] = W64LIT(0x736f6d6570736575); + m_v[1] = W64LIT(0x646f72616e646f6d); + m_v[2] = W64LIT(0x6c7967656e657261); + m_v[3] = W64LIT(0x7465646279746573); + + m_v[3] ^= m_k[1]; + m_v[2] ^= m_k[0]; + m_v[1] ^= m_k[1]; + m_v[0] ^= m_k[0]; + + if (T_128bit) + { + m_v[1] ^= 0xee; + } + + m_idx = 0; + m_b[0] = 0; +} + +NAMESPACE_END + +#endif // CRYPTOPP_SIPHASH_H diff --git a/third_party/cryptoppwin/include/cryptopp/skipjack.h b/third_party/cryptoppwin/include/cryptopp/skipjack.h new file mode 100644 index 00000000..96fdaf40 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/skipjack.h @@ -0,0 +1,80 @@ +// skipjack.h - originally written and placed in the public domain by Wei Dai + +/// \file skipjack.h +/// \brief Classes for the SKIPJACK block cipher +/// \details The Crypto++ implementation conforms to SKIPJACK and KEA +/// Algorithm Specifications published by NIST in May 1998. The library passes +/// known answer tests available in NIST SP800-17, Table 6, pp. 140-42. +/// \sa SKIPJACK +/// and KEA Algorithm Specifications (May 1998), +/// SKIPJACK on the +// Crypto++ wiki + +#ifndef CRYPTOPP_SKIPJACK_H +#define CRYPTOPP_SKIPJACK_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SKIPJACK block cipher information +struct SKIPJACK_Info : public FixedBlockSize<8>, public FixedKeyLength<10> +{ + CRYPTOPP_DLL static const char * CRYPTOPP_API StaticAlgorithmName() {return "SKIPJACK";} +}; + +/// \brief SKIPJACK block cipher +/// \details The Crypto++ implementation conforms to SKIPJACK and KEA +/// Algorithm Specifications published by NIST in May 1998. The library passes +/// known answer tests available in NIST SP800-17, Table 6, pp. 140-42. +/// \sa SKIPJACK +/// and KEA Algorithm Specifications (May 1998), +/// SKIPJACK on the +/// Crypto++ wiki +class SKIPJACK : public SKIPJACK_Info, public BlockCipherDocumentation +{ + /// \brief SKIPJACK block cipher default operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + unsigned int OptimalDataAlignment() const {return GetAlignmentOf();} + + protected: + static const byte fTable[256]; + + FixedSizeSecBlock tab; + }; + + /// \brief SKIPJACK block cipher encryption operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Se[256]; + static const word32 Te[4][256]; + }; + + /// \brief SKIPJACK block cipher decryption operation + class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Sd[256]; + static const word32 Td[4][256]; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef SKIPJACK::Encryption SKIPJACKEncryption; +typedef SKIPJACK::Decryption SKIPJACKDecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/sm3.h b/third_party/cryptoppwin/include/cryptopp/sm3.h new file mode 100644 index 00000000..fefcfec4 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/sm3.h @@ -0,0 +1,61 @@ +// sm3.h - written and placed in the public domain by Jeffrey Walton and Han Lulu +// Based on the specification provided by Sean Shen and Xiaodong Lee. +// Based on code by Krzysztof Kwiatkowski and Jack Lloyd. +// Also see https://tools.ietf.org/html/draft-shen-sm3-hash. + +/// \file sm3.h +/// \brief Classes for the SM3 hash function +/// \details SM3 is a hash function designed by Xiaoyun Wang, et al. The hash is part of the +/// Chinese State Cryptography Administration portfolio. +/// \sa SM3 Hash Function and +/// Reference implementation using OpenSSL. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SM3_H +#define CRYPTOPP_SM3_H + +#include "config.h" +#include "iterhash.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SM3 hash function +/// \details SM3 is a hash function designed by Xiaoyun Wang, et al. The hash is part of the +/// Chinese State Cryptography Administration portfolio. +/// \sa SM3 Hash Function +/// \since Crypto++ 6.0 +class SM3 : public IteratedHashWithStaticTransform +{ +public: + /// \brief Initialize state array + /// \param state the state of the hash + /// \details InitState sets a state array to SM3 initial values + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState() and Transform(). External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + static void InitState(HashWordType *state); + + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + /// \details Transform() operates the hash on data. When the call is invoked + /// digest holds initial or current state. Upon return digest holds + /// the hash or updated state. + /// \details Hashes which derive from IteratedHashWithStaticTransform provide static + /// member functions InitState() and Transform(). External classes, like SEAL and MDC, + /// can initialize state with a user provided key and operate the hash on the data + /// with the user supplied state. + static void Transform(HashWordType *digest, const HashWordType *data); + + /// \brief The algorithm name + /// \return C-style string "SM3" + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() { return "SM3"; } + +protected: + size_t HashMultipleBlocks(const HashWordType *input, size_t length); +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SM3_H diff --git a/third_party/cryptoppwin/include/cryptopp/sm4.h b/third_party/cryptoppwin/include/cryptopp/sm4.h new file mode 100644 index 00000000..dc41f732 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/sm4.h @@ -0,0 +1,96 @@ +// sm4.h - written and placed in the public domain by Jeffrey Walton and Han Lulu + +/// \file sm4.h +/// \brief Classes for the SM4 block cipher +/// \details SM4 is a block cipher designed by Xiaoyun Wang, et al. The block cipher is part of the +/// Chinese State Cryptography Administration portfolio. The cipher was formerly known as SMS4. +/// \details SM4 encryption is accelerated on machines with AES-NI. Decryption is not accelerated because +/// it is not profitable. Thanks to Markku-Juhani Olavi Saarinen for help and the code. +/// \sa SMS4 Encryption Algorithm for Wireless Networks, +/// Reference implementation using OpenSSL and +/// Markku-Juhani Olavi Saarinen GitHub. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SM4_H +#define CRYPTOPP_SM4_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +#if (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86) +# ifndef CRYPTOPP_DISABLE_SM4_SIMD +# define CRYPTOPP_SM4_ADVANCED_PROCESS_BLOCKS 1 +# endif +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SM4 block cipher information +/// \since Crypto++ 6.0 +struct SM4_Info : public FixedBlockSize<16>, FixedKeyLength<16> +{ + static const std::string StaticAlgorithmName() + { + return "SM4"; + } +}; + +/// \brief Classes for the SM4 block cipher +/// \details SM4 is a block cipher designed by Xiaoyun Wang, et al. The block cipher is part of the +/// Chinese State Cryptography Administration portfolio. The cipher was formerly known as SMS4. +/// \sa SMS4 Encryption Algorithm for Wireless Networks +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SM4 : public SM4_Info, public BlockCipherDocumentation +{ +public: + /// \brief SM4 block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + + SecBlock > m_rkeys; + mutable SecBlock > m_wspace; + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key + /// sizes are supported. + /// \details SM4 encryption is accelerated on machines with AES-NI. Decryption is + /// not accelerated because it is not profitable. Thanks to Markku-Juhani Olavi + /// Saarinen. + /// \since Crypto++ 6.0, AESNI encryption since Crypto++ 8.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + std::string AlgorithmProvider() const; + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SM4_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key + /// sizes are supported. + /// \details SM4 encryption is accelerated on machines with AES-NI. Decryption is + /// not accelerated because it is not profitable. Thanks to Markku-Juhani Olavi + /// Saarinen. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SM4_H diff --git a/third_party/cryptoppwin/include/cryptopp/smartptr.h b/third_party/cryptoppwin/include/cryptopp/smartptr.h new file mode 100644 index 00000000..4e16a7fe --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/smartptr.h @@ -0,0 +1,257 @@ +// smartptr.h - originally written and placed in the public domain by Wei Dai + +/// \file smartptr.h +/// \brief Classes for automatic resource management + +#ifndef CRYPTOPP_SMARTPTR_H +#define CRYPTOPP_SMARTPTR_H + +#include "config.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Manages resources for a single object +/// \tparam T class or type +/// \details \p simple_ptr is used frequently in the library to manage resources and +/// ensure cleanup under the RAII pattern (Resource Acquisition Is Initialization). +template class simple_ptr +{ +public: + simple_ptr(T *p = NULLPTR) : m_p(p) {} + ~simple_ptr() + { + delete m_p; + m_p = NULLPTR; + } + + T *m_p; +}; + +/// \brief Pointer that overloads operator -> +/// \tparam T class or type +/// \details member_ptr is used frequently in the library to avoid the issues related to +/// std::auto_ptr in C++11 (deprecated) and std::unique_ptr in C++03 (non-existent). +/// \bug Issue 48: "Use of auto_ptr +/// causes dirty compile under C++11" +template class member_ptr +{ +public: + explicit member_ptr(T *p = NULLPTR) : m_p(p) {} + + ~member_ptr(); + + const T& operator*() const { return *m_p; } + T& operator*() { return *m_p; } + + const T* operator->() const { return m_p; } + T* operator->() { return m_p; } + + const T* get() const { return m_p; } + T* get() { return m_p; } + + T* release() + { + T *old_p = m_p; + m_p = NULLPTR; + return old_p; + } + + void reset(T *p = NULLPTR); + +protected: + member_ptr(const member_ptr& rhs); // copy not allowed + void operator=(const member_ptr& rhs); // assignment not allowed + + T *m_p; +}; + +template member_ptr::~member_ptr() {delete m_p;} +template void member_ptr::reset(T *p) {delete m_p; m_p = p;} + +// ******************************************************** + +/// \brief Value pointer +/// \tparam T class or type +template class value_ptr : public member_ptr +{ +public: + value_ptr(const T &obj) : member_ptr(new T(obj)) {} + value_ptr(T *p = NULLPTR) : member_ptr(p) {} + value_ptr(const value_ptr& rhs) + : member_ptr(rhs.m_p ? new T(*rhs.m_p) : NULLPTR) {} + + value_ptr& operator=(const value_ptr& rhs); + bool operator==(const value_ptr& rhs) + { + return (!this->m_p && !rhs.m_p) || (this->m_p && rhs.m_p && *this->m_p == *rhs.m_p); + } +}; + +template value_ptr& value_ptr::operator=(const value_ptr& rhs) +{ + T *old_p = this->m_p; + this->m_p = rhs.m_p ? new T(*rhs.m_p) : NULLPTR; + delete old_p; + return *this; +} + +// ******************************************************** + +/// \brief A pointer which can be copied and cloned +/// \tparam T class or type +/// \details \p T should adhere to the \p Clonable interface +template class clonable_ptr : public member_ptr +{ +public: + clonable_ptr(const T &obj) : member_ptr(obj.Clone()) {} + clonable_ptr(T *p = NULLPTR) : member_ptr(p) {} + clonable_ptr(const clonable_ptr& rhs) + : member_ptr(rhs.m_p ? rhs.m_p->Clone() : NULLPTR) {} + + clonable_ptr& operator=(const clonable_ptr& rhs); +}; + +template clonable_ptr& clonable_ptr::operator=(const clonable_ptr& rhs) +{ + T *old_p = this->m_p; + this->m_p = rhs.m_p ? rhs.m_p->Clone() : NULLPTR; + delete old_p; + return *this; +} + +// ******************************************************** + +/// \brief Reference counted pointer +/// \tparam T class or type +/// \details users should declare \p m_referenceCount as std::atomic +/// (or similar) under C++ 11 +template class counted_ptr +{ +public: + explicit counted_ptr(T *p = NULLPTR); + counted_ptr(const T &r) : m_p(0) {attach(r);} + counted_ptr(const counted_ptr& rhs); + + ~counted_ptr(); + + const T& operator*() const { return *m_p; } + T& operator*() { return *m_p; } + + const T* operator->() const { return m_p; } + T* operator->() { return get(); } + + const T* get() const { return m_p; } + T* get(); + + void attach(const T &p); + + counted_ptr & operator=(const counted_ptr& rhs); + +private: + T *m_p; +}; + +template counted_ptr::counted_ptr(T *p) + : m_p(p) +{ + if (m_p) + m_p->m_referenceCount = 1; +} + +template counted_ptr::counted_ptr(const counted_ptr& rhs) + : m_p(rhs.m_p) +{ + if (m_p) + m_p->m_referenceCount++; +} + +template counted_ptr::~counted_ptr() +{ + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; +} + +template void counted_ptr::attach(const T &r) +{ + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; + if (r.m_referenceCount == 0) + { + m_p = r.clone(); + m_p->m_referenceCount = 1; + } + else + { + m_p = const_cast(&r); + m_p->m_referenceCount++; + } +} + +template T* counted_ptr::get() +{ + if (m_p && m_p->m_referenceCount > 1) + { + T *temp = m_p->clone(); + m_p->m_referenceCount--; + m_p = temp; + m_p->m_referenceCount = 1; + } + return m_p; +} + +template counted_ptr & counted_ptr::operator=(const counted_ptr& rhs) +{ + if (m_p != rhs.m_p) + { + if (m_p && --m_p->m_referenceCount == 0) + delete m_p; + m_p = rhs.m_p; + if (m_p) + m_p->m_referenceCount++; + } + return *this; +} + +// ******************************************************** + +/// \brief Manages resources for an array of objects +/// \tparam T class or type +template class vector_member_ptrs +{ +public: + /// Construct an array of \p T + /// \param size the size of the array, in elements + /// \details If \p T is a Plain Old Dataype (POD), then the array is uninitialized. + vector_member_ptrs(size_t size=0) + : m_size(size), m_ptr(new member_ptr[size]) {} + ~vector_member_ptrs() + {delete [] this->m_ptr;} + + member_ptr& operator[](size_t index) + {CRYPTOPP_ASSERT(indexm_size); return this->m_ptr[index];} + const member_ptr& operator[](size_t index) const + {CRYPTOPP_ASSERT(indexm_size); return this->m_ptr[index];} + + size_t size() const {return this->m_size;} + void resize(size_t newSize) + { + member_ptr *newPtr = new member_ptr[newSize]; + for (size_t i=0; im_size && im_ptr[i].release()); + delete [] this->m_ptr; + this->m_size = newSize; + this->m_ptr = newPtr; + } + +private: + vector_member_ptrs(const vector_member_ptrs &c); // copy not allowed + void operator=(const vector_member_ptrs &x); // assignment not allowed + + size_t m_size; + member_ptr *m_ptr; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/sosemanuk.h b/third_party/cryptoppwin/include/cryptopp/sosemanuk.h new file mode 100644 index 00000000..fc1a1bb7 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/sosemanuk.h @@ -0,0 +1,62 @@ +// sosemanuk.h - originally written and placed in the public domain by Wei Dai + +/// \file sosemanuk.h +/// \brief Classes for Sosemanuk stream cipher +/// \since Crypto++ 5.5 + +#ifndef CRYPTOPP_SOSEMANUK_H +#define CRYPTOPP_SOSEMANUK_H + +#include "strciphr.h" +#include "secblock.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_SOSEMANUK_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Sosemanuk stream cipher information +/// \since Crypto++ 5.5 +struct SosemanukInfo : public VariableKeyLength<16, 1, 32, 1, SimpleKeyingInterface::UNIQUE_IV, 16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Sosemanuk";} +}; + +/// \brief Sosemanuk stream cipher implementation +/// \since Crypto++ 5.5 +class SosemanukPolicy : public AdditiveCipherConcretePolicy, public SosemanukInfo +{ +protected: + std::string AlgorithmProvider() const; + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length); + bool CipherIsRandomAccess() const {return false;} +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) + unsigned int GetAlignment() const; + unsigned int GetOptimalBlockSize() const; +#endif + + FixedSizeSecBlock m_key; + FixedSizeAlignedSecBlock m_state; +}; + +/// \brief Sosemanuk stream cipher +/// \details is a stream cipher developed by Come Berbain, Olivier Billet, Anne Canteaut, Nicolas Courtois, +/// Henri Gilbert, Louis Goubin, Aline Gouget, Louis Granboulan, Cédric Lauradoux, Marine Minier, Thomas +/// Pornin and Hervé Sibert. Sosemanuk is one of the final four Profile 1 (software) ciphers selected for +/// the eSTREAM Portfolio. +/// \sa Sosemanuk +/// \since Crypto++ 5.5 +struct Sosemanuk : public SosemanukInfo, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, SosemanukInfo> Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/speck.h b/third_party/cryptoppwin/include/cryptopp/speck.h new file mode 100644 index 00000000..5ab3ece7 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/speck.h @@ -0,0 +1,206 @@ +// speck.h - written and placed in the public domain by Jeffrey Walton + +/// \file speck.h +/// \brief Classes for the Speck block cipher +/// \details Speck is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \sa The SIMON and SPECK Families of +/// Lightweight Block Ciphers, +/// The Simon and Speck GitHub and +/// SPECK on the Crypto++ wiki. +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_SPECK_H +#define CRYPTOPP_SPECK_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" + +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 || \ + CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARMV8 || \ + CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 +# ifndef CRYPTOPP_DISABLE_SPECK_SIMD +# define CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS 1 +# endif +#endif + +// Yet another SunStudio/SunCC workaround. Failed self tests +// in SSE code paths on i386 for SunStudio 12.3 and below. +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x5120) +# undef CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief SPECK block cipher information +/// \tparam L block size of the cipher, in bytes +/// \tparam D default key length, in bytes +/// \tparam N minimum key length, in bytes +/// \tparam M maximum key length, in bytes +/// \since Crypto++ 6.0 +template +struct SPECK_Info : public FixedBlockSize, VariableKeyLength +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "SPECK-" + IntToString(L*8); + } +}; + +/// \brief SPECK block cipher base class +/// \tparam W the word type +/// \details User code should use SPECK64 or SPECK128 +/// \sa SPECK64, SPECK128, SPECK +/// \since Crypto++ 6.0 +template +struct SPECK_Base +{ + virtual ~SPECK_Base() {} + SPECK_Base() : m_kwords(0), m_rounds(0) {} + + typedef SecBlock > AlignedSecBlock; + mutable AlignedSecBlock m_wspace; // workspace + AlignedSecBlock m_rkeys; // round keys + unsigned int m_kwords; // number of key words + unsigned int m_rounds; // number of rounds +}; + +/// \brief SPECK 64-bit block cipher +/// \details Speck is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \details SPECK64 provides 64-bit block size. The valid key sizes are 96-bit and 128-bit. +/// \sa SPECK64, SPECK128, The SIMON and SPECK +/// Families of Lightweight Block Ciphers, +/// The Simon and Speck GitHub, SPECK on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SPECK64 : public SPECK_Info<8, 12, 12, 16>, public BlockCipherDocumentation +{ +public: + /// \brief SPECK64 block cipher base implementation + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : protected SPECK_Base, public BlockCipherImpl > + { + public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details AlgorithmName returns the algorithm's name as a + /// member function. + std::string AlgorithmName() const { + return StaticAlgorithmName() + (m_kwords == 0 ? "" : + "(" + IntToString(m_kwords*sizeof(word32)*8) + ")"); + } + + std::string AlgorithmProvider() const; + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const; + + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief SPECK64 encryption transformation + /// \details Enc provides the encryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief SPECK64 decryption transformation + /// \details Dec provides the decryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief SPECK 128-bit block cipher +/// \details Speck is a block cipher designed by Ray Beaulieu, Douglas Shors, Jason Smith, +/// Stefan Treatman-Clark, Bryan Weeks and Louis Wingers. +/// \details SPECK128 provides 128-bit block size. The valid key sizes are 128-bit, 192-bit and 256-bit. +/// \sa SPECK64, SPECK128, The SIMON and SPECK +/// Families of Lightweight Block Ciphers, +/// The Simon and Speck GitHub, SPECK on the +/// Crypto++ wiki +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE SPECK128 : public SPECK_Info<16, 16, 16, 32>, public BlockCipherDocumentation +{ +public: + /// \brief SPECK128 block cipher base implementation + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : protected SPECK_Base, public BlockCipherImpl > + { + public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details AlgorithmName returns the algorithm's name as a + /// member function. + std::string AlgorithmName() const { + return StaticAlgorithmName() + (m_kwords == 0 ? "" : + "(" + IntToString(m_kwords*sizeof(word64)*8) + ")"); + } + + std::string AlgorithmProvider() const; + + /// \brief Provides input and output data alignment for optimal performance. + /// \return the input data alignment that provides optimal performance + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const; + + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief SPECK128 encryption transformation + /// \details Enc provides the encryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + /// \brief SPECK128 decryption transformation + /// \details Dec provides the decryption transformation. + /// All key sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; +#if CRYPTOPP_SPECK128_ADVANCED_PROCESS_BLOCKS + size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const; +#endif + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif // CRYPTOPP_SPECK_H diff --git a/third_party/cryptoppwin/include/cryptopp/square.h b/third_party/cryptoppwin/include/cryptopp/square.h new file mode 100644 index 00000000..e43e796d --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/square.h @@ -0,0 +1,63 @@ +// square.h - originally written and placed in the public domain by Wei Dai + +/// \file square.h +/// \brief Classes for the Square block cipher + +#ifndef CRYPTOPP_SQUARE_H +#define CRYPTOPP_SQUARE_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Square block cipher information +/// \since Crypto++ 2.2 +struct Square_Info : public FixedBlockSize<16>, public FixedKeyLength<16>, FixedRounds<8> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Square";} +}; + +/// \brief Square block cipher +/// \sa Square +/// \since Crypto++ 2.2 +class Square : public Square_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeSecBlock m_roundkeys; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Se[256]; + static const word32 Te[4][256]; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + private: + static const byte Sd[256]; + static const word32 Td[4][256]; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Square::Encryption SquareEncryption; +typedef Square::Decryption SquareDecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/stdcpp.h b/third_party/cryptoppwin/include/cryptopp/stdcpp.h new file mode 100644 index 00000000..4b5d8426 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/stdcpp.h @@ -0,0 +1,101 @@ +// stdcpp.h - originally written and placed in the public domain by Wei Dai + +/// \file stdcpp.h +/// \brief Common C++ header files + +#ifndef CRYPTOPP_STDCPP_H +#define CRYPTOPP_STDCPP_H + +#if (CRYPTOPP_MSC_VERSION >= 1500) +#define _DO_NOT_DECLARE_INTERLOCKED_INTRINSICS_IN_MEMORY +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// http://connect.microsoft.com/VisualStudio/feedback/details/1600701/type-info-does-not-compile-with-has-exceptions-0 +#if defined(CRYPTOPP_MSC_VERSION) && (CRYPTOPP_MSC_VERSION < 1900) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 0) +namespace std { + using ::type_info; +} +#endif + +// workaround needed for IBM XLC and debug heaps on AIX +#if defined(_AIX) && (defined(__xlc__) || defined(__xlC__) || defined(__ibmxl__)) +# if defined(__DEBUG_ALLOC__) +namespace std { + using ::_debug_memset; + using ::_debug_memcpy; +} +# endif +#endif + +// make_unchecked_array_iterator +#if (CRYPTOPP_MSC_VERSION >= 1600) +#include +#endif + +#if defined(CRYPTOPP_CXX11_ATOMIC) +#include +#endif + +#if defined(CRYPTOPP_CXX11_SYNCHRONIZATION) +#include +#endif + +#if defined(CRYPTOPP_CXX11_RVALUES) +# include +#endif + +#include +#include +#include +#include + +// It is 2019 and VS2017/Win10 still can't compile a +// program that includes without making users +// do something special. "Epic fail" comes to mind. +// Also see https://github.com/weidai11/cryptopp/issues/781 +#ifndef CRYPTOPP_MSC_VERSION +# include +#endif + +// uintptr_t and ptrdiff_t +#if defined(__SUNPRO_CC) +# if (__SUNPRO_CC >= 0x5100) +# include +# endif +#elif defined(CRYPTOPP_MSC_VERSION) +# if (CRYPTOPP_MSC_VERSION >= 1700) +# include +# else +# include +# endif +#elif (__cplusplus < 201103L) +# include +#endif + +// workaround needed on Sun Studio 12u1 Sun C++ 5.10 SunOS_i386 128229-02 2009/09/21 +#ifdef CRYPTOPP_INCLUDE_VECTOR_CC +# include +#endif + +// C++Builder's standard library (Dinkumware) do not have C's global log() function +// https://github.com/weidai11/cryptopp/issues/520 +#ifdef __BORLANDC__ +using std::log; +#endif + +#endif // CRYPTOPP_STDCPP_H diff --git a/third_party/cryptoppwin/include/cryptopp/strciphr.h b/third_party/cryptoppwin/include/cryptopp/strciphr.h new file mode 100644 index 00000000..ef8989db --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/strciphr.h @@ -0,0 +1,737 @@ +// strciphr.h - originally written and placed in the public domain by Wei Dai + +/// \file strciphr.h +/// \brief Classes for implementing stream ciphers +/// \details This file contains helper classes for implementing stream ciphers. +/// All this infrastructure may look very complex compared to what's in Crypto++ 4.x, +/// but stream ciphers implementations now support a lot of new functionality, +/// including better performance (minimizing copying), resetting of keys and IVs, and +/// methods to query which features are supported by a cipher. +/// \details Here's an explanation of these classes. The word "policy" is used here to +/// mean a class with a set of methods that must be implemented by individual stream +/// cipher implementations. This is usually much simpler than the full stream cipher +/// API, which is implemented by either AdditiveCipherTemplate or CFB_CipherTemplate +/// using the policy. So for example, an implementation of SEAL only needs to implement +/// the AdditiveCipherAbstractPolicy interface (since it's an additive cipher, i.e., it +/// xors a keystream into the plaintext). See this line in seal.h: +///
+///     typedef SymmetricCipherFinal\, AdditiveCipherTemplate\<\> \> \> Encryption;
+/// 
+/// \details AdditiveCipherTemplate and CFB_CipherTemplate are designed so that they don't +/// need to take a policy class as a template parameter (although this is allowed), so +/// that their code is not duplicated for each new cipher. Instead they each get a +/// reference to an abstract policy interface by calling AccessPolicy() on itself, so +/// AccessPolicy() must be overridden to return the actual policy reference. This is done +/// by the ConcretePolicyHolder class. Finally, SymmetricCipherFinal implements the +/// constructors and other functions that must be implemented by the most derived class. + +#ifndef CRYPTOPP_STRCIPHR_H +#define CRYPTOPP_STRCIPHR_H + +#include "config.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(push) +# pragma warning(disable: 4127 4189 4231 4275) +#endif + +#include "cryptlib.h" +#include "seckey.h" +#include "secblock.h" +#include "argnames.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Access a stream cipher policy object +/// \tparam POLICY_INTERFACE class implementing AbstractPolicyHolder +/// \tparam BASE class or type to use as a base class +template +class CRYPTOPP_NO_VTABLE AbstractPolicyHolder : public BASE +{ +public: + typedef POLICY_INTERFACE PolicyInterface; + virtual ~AbstractPolicyHolder() {} + +protected: + virtual const POLICY_INTERFACE & GetPolicy() const =0; + virtual POLICY_INTERFACE & AccessPolicy() =0; +}; + +/// \brief Stream cipher policy object +/// \tparam POLICY class implementing AbstractPolicyHolder +/// \tparam BASE class or type to use as a base class +template +class ConcretePolicyHolder : public BASE, protected POLICY +{ +public: + virtual ~ConcretePolicyHolder() {} +protected: + const POLICY_INTERFACE & GetPolicy() const {return *this;} + POLICY_INTERFACE & AccessPolicy() {return *this;} +}; + +/// \brief Keystream operation flags +/// \sa AdditiveCipherAbstractPolicy::GetBytesPerIteration(), AdditiveCipherAbstractPolicy::GetOptimalBlockSize() +/// and AdditiveCipherAbstractPolicy::GetAlignment() +enum KeystreamOperationFlags { + /// \brief Output buffer is aligned + OUTPUT_ALIGNED=1, + /// \brief Input buffer is aligned + INPUT_ALIGNED=2, + /// \brief Input buffer is NULL + INPUT_NULL = 4 +}; + +/// \brief Keystream operation flags +/// \sa AdditiveCipherAbstractPolicy::GetBytesPerIteration(), AdditiveCipherAbstractPolicy::GetOptimalBlockSize() +/// and AdditiveCipherAbstractPolicy::GetAlignment() +enum KeystreamOperation { + /// \brief Write the keystream to the output buffer, input is NULL + WRITE_KEYSTREAM = INPUT_NULL, + /// \brief Write the keystream to the aligned output buffer, input is NULL + WRITE_KEYSTREAM_ALIGNED = INPUT_NULL | OUTPUT_ALIGNED, + /// \brief XOR the input buffer and keystream, write to the output buffer + XOR_KEYSTREAM = 0, + /// \brief XOR the aligned input buffer and keystream, write to the output buffer + XOR_KEYSTREAM_INPUT_ALIGNED = INPUT_ALIGNED, + /// \brief XOR the input buffer and keystream, write to the aligned output buffer + XOR_KEYSTREAM_OUTPUT_ALIGNED= OUTPUT_ALIGNED, + /// \brief XOR the aligned input buffer and keystream, write to the aligned output buffer + XOR_KEYSTREAM_BOTH_ALIGNED = OUTPUT_ALIGNED | INPUT_ALIGNED +}; + +/// \brief Policy object for additive stream ciphers +struct CRYPTOPP_DLL CRYPTOPP_NO_VTABLE AdditiveCipherAbstractPolicy +{ + virtual ~AdditiveCipherAbstractPolicy() {} + + /// \brief Provides data alignment requirements + /// \return data alignment requirements, in bytes + /// \details Internally, the default implementation returns 1. If the stream cipher is implemented + /// using an SSE2 ASM or intrinsics, then the value returned is usually 16. + virtual unsigned int GetAlignment() const {return 1;} + + /// \brief Provides number of bytes operated upon during an iteration + /// \return bytes operated upon during an iteration, in bytes + /// \sa GetOptimalBlockSize() + virtual unsigned int GetBytesPerIteration() const =0; + + /// \brief Provides number of ideal bytes to process + /// \return the ideal number of bytes to process + /// \details Internally, the default implementation returns GetBytesPerIteration() + /// \sa GetBytesPerIteration() + virtual unsigned int GetOptimalBlockSize() const {return GetBytesPerIteration();} + + /// \brief Provides buffer size based on iterations + /// \return the buffer size based on iterations, in bytes + virtual unsigned int GetIterationsToBuffer() const =0; + + /// \brief Generate the keystream + /// \param keystream the key stream + /// \param iterationCount the number of iterations to generate the key stream + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream() + virtual void WriteKeystream(byte *keystream, size_t iterationCount) + {OperateKeystream(KeystreamOperation(INPUT_NULL | static_cast(IsAlignedOn(keystream, GetAlignment()))), keystream, NULLPTR, iterationCount);} + + /// \brief Flag indicating + /// \return true if the stream can be generated independent of the transformation input, false otherwise + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream() + virtual bool CanOperateKeystream() const {return false;} + + /// \brief Operates the keystream + /// \param operation the operation with additional flags + /// \param output the output buffer + /// \param input the input buffer + /// \param iterationCount the number of iterations to perform on the input + /// \details OperateKeystream() will attempt to operate upon GetOptimalBlockSize() buffer, + /// which will be derived from GetBytesPerIteration(). + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream(), KeystreamOperation() + virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) + {CRYPTOPP_UNUSED(operation); CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(input); + CRYPTOPP_UNUSED(iterationCount); CRYPTOPP_ASSERT(false);} + + /// \brief Key the cipher + /// \param params set of NameValuePairs use to initialize this object + /// \param key a byte array used to key the cipher + /// \param length the size of the key array + virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) =0; + + /// \brief Resynchronize the cipher + /// \param keystreamBuffer the keystream buffer + /// \param iv a byte array used to resynchronize the cipher + /// \param length the size of the IV array + virtual void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) + {CRYPTOPP_UNUSED(keystreamBuffer); CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(length); + throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");} + + /// \brief Flag indicating random access + /// \return true if the cipher is seekable, false otherwise + /// \sa SeekToIteration() + virtual bool CipherIsRandomAccess() const =0; + + /// \brief Seeks to a random position in the stream + /// \sa CipherIsRandomAccess() + virtual void SeekToIteration(lword iterationCount) + {CRYPTOPP_UNUSED(iterationCount); CRYPTOPP_ASSERT(!CipherIsRandomAccess()); + throw NotImplemented("StreamTransformation: this object doesn't support random access");} + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2". + /// Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics + /// instead of ASM. + /// \details Algorithms which combine different instructions or ISAs provide the + /// dominant one. For example on x86 AES/GCM returns "AESNI" rather than + /// "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL". + /// \note Provider is not universally implemented yet. + virtual std::string AlgorithmProvider() const { return "C++"; } +}; + +/// \brief Base class for additive stream ciphers +/// \tparam WT word type +/// \tparam W count of words +/// \tparam X bytes per iteration count +/// \tparam BASE AdditiveCipherAbstractPolicy derived base class +template +struct CRYPTOPP_NO_VTABLE AdditiveCipherConcretePolicy : public BASE +{ + /// \brief Word type for the cipher + typedef WT WordType; + + /// \brief Number of bytes for an iteration + /// \details BYTES_PER_ITERATION is the product sizeof(WordType) * W. + /// For example, ChaCha uses 16 each word32, and the value of + /// BYTES_PER_ITERATION is 64. Each invocation of the ChaCha block function + /// produces 64 bytes of keystream. + CRYPTOPP_CONSTANT(BYTES_PER_ITERATION = sizeof(WordType) * W); + + virtual ~AdditiveCipherConcretePolicy() {} + + /// \brief Provides data alignment requirements + /// \return data alignment requirements, in bytes + /// \details Internally, the default implementation returns 1. If the stream + /// cipher is implemented using an SSE2 ASM or intrinsics, then the value + /// returned is usually 16. + unsigned int GetAlignment() const {return GetAlignmentOf();} + + /// \brief Provides number of bytes operated upon during an iteration + /// \return bytes operated upon during an iteration, in bytes + /// \sa GetOptimalBlockSize() + unsigned int GetBytesPerIteration() const {return BYTES_PER_ITERATION;} + + /// \brief Provides buffer size based on iterations + /// \return the buffer size based on iterations, in bytes + unsigned int GetIterationsToBuffer() const {return X;} + + /// \brief Flag indicating + /// \return true if the stream can be generated independent of the + /// transformation input, false otherwise + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream() + bool CanOperateKeystream() const {return true;} + + /// \brief Operates the keystream + /// \param operation the operation with additional flags + /// \param output the output buffer + /// \param input the input buffer + /// \param iterationCount the number of iterations to perform on the input + /// \details OperateKeystream() will attempt to operate upon GetOptimalBlockSize() buffer, + /// which will be derived from GetBytesPerIteration(). + /// \sa CanOperateKeystream(), OperateKeystream(), WriteKeystream(), KeystreamOperation() + virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) =0; +}; + +/// \brief Helper macro to implement OperateKeystream +/// \param x KeystreamOperation mask +/// \param b Endian order +/// \param i index in output buffer +/// \param a value to output +#define CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, b, i, a) \ + PutWord(((x & OUTPUT_ALIGNED) != 0), b, output+i*sizeof(WordType), (x & INPUT_NULL) ? (a) : (a) ^ GetWord(((x & INPUT_ALIGNED) != 0), b, input+i*sizeof(WordType))); + +/// \brief Helper macro to implement OperateKeystream +/// \param x KeystreamOperation mask +/// \param i index in output buffer +/// \param a value to output +#define CRYPTOPP_KEYSTREAM_OUTPUT_XMM(x, i, a) {\ + __m128i t = (x & INPUT_NULL) ? a : _mm_xor_si128(a, (x & INPUT_ALIGNED) ? _mm_load_si128((__m128i *)input+i) : _mm_loadu_si128((__m128i *)input+i));\ + if (x & OUTPUT_ALIGNED) _mm_store_si128((__m128i *)output+i, t);\ + else _mm_storeu_si128((__m128i *)output+i, t);} + +/// \brief Helper macro to implement OperateKeystream +#define CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(x, y) \ + switch (operation) \ + { \ + case WRITE_KEYSTREAM: \ + x(EnumToInt(WRITE_KEYSTREAM)) \ + break; \ + case XOR_KEYSTREAM: \ + x(EnumToInt(XOR_KEYSTREAM)) \ + input += y; \ + break; \ + case XOR_KEYSTREAM_INPUT_ALIGNED: \ + x(EnumToInt(XOR_KEYSTREAM_INPUT_ALIGNED)) \ + input += y; \ + break; \ + case XOR_KEYSTREAM_OUTPUT_ALIGNED: \ + x(EnumToInt(XOR_KEYSTREAM_OUTPUT_ALIGNED)) \ + input += y; \ + break; \ + case WRITE_KEYSTREAM_ALIGNED: \ + x(EnumToInt(WRITE_KEYSTREAM_ALIGNED)) \ + break; \ + case XOR_KEYSTREAM_BOTH_ALIGNED: \ + x(EnumToInt(XOR_KEYSTREAM_BOTH_ALIGNED)) \ + input += y; \ + break; \ + } \ + output += y; + +/// \brief Base class for additive stream ciphers with SymmetricCipher interface +/// \tparam BASE AbstractPolicyHolder base class +template > +class CRYPTOPP_NO_VTABLE AdditiveCipherTemplate : public BASE, public RandomNumberGenerator +{ +public: + virtual ~AdditiveCipherTemplate() {} + AdditiveCipherTemplate() : m_leftOver(0) {} + + /// \brief Generate random array of bytes + /// \param output the byte buffer + /// \param size the length of the buffer, in bytes + /// \details All generated values are uniformly distributed over the range specified + /// within the constraints of a particular generator. + void GenerateBlock(byte *output, size_t size); + + /// \brief Apply keystream to data + /// \param outString a buffer to write the transformed data + /// \param inString a buffer to read the data + /// \param length the size of the buffers, in bytes + /// \details This is the primary method to operate a stream cipher. For example: + ///
+	///     size_t size = 30;
+	///     byte plain[size] = "Do or do not; there is no try";
+	///     byte cipher[size];
+	///     ...
+	///     ChaCha20 chacha(key, keySize);
+	///     chacha.ProcessData(cipher, plain, size);
+	/// 
+ /// \details You should use distinct buffers for inString and outString. If the buffers + /// are the same, then the data will be copied to an internal buffer to avoid GCC alias + /// violations. The internal copy will impact performance. + /// \sa Issue 1088, 36% loss + /// of performance with AES, Issue + /// 1010, HIGHT cipher troubles with FileSource + void ProcessData(byte *outString, const byte *inString, size_t length); + + /// \brief Resynchronize the cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param length the size of the IV array + void Resynchronize(const byte *iv, int length=-1); + + /// \brief Provides number of ideal bytes to process + /// \return the ideal number of bytes to process + /// \details Internally, the default implementation returns GetBytesPerIteration() + /// \sa GetBytesPerIteration() and GetOptimalNextBlockSize() + unsigned int OptimalBlockSize() const {return this->GetPolicy().GetOptimalBlockSize();} + + /// \brief Provides number of ideal bytes to process + /// \return the ideal number of bytes to process + /// \details Internally, the default implementation returns remaining unprocessed bytes + /// \sa GetBytesPerIteration() and OptimalBlockSize() + unsigned int GetOptimalNextBlockSize() const {return (unsigned int)this->m_leftOver;} + + /// \brief Provides number of ideal data alignment + /// \return the ideal data alignment, in bytes + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const {return this->GetPolicy().GetAlignment();} + + /// \brief Determines if the cipher is self inverting + /// \return true if the stream cipher is self inverting, false otherwise + bool IsSelfInverting() const {return true;} + + /// \brief Determines if the cipher is a forward transformation + /// \return true if the stream cipher is a forward transformation, false otherwise + bool IsForwardTransformation() const {return true;} + + /// \brief Flag indicating random access + /// \return true if the cipher is seekable, false otherwise + /// \sa Seek() + bool IsRandomAccess() const {return this->GetPolicy().CipherIsRandomAccess();} + + /// \brief Seeks to a random position in the stream + /// \param position the absolute position in the stream + /// \sa IsRandomAccess() + void Seek(lword position); + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2". + /// Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics + /// instead of ASM. + /// \details Algorithms which combine different instructions or ISAs provide the + /// dominant one. For example on x86 AES/GCM returns "AESNI" rather than + /// "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL". + /// \note Provider is not universally implemented yet. + std::string AlgorithmProvider() const { return this->GetPolicy().AlgorithmProvider(); } + + typedef typename BASE::PolicyInterface PolicyInterface; + +protected: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + + unsigned int GetBufferByteSize(const PolicyInterface &policy) const {return policy.GetBytesPerIteration() * policy.GetIterationsToBuffer();} + + inline byte * KeystreamBufferBegin() {return this->m_buffer.data();} + inline byte * KeystreamBufferEnd() {return (PtrAdd(this->m_buffer.data(), this->m_buffer.size()));} + + AlignedSecByteBlock m_buffer; + size_t m_leftOver; +}; + +/// \brief Policy object for feedback based stream ciphers +class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CFB_CipherAbstractPolicy +{ +public: + virtual ~CFB_CipherAbstractPolicy() {} + + /// \brief Provides data alignment requirements + /// \return data alignment requirements, in bytes + /// \details Internally, the default implementation returns 1. If the stream cipher is implemented + /// using an SSE2 ASM or intrinsics, then the value returned is usually 16. + virtual unsigned int GetAlignment() const =0; + + /// \brief Provides number of bytes operated upon during an iteration + /// \return bytes operated upon during an iteration, in bytes + /// \sa GetOptimalBlockSize() + virtual unsigned int GetBytesPerIteration() const =0; + + /// \brief Access the feedback register + /// \return pointer to the first byte of the feedback register + virtual byte * GetRegisterBegin() =0; + + /// \brief TODO + virtual void TransformRegister() =0; + + /// \brief Flag indicating iteration support + /// \return true if the cipher supports iteration, false otherwise + virtual bool CanIterate() const {return false;} + + /// \brief Iterate the cipher + /// \param output the output buffer + /// \param input the input buffer + /// \param dir the direction of the cipher + /// \param iterationCount the number of iterations to perform on the input + /// \sa IsSelfInverting() and IsForwardTransformation() + virtual void Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount) + {CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(input); CRYPTOPP_UNUSED(dir); + CRYPTOPP_UNUSED(iterationCount); CRYPTOPP_ASSERT(false); + throw Exception(Exception::OTHER_ERROR, "SimpleKeyingInterface: unexpected error");} + + /// \brief Key the cipher + /// \param params set of NameValuePairs use to initialize this object + /// \param key a byte array used to key the cipher + /// \param length the size of the key array + virtual void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) =0; + + /// \brief Resynchronize the cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param length the size of the IV array + virtual void CipherResynchronize(const byte *iv, size_t length) + {CRYPTOPP_UNUSED(iv); CRYPTOPP_UNUSED(length); + throw NotImplemented("SimpleKeyingInterface: this object doesn't support resynchronization");} + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2". + /// Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics + /// instead of ASM. + /// \details Algorithms which combine different instructions or ISAs provide the + /// dominant one. For example on x86 AES/GCM returns "AESNI" rather than + /// "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL". + /// \note Provider is not universally implemented yet. + virtual std::string AlgorithmProvider() const { return "C++"; } +}; + +/// \brief Base class for feedback based stream ciphers +/// \tparam WT word type +/// \tparam W count of words +/// \tparam BASE CFB_CipherAbstractPolicy derived base class +template +struct CRYPTOPP_NO_VTABLE CFB_CipherConcretePolicy : public BASE +{ + typedef WT WordType; + + virtual ~CFB_CipherConcretePolicy() {} + + /// \brief Provides data alignment requirements + /// \return data alignment requirements, in bytes + /// \details Internally, the default implementation returns 1. If the stream cipher is implemented + /// using an SSE2 ASM or intrinsics, then the value returned is usually 16. + unsigned int GetAlignment() const {return sizeof(WordType);} + + /// \brief Provides number of bytes operated upon during an iteration + /// \return bytes operated upon during an iteration, in bytes + /// \sa GetOptimalBlockSize() + unsigned int GetBytesPerIteration() const {return sizeof(WordType) * W;} + + /// \brief Flag indicating iteration support + /// \return true if the cipher supports iteration, false otherwise + bool CanIterate() const {return true;} + + /// \brief Perform one iteration in the forward direction + void TransformRegister() {this->Iterate(NULLPTR, NULLPTR, ENCRYPTION, 1);} + + /// \brief Provides alternate access to a feedback register + /// \tparam B enumeration indicating endianness + /// \details RegisterOutput() provides alternate access to the feedback register. The + /// enumeration B is BigEndian or LittleEndian. Repeatedly applying operator() + /// results in advancing in the register. + template + struct RegisterOutput + { + RegisterOutput(byte *output, const byte *input, CipherDir dir) + : m_output(output), m_input(input), m_dir(dir) {} + + /// \brief XOR feedback register with data + /// \param registerWord data represented as a word type + /// \return reference to the next feedback register word + inline RegisterOutput& operator()(WordType ®isterWord) + { + //CRYPTOPP_ASSERT(IsAligned(m_output)); + //CRYPTOPP_ASSERT(IsAligned(m_input)); + + if (!NativeByteOrderIs(B::ToEnum())) + registerWord = ByteReverse(registerWord); + + if (m_dir == ENCRYPTION) + { + if (m_input == NULLPTR) + { + CRYPTOPP_ASSERT(m_output == NULLPTR); + } + else + { + // WordType ct = *(const WordType *)m_input ^ registerWord; + WordType ct = GetWord(false, NativeByteOrder::ToEnum(), m_input) ^ registerWord; + registerWord = ct; + + // *(WordType*)m_output = ct; + PutWord(false, NativeByteOrder::ToEnum(), m_output, ct); + + m_input += sizeof(WordType); + m_output += sizeof(WordType); + } + } + else + { + // WordType ct = *(const WordType *)m_input; + WordType ct = GetWord(false, NativeByteOrder::ToEnum(), m_input); + + // *(WordType*)m_output = registerWord ^ ct; + PutWord(false, NativeByteOrder::ToEnum(), m_output, registerWord ^ ct); + registerWord = ct; + + m_input += sizeof(WordType); + m_output += sizeof(WordType); + } + + // registerWord is left unreversed so it can be xor-ed with further input + + return *this; + } + + byte *m_output; + const byte *m_input; + CipherDir m_dir; + }; +}; + +/// \brief Base class for feedback based stream ciphers with SymmetricCipher interface +/// \tparam BASE AbstractPolicyHolder base class +template +class CRYPTOPP_NO_VTABLE CFB_CipherTemplate : public BASE +{ +public: + virtual ~CFB_CipherTemplate() {} + CFB_CipherTemplate() : m_leftOver(0) {} + + /// \brief Apply keystream to data + /// \param outString a buffer to write the transformed data + /// \param inString a buffer to read the data + /// \param length the size of the buffers, in bytes + /// \details This is the primary method to operate a stream cipher. For example: + ///
+	///     size_t size = 30;
+	///     byte plain[size] = "Do or do not; there is no try";
+	///     byte cipher[size];
+	///     ...
+	///     ChaCha20 chacha(key, keySize);
+	///     chacha.ProcessData(cipher, plain, size);
+	/// 
+ /// \details You should use distinct buffers for inString and outString. If the buffers + /// are the same, then the data will be copied to an internal buffer to avoid GCC alias + /// violations. The internal copy will impact performance. + /// \sa Issue 1088, 36% loss + /// of performance with AES, Issue + /// 1010, HIGHT cipher troubles with FileSource + void ProcessData(byte *outString, const byte *inString, size_t length); + + /// \brief Resynchronize the cipher + /// \param iv a byte array used to resynchronize the cipher + /// \param length the size of the IV array + void Resynchronize(const byte *iv, int length=-1); + + /// \brief Provides number of ideal bytes to process + /// \return the ideal number of bytes to process + /// \details Internally, the default implementation returns GetBytesPerIteration() + /// \sa GetBytesPerIteration() and GetOptimalNextBlockSize() + unsigned int OptimalBlockSize() const {return this->GetPolicy().GetBytesPerIteration();} + + /// \brief Provides number of ideal bytes to process + /// \return the ideal number of bytes to process + /// \details Internally, the default implementation returns remaining unprocessed bytes + /// \sa GetBytesPerIteration() and OptimalBlockSize() + unsigned int GetOptimalNextBlockSize() const {return (unsigned int)m_leftOver;} + + /// \brief Provides number of ideal data alignment + /// \return the ideal data alignment, in bytes + /// \sa GetAlignment() and OptimalBlockSize() + unsigned int OptimalDataAlignment() const {return this->GetPolicy().GetAlignment();} + + /// \brief Flag indicating random access + /// \return true if the cipher is seekable, false otherwise + /// \sa Seek() + bool IsRandomAccess() const {return false;} + + /// \brief Determines if the cipher is self inverting + /// \return true if the stream cipher is self inverting, false otherwise + bool IsSelfInverting() const {return false;} + + /// \brief Retrieve the provider of this algorithm + /// \return the algorithm provider + /// \details The algorithm provider can be a name like "C++", "SSE", "NEON", "AESNI", + /// "ARMv8" and "Power8". C++ is standard C++ code. Other labels, like SSE, + /// usually indicate a specialized implementation using instructions from a higher + /// instruction set architecture (ISA). Future labels may include external hardware + /// like a hardware security module (HSM). + /// \details Generally speaking Wei Dai's original IA-32 ASM code falls under "SSE2". + /// Labels like "SSSE3" and "SSE4.1" follow after Wei's code and use intrinsics + /// instead of ASM. + /// \details Algorithms which combine different instructions or ISAs provide the + /// dominant one. For example on x86 AES/GCM returns "AESNI" rather than + /// "CLMUL" or "AES+SSE4.1" or "AES+CLMUL" or "AES+SSE4.1+CLMUL". + /// \note Provider is not universally implemented yet. + std::string AlgorithmProvider() const { return this->GetPolicy().AlgorithmProvider(); } + + typedef typename BASE::PolicyInterface PolicyInterface; + +protected: + virtual void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length) =0; + + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); + + size_t m_leftOver; +}; + +/// \brief Base class for feedback based stream ciphers in the forward direction with SymmetricCipher interface +/// \tparam BASE AbstractPolicyHolder base class +template > +class CRYPTOPP_NO_VTABLE CFB_EncryptionTemplate : public CFB_CipherTemplate +{ + bool IsForwardTransformation() const {return true;} + void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length); +}; + +/// \brief Base class for feedback based stream ciphers in the reverse direction with SymmetricCipher interface +/// \tparam BASE AbstractPolicyHolder base class +template > +class CRYPTOPP_NO_VTABLE CFB_DecryptionTemplate : public CFB_CipherTemplate +{ + bool IsForwardTransformation() const {return false;} + void CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length); +}; + +/// \brief Base class for feedback based stream ciphers with a mandatory block size +/// \tparam BASE CFB_EncryptionTemplate or CFB_DecryptionTemplate base class +template +class CFB_RequireFullDataBlocks : public BASE +{ +public: + unsigned int MandatoryBlockSize() const {return this->OptimalBlockSize();} +}; + +/// \brief SymmetricCipher implementation +/// \tparam BASE AbstractPolicyHolder derived base class +/// \tparam INFO AbstractPolicyHolder derived information class +/// \sa Weak::ARC4, ChaCha8, ChaCha12, ChaCha20, Salsa20, SEAL, Sosemanuk, WAKE +template +class SymmetricCipherFinal : public AlgorithmImpl, INFO> +{ +public: + virtual ~SymmetricCipherFinal() {} + + /// \brief Construct a stream cipher + SymmetricCipherFinal() {} + + /// \brief Construct a stream cipher + /// \param key a byte array used to key the cipher + /// \details This overload uses DEFAULT_KEYLENGTH + SymmetricCipherFinal(const byte *key) + {this->SetKey(key, this->DEFAULT_KEYLENGTH);} + + /// \brief Construct a stream cipher + /// \param key a byte array used to key the cipher + /// \param length the size of the key array + SymmetricCipherFinal(const byte *key, size_t length) + {this->SetKey(key, length);} + + /// \brief Construct a stream cipher + /// \param key a byte array used to key the cipher + /// \param length the size of the key array + /// \param iv a byte array used as an initialization vector + SymmetricCipherFinal(const byte *key, size_t length, const byte *iv) + {this->SetKeyWithIV(key, length, iv);} + + /// \brief Clone a SymmetricCipher + /// \return a new SymmetricCipher based on this object + Clonable * Clone() const {return static_cast(new SymmetricCipherFinal(*this));} +}; + +NAMESPACE_END + +// Used by dll.cpp to ensure objects are in dll.o, and not strciphr.o. +#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES +# include "strciphr.cpp" +#endif + +NAMESPACE_BEGIN(CryptoPP) + +CRYPTOPP_DLL_TEMPLATE_CLASS AbstractPolicyHolder; +CRYPTOPP_DLL_TEMPLATE_CLASS AdditiveCipherTemplate >; + +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_CipherTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_EncryptionTemplate >; +CRYPTOPP_DLL_TEMPLATE_CLASS CFB_DecryptionTemplate >; + +NAMESPACE_END + +#if CRYPTOPP_MSC_VERSION +# pragma warning(pop) +#endif + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/tea.h b/third_party/cryptoppwin/include/cryptopp/tea.h new file mode 100644 index 00000000..e4ba5df3 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/tea.h @@ -0,0 +1,161 @@ +// tea.h - originally written and placed in the public domain by Wei Dai + +/// \file tea.h +/// \brief Classes for the TEA, BTEA and XTEA block ciphers + +#ifndef CRYPTOPP_TEA_H +#define CRYPTOPP_TEA_H + +#include "seckey.h" +#include "secblock.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief TEA block cipher information +struct TEA_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public VariableRounds<32> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "TEA";} +}; + +/// \brief TEA block cipher +/// \sa TEA +class TEA : public TEA_Info, public BlockCipherDocumentation +{ + /// \brief TEA block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeSecBlock m_k; + word32 m_limit; + }; + + /// \brief TEA block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief TEA block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef TEA::Encryption TEAEncryption; +typedef TEA::Decryption TEADecryption; + +/// \brief XTEA block cipher information +struct XTEA_Info : public FixedBlockSize<8>, public FixedKeyLength<16>, public VariableRounds<32> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "XTEA";} +}; + +/// \brief XTEA block cipher +/// \sa XTEA +class XTEA : public XTEA_Info, public BlockCipherDocumentation +{ + /// \brief XTEA block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + FixedSizeSecBlock m_k; + word32 m_limit; + }; + + /// \brief XTEA block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief XTEA block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +/// \brief BTEA block cipher information +struct BTEA_Info : public FixedKeyLength<16> +{ + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "BTEA";} +}; + +/// \brief BTEA block cipher +/// \details Corrected Block TEA as described in "xxtea". This class hasn't been tested yet. +/// \sa Correction to xtea and +/// Corrected Block TEA. +class BTEA : public BTEA_Info, public BlockCipherDocumentation +{ + /// \brief BTEA block cipher default operation + class CRYPTOPP_NO_VTABLE Base : public AlgorithmImpl, BTEA_Info> + { + public: + void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) + { + CRYPTOPP_UNUSED(length), CRYPTOPP_UNUSED(params); + m_blockSize = params.GetIntValueWithDefault("BlockSize", 60*4); + GetUserKey(BIG_ENDIAN_ORDER, m_k.begin(), 4, key, KEYLENGTH); + } + + unsigned int BlockSize() const {return m_blockSize;} + + protected: + FixedSizeSecBlock m_k; + unsigned int m_blockSize; + }; + + /// \brief BTEA block cipher encryption operation + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief BTEA block cipher decryption operation + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/threefish.h b/third_party/cryptoppwin/include/cryptopp/threefish.h new file mode 100644 index 00000000..ab32ce01 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/threefish.h @@ -0,0 +1,201 @@ +// threefish.h - written and placed in the public domain by Jeffrey Walton +// Based on public domain code by Keru Kuro. Kuro's code is +// available at http://cppcrypto.sourceforge.net/. + +/// \file Threefish.h +/// \brief Classes for the Threefish block cipher +/// \since Crypto++ 6.0 + +#ifndef CRYPTOPP_THREEFISH_H +#define CRYPTOPP_THREEFISH_H + +#include "config.h" +#include "seckey.h" +#include "secblock.h" +#include "algparam.h" +#include "argnames.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Threefish block cipher information +/// \tparam BS block size of the cipher, in bytes +/// \since Crypto++ 6.0 +template +struct Threefish_Info : public FixedBlockSize, FixedKeyLength +{ + static const std::string StaticAlgorithmName() + { + // Format is Cipher-Blocksize(Keylength) + return "Threefish-" + IntToString(BS*8) + "(" + IntToString(BS*8) + ")"; + } +}; + +/// \brief Threefish block cipher base class +/// \tparam BS block size of the cipher, in bytes +/// \details User code should use Threefish256, Threefish512, Threefish1024 +/// \sa Threefish256, Threefish512, Threefish1024, Threefish +/// \since Crypto++ 6.0 +template +struct CRYPTOPP_NO_VTABLE Threefish_Base +{ + virtual ~Threefish_Base() {} + + void SetTweak(const NameValuePairs ¶ms) + { + m_tweak.New(3); + ConstByteArrayParameter t; + if (params.GetValue(Name::Tweak(), t)) + { + // Tweak size is fixed at 16 for Threefish + CRYPTOPP_ASSERT(t.size() == 16); + GetUserKey(LITTLE_ENDIAN_ORDER, m_tweak.begin(), 2, t.begin(), 16); + m_tweak[2] = m_tweak[0] ^ m_tweak[1]; + } + else + { + std::memset(m_tweak.begin(), 0x00, 24); + } + } + + typedef SecBlock > AlignedSecBlock64; + mutable AlignedSecBlock64 m_wspace; // workspace + AlignedSecBlock64 m_rkey; // keys + AlignedSecBlock64 m_tweak; +}; + +/// \brief Threefish 256-bit block cipher +/// \details Threefish256 provides 256-bit block size. The valid key size is 256-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa Threefish512, Threefish1024, Threefish +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE Threefish256 : public Threefish_Info<32>, public BlockCipherDocumentation +{ +public: + /// \brief Threefish block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : public Threefish_Base<32>, public BlockCipherImpl > + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Threefish256::Encryption Threefish256Encryption; +typedef Threefish256::Decryption Threefish256Decryption; + +/// \brief Threefish 512-bit block cipher +/// \details Threefish512 provides 512-bit block size. The valid key size is 512-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa Threefish256, Threefish1024, Threefish +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE Threefish512 : public Threefish_Info<64>, public BlockCipherDocumentation +{ +public: + /// \brief Threefish block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : public Threefish_Base<64>, public BlockCipherImpl > + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Decryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Threefish512::Encryption Threefish512Encryption; +typedef Threefish512::Decryption Threefish512Decryption; + +/// \brief Threefish 1024-bit block cipher +/// \details Threefish1024 provides 1024-bit block size. The valid key size is 1024-bit. +/// \note Crypto++ provides a byte oriented implementation +/// \sa Threefish256, Threefish512, Threefish +/// \since Crypto++ 6.0 +class CRYPTOPP_NO_VTABLE Threefish1024 : public Threefish_Info<128>, public BlockCipherDocumentation +{ +public: + /// \brief Threefish block cipher transformation functions + /// \details Provides implementation common to encryption and decryption + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Base : public Threefish_Base<128>, public BlockCipherImpl > + { + protected: + void UncheckedSetKey(const byte *userKey, unsigned int keyLength, const NameValuePairs ¶ms); + }; + + /// \brief Encryption transformation + /// \details Enc provides implementation for encryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Enc : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + /// \brief Encryption transformation + /// \details Dec provides implementation for decryption transformation. All key and block + /// sizes are supported. + /// \since Crypto++ 6.0 + class CRYPTOPP_NO_VTABLE Dec : public Base + { + protected: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Threefish1024::Encryption Threefish1024Encryption; +typedef Threefish1024::Decryption Threefish1024Decryption; + +NAMESPACE_END + +#endif // CRYPTOPP_THREEFISH_H diff --git a/third_party/cryptoppwin/include/cryptopp/tiger.h b/third_party/cryptoppwin/include/cryptopp/tiger.h new file mode 100644 index 00000000..369f1ccd --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/tiger.h @@ -0,0 +1,61 @@ +// tiger.h - originally written and placed in the public domain by Wei Dai + +/// \file tiger.h +/// \brief Classes for the Tiger message digest +/// \details Crypto++ provides the original Tiger hash that was +/// submitted to the NESSIE project. The implementation is different +/// from the revised Tiger2 hash. +/// \sa Tiger and +/// Tiger: +/// A Fast New Cryptographic Hash Function +/// \since Crypto++ 2.1 + +#ifndef CRYPTOPP_TIGER_H +#define CRYPTOPP_TIGER_H + +#include "config.h" +#include "iterhash.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_TIGER_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Tiger message digest +/// \details Crypto++ provides the original Tiger hash that was +/// submitted to the NESSIE project. The implementation is different +/// from the revised Tiger2 hash. +/// \sa Tiger and +/// Tiger: +/// A Fast New Cryptographic Hash Function +/// \since Crypto++ 2.1 +class Tiger : public IteratedHashWithStaticTransform +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Tiger";} + std::string AlgorithmProvider() const; + + /// \brief Initialize state array + /// \param state the state of the hash + static void InitState(HashWordType *state); + /// \brief Operate the hash + /// \param digest the state of the hash + /// \param data the data to be digested + static void Transform(word64 *digest, const word64 *data); + /// \brief Computes the hash of the current message + /// \param digest a pointer to the buffer to receive the hash + /// \param digestSize the size of the truncated digest, in bytes + /// \details TruncatedFinal() calls Final() and then copies digestSize bytes to digest. + /// The hash is restarted the hash for the next message. + void TruncatedFinal(byte *digest, size_t digestSize); + +protected: + static const word64 table[4*256+3]; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/trap.h b/third_party/cryptoppwin/include/cryptopp/trap.h new file mode 100644 index 00000000..2c2906b9 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/trap.h @@ -0,0 +1,163 @@ +// trap.h - written and placed in public domain by Jeffrey Walton. + +/// \file trap.h +/// \brief Debugging and diagnostic assertions +/// \details CRYPTOPP_ASSERT is the library's debugging and diagnostic +/// assertion. CRYPTOPP_ASSERT is enabled by CRYPTOPP_DEBUG, +/// DEBUG or _DEBUG. +/// \details CRYPTOPP_ASSERT raises a SIGTRAP (Unix) or calls +/// DebugBreak() (Windows). +/// \details CRYPTOPP_ASSERT is only in effect when the user requests a +/// debug configuration. NDEBUG (or failure to define it) does not +/// affect CRYPTOPP_ASSERT. +/// \since Crypto++ 5.6.5 +/// \sa DebugTrapHandler, Issue 277, +/// CVE-2016-7420 + +#ifndef CRYPTOPP_TRAP_H +#define CRYPTOPP_TRAP_H + +#include "config.h" + +#if defined(CRYPTOPP_DEBUG) +# include +# include +# if defined(UNIX_SIGNALS_AVAILABLE) +# include "ossig.h" +# elif defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(__CYGWIN__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); +# endif +#endif // CRYPTOPP_DEBUG + +// ************** run-time assertion *************** + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Debugging and diagnostic assertion +/// \details CRYPTOPP_ASSERT is the library's debugging and diagnostic +/// assertion. CRYPTOPP_ASSERT is enabled by the preprocessor macros +/// CRYPTOPP_DEBUG, DEBUG or _DEBUG. +/// \details CRYPTOPP_ASSERT raises a SIGTRAP (Unix) or calls +/// DebugBreak() (Windows). CRYPTOPP_ASSERT is only in effect +/// when the user explicitly requests a debug configuration. +/// \details If you want to ensure CRYPTOPP_ASSERT is inert, then do +/// not define CRYPTOPP_DEBUG, DEBUG or _DEBUG. +/// Avoiding the defines means CRYPTOPP_ASSERT is preprocessed into an +/// empty string. +/// \details The traditional Posix define NDEBUG has no effect on +/// CRYPTOPP_DEBUG, CRYPTOPP_ASSERT or DebugTrapHandler. +/// \details An example of using CRYPTOPP_ASSERT and DebugTrapHandler is shown +/// below. The library's test program, cryptest.exe (from test.cpp), +/// exercises the structure: +///
+///   \#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
+///   static const DebugTrapHandler g_dummyHandler;
+///   \#endif
+///
+///   int main(int argc, char* argv[])
+///   {
+///      CRYPTOPP_ASSERT(argv != nullptr);
+///      ...
+///   }
+///  
+/// \since Crypto++ 5.6.5 +/// \sa DebugTrapHandler, SignalHandler, Issue 277, +/// CVE-2016-7420 +# define CRYPTOPP_ASSERT(exp) { ... } +#endif + +#if defined(CRYPTOPP_DEBUG) +# if defined(UNIX_SIGNALS_AVAILABLE) || defined(__CYGWIN__) +# define CRYPTOPP_ASSERT(exp) { \ + if (!(exp)) { \ + std::ostringstream oss; \ + oss << "Assertion failed: " << __FILE__ << "(" \ + << __LINE__ << "): " << __func__ \ + << std::endl; \ + std::cout << std::flush; \ + std::cerr << oss.str(); \ + raise(SIGTRAP); \ + } \ + } +# elif CRYPTOPP_DEBUG && defined(CRYPTOPP_WIN32_AVAILABLE) +# define CRYPTOPP_ASSERT(exp) { \ + if (!(exp)) { \ + std::ostringstream oss; \ + oss << "Assertion failed: " << __FILE__ << "(" \ + << __LINE__ << "): " << __FUNCTION__ \ + << std::endl; \ + std::cout << std::flush; \ + std::cerr << oss.str(); \ + if (IsDebuggerPresent()) {DebugBreak();} \ + } \ + } +# endif // Unix or Windows +#endif // CRYPTOPP_DEBUG + +// Remove CRYPTOPP_ASSERT in non-debug builds. +#ifndef CRYPTOPP_ASSERT +# define CRYPTOPP_ASSERT(exp) (void)0 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +// ************** SIGTRAP handler *************** + +#if (CRYPTOPP_DEBUG && defined(UNIX_SIGNALS_AVAILABLE)) || defined(CRYPTOPP_DOXYGEN_PROCESSING) +/// \brief Default SIGTRAP handler +/// \details DebugTrapHandler() can be used by a program to install an empty +/// SIGTRAP handler. If present, the handler ensures there is a signal +/// handler in place for SIGTRAP raised by +/// CRYPTOPP_ASSERT. If CRYPTOPP_ASSERT raises +/// SIGTRAP without a handler, then one of two things can +/// occur. First, the OS might allow the program to continue. Second, the OS +/// might terminate the program. OS X allows the program to continue, while +/// some Linuxes terminate the program. +/// \details If DebugTrapHandler detects another handler in place, then it will +/// not install a handler. This ensures a debugger can gain control of the +/// SIGTRAP signal without contention. It also allows multiple +/// DebugTrapHandler to be created without contentious or unusual behavior. +/// Though multiple DebugTrapHandler can be created, a program should only +/// create one, if needed. +/// \details A DebugTrapHandler is subject to C++ static initialization +/// [dis]order. If you need to install a handler and it must be installed +/// early, then reference the code associated with +/// CRYPTOPP_INIT_PRIORITY in cryptlib.cpp and cpu.cpp. +/// \details If you want to ensure CRYPTOPP_ASSERT is inert, then +/// do not define CRYPTOPP_DEBUG, DEBUG or +/// _DEBUG. Avoiding the defines means CRYPTOPP_ASSERT +/// is processed into ((void)0). +/// \details The traditional Posix define NDEBUG has no effect on +/// CRYPTOPP_DEBUG, CRYPTOPP_ASSERT or DebugTrapHandler. +/// \details An example of using \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT" and +/// DebugTrapHandler is shown below. The library's test program, +/// cryptest.exe (from test.cpp), exercises the structure: +///
+///   \#if defined(CRYPTOPP_DEBUG) && defined(UNIX_SIGNALS_AVAILABLE)
+///   const DebugTrapHandler g_dummyHandler;
+///   \#endif
+///
+///   int main(int argc, char* argv[])
+///   {
+///      CRYPTOPP_ASSERT(argv != nullptr);
+///      ...
+///   }
+///  
+/// \since Crypto++ 5.6.5 +/// \sa \ref CRYPTOPP_ASSERT "CRYPTOPP_ASSERT", SignalHandler, Issue 277, +/// CVE-2016-7420 + +#if defined(CRYPTOPP_DOXYGEN_PROCESSING) +class DebugTrapHandler : public SignalHandler { }; +#else +typedef SignalHandler DebugTrapHandler; +#endif + +#endif // Linux, Unix and Documentation + +NAMESPACE_END + +#endif // CRYPTOPP_TRAP_H diff --git a/third_party/cryptoppwin/include/cryptopp/trunhash.h b/third_party/cryptoppwin/include/cryptopp/trunhash.h new file mode 100644 index 00000000..e659cc87 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/trunhash.h @@ -0,0 +1,63 @@ +// trunhash.h - originally written and placed in the public domain by Wei Dai + +/// \file trunhash.h +/// \brief Classes for truncated hashes + +#ifndef CRYPTOPP_TRUNHASH_H +#define CRYPTOPP_TRUNHASH_H + +#include "cryptlib.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Null hash +/// \details A null hash that conforms to HashTransformation interface +class NullHash : public HashTransformation +{ +public: + void Update(const byte *input, size_t length) + {CRYPTOPP_UNUSED(input);CRYPTOPP_UNUSED(length);} + unsigned int DigestSize() const + {return 0;} + void TruncatedFinal(byte *digest, size_t digestSize) + {CRYPTOPP_UNUSED(digest);CRYPTOPP_UNUSED(digestSize);} + bool TruncatedVerify(const byte *digest, size_t digestLength) + {CRYPTOPP_UNUSED(digest);CRYPTOPP_UNUSED(digestLength);return true;} +}; + +/// \brief Construct new HashModule with smaller digest size from an existing one +/// \tparam T HashTransformation derived class +template +class TruncatedHashTemplate : public HashTransformation +{ +public: + /// \brief Construct a TruncatedHashTemplate + TruncatedHashTemplate(T hm, unsigned int digestSize) + : m_hm(hm), m_digestSize(digestSize) {} + /// \brief Construct a TruncatedHashTemplate + TruncatedHashTemplate(const byte *key, size_t keyLength, unsigned int digestSize) + : m_hm(key, keyLength), m_digestSize(digestSize) {} + /// \brief Construct a TruncatedHashTemplate + TruncatedHashTemplate(size_t digestSize) + : m_digestSize(digestSize) {} + + void Restart() + {m_hm.Restart();} + void Update(const byte *input, size_t length) + {m_hm.Update(input, length);} + unsigned int DigestSize() const {return m_digestSize;} + void TruncatedFinal(byte *digest, size_t digestSize) + {m_hm.TruncatedFinal(digest, digestSize);} + bool TruncatedVerify(const byte *digest, size_t digestLength) + {return m_hm.TruncatedVerify(digest, digestLength);} + +private: + T m_hm; + unsigned int m_digestSize; +}; + +typedef TruncatedHashTemplate TruncatedHashModule; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/ttmac.h b/third_party/cryptoppwin/include/cryptopp/ttmac.h new file mode 100644 index 00000000..9d959875 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/ttmac.h @@ -0,0 +1,44 @@ +// ttmac.h - written and placed in the public domain by Kevin Springle + +/// \file ttmac.h +/// \brief Classes for the TTMAC message authentication code + +#ifndef CRYPTOPP_TTMAC_H +#define CRYPTOPP_TTMAC_H + +#include "seckey.h" +#include "iterhash.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief TTMAC message authentication code information +class CRYPTOPP_NO_VTABLE TTMAC_Base : public FixedKeyLength<20>, public IteratedHash +{ +public: + static std::string StaticAlgorithmName() {return std::string("Two-Track-MAC");} + CRYPTOPP_CONSTANT(DIGESTSIZE=20); + + unsigned int DigestSize() const {return DIGESTSIZE;}; + void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms); + void TruncatedFinal(byte *mac, size_t size); + +protected: + static void Transform (word32 *digest, const word32 *X, bool last); + void HashEndianCorrectedBlock(const word32 *data) {Transform(m_digest, data, false);} + void Init(); + word32* StateBuf() {return m_digest;} + + FixedSizeSecBlock m_digest; + FixedSizeSecBlock m_key; +}; + +/// \brief Two-Track-MAC message authentication code +/// \tparam T HashTransformation class +/// \details 160-bit MAC with 160-bit key +/// \sa MessageAuthenticationCode(), Two-Track-MAC +DOCUMENTED_TYPEDEF(MessageAuthenticationCodeFinal, TTMAC); + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/tweetnacl.h b/third_party/cryptoppwin/include/cryptopp/tweetnacl.h new file mode 100644 index 00000000..beafb752 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/tweetnacl.h @@ -0,0 +1,281 @@ +// tweetnacl.h - written and placed in the public domain by Jeffrey Walton + +/// \file nr.h +/// \brief Declarations for Bernstein's TweetNaCL +/// \details TweetNaCL is used to cross-validate the library's implementations. +/// The implementation itself is not optimized and kind of amusing. However +/// it serves a valuable purpose for cross-validation. +/// \details Don't use this in production. + +#ifndef TWEETNACL_H +#define TWEETNACL_H +#define crypto_auth_PRIMITIVE "hmacsha512256" +#define crypto_auth crypto_auth_hmacsha512256 +#define crypto_auth_verify crypto_auth_hmacsha512256_verify +#define crypto_auth_BYTES crypto_auth_hmacsha512256_BYTES +#define crypto_auth_KEYBYTES crypto_auth_hmacsha512256_KEYBYTES +#define crypto_auth_IMPLEMENTATION crypto_auth_hmacsha512256_IMPLEMENTATION +#define crypto_auth_VERSION crypto_auth_hmacsha512256_VERSION +#define crypto_auth_hmacsha512256_tweet_BYTES 32 +#define crypto_auth_hmacsha512256_tweet_KEYBYTES 32 +extern int crypto_auth_hmacsha512256_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); +extern int crypto_auth_hmacsha512256_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); +#define crypto_auth_hmacsha512256_tweet_VERSION "-" +#define crypto_auth_hmacsha512256 crypto_auth_hmacsha512256_tweet +#define crypto_auth_hmacsha512256_verify crypto_auth_hmacsha512256_tweet_verify +#define crypto_auth_hmacsha512256_BYTES crypto_auth_hmacsha512256_tweet_BYTES +#define crypto_auth_hmacsha512256_KEYBYTES crypto_auth_hmacsha512256_tweet_KEYBYTES +#define crypto_auth_hmacsha512256_VERSION crypto_auth_hmacsha512256_tweet_VERSION +#define crypto_auth_hmacsha512256_IMPLEMENTATION "crypto_auth/hmacsha512256/tweet" +#define crypto_box_PRIMITIVE "curve25519xsalsa20poly1305" +#define crypto_box crypto_box_curve25519xsalsa20poly1305 +#define crypto_box_open crypto_box_curve25519xsalsa20poly1305_open +#define crypto_box_keypair crypto_box_curve25519xsalsa20poly1305_keypair +#define crypto_box_beforenm crypto_box_curve25519xsalsa20poly1305_beforenm +#define crypto_box_afternm crypto_box_curve25519xsalsa20poly1305_afternm +#define crypto_box_open_afternm crypto_box_curve25519xsalsa20poly1305_open_afternm +#define crypto_box_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES +#define crypto_box_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES +#define crypto_box_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES +#define crypto_box_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_NONCEBYTES +#define crypto_box_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_ZEROBYTES +#define crypto_box_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES +#define crypto_box_IMPLEMENTATION crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION +#define crypto_box_VERSION crypto_box_curve25519xsalsa20poly1305_VERSION +#define crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES 32 +#define crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES 32 +#define crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES 32 +#define crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES 24 +#define crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES 32 +#define crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES 16 +extern int crypto_box_curve25519xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_keypair(unsigned char *,unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_beforenm(unsigned char *,const unsigned char *,const unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +#define crypto_box_curve25519xsalsa20poly1305_tweet_VERSION "-" +#define crypto_box_curve25519xsalsa20poly1305 crypto_box_curve25519xsalsa20poly1305_tweet +#define crypto_box_curve25519xsalsa20poly1305_open crypto_box_curve25519xsalsa20poly1305_tweet_open +#define crypto_box_curve25519xsalsa20poly1305_keypair crypto_box_curve25519xsalsa20poly1305_tweet_keypair +#define crypto_box_curve25519xsalsa20poly1305_beforenm crypto_box_curve25519xsalsa20poly1305_tweet_beforenm +#define crypto_box_curve25519xsalsa20poly1305_afternm crypto_box_curve25519xsalsa20poly1305_tweet_afternm +#define crypto_box_curve25519xsalsa20poly1305_open_afternm crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm +#define crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES +#define crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES +#define crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES +#define crypto_box_curve25519xsalsa20poly1305_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES +#define crypto_box_curve25519xsalsa20poly1305_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES +#define crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES +#define crypto_box_curve25519xsalsa20poly1305_VERSION crypto_box_curve25519xsalsa20poly1305_tweet_VERSION +#define crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION "crypto_box/curve25519xsalsa20poly1305/tweet" +#define crypto_core_PRIMITIVE "salsa20" +#define crypto_core crypto_core_salsa20 +#define crypto_core_OUTPUTBYTES crypto_core_salsa20_OUTPUTBYTES +#define crypto_core_INPUTBYTES crypto_core_salsa20_INPUTBYTES +#define crypto_core_KEYBYTES crypto_core_salsa20_KEYBYTES +#define crypto_core_CONSTBYTES crypto_core_salsa20_CONSTBYTES +#define crypto_core_IMPLEMENTATION crypto_core_salsa20_IMPLEMENTATION +#define crypto_core_VERSION crypto_core_salsa20_VERSION +#define crypto_core_salsa20_tweet_OUTPUTBYTES 64 +#define crypto_core_salsa20_tweet_INPUTBYTES 16 +#define crypto_core_salsa20_tweet_KEYBYTES 32 +#define crypto_core_salsa20_tweet_CONSTBYTES 16 +extern int crypto_core_salsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *); +#define crypto_core_salsa20_tweet_VERSION "-" +#define crypto_core_salsa20 crypto_core_salsa20_tweet +#define crypto_core_salsa20_OUTPUTBYTES crypto_core_salsa20_tweet_OUTPUTBYTES +#define crypto_core_salsa20_INPUTBYTES crypto_core_salsa20_tweet_INPUTBYTES +#define crypto_core_salsa20_KEYBYTES crypto_core_salsa20_tweet_KEYBYTES +#define crypto_core_salsa20_CONSTBYTES crypto_core_salsa20_tweet_CONSTBYTES +#define crypto_core_salsa20_VERSION crypto_core_salsa20_tweet_VERSION +#define crypto_core_salsa20_IMPLEMENTATION "crypto_core/salsa20/tweet" +#define crypto_core_hsalsa20_tweet_OUTPUTBYTES 32 +#define crypto_core_hsalsa20_tweet_INPUTBYTES 16 +#define crypto_core_hsalsa20_tweet_KEYBYTES 32 +#define crypto_core_hsalsa20_tweet_CONSTBYTES 16 +extern int crypto_core_hsalsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *); +#define crypto_core_hsalsa20_tweet_VERSION "-" +#define crypto_core_hsalsa20 crypto_core_hsalsa20_tweet +#define crypto_core_hsalsa20_OUTPUTBYTES crypto_core_hsalsa20_tweet_OUTPUTBYTES +#define crypto_core_hsalsa20_INPUTBYTES crypto_core_hsalsa20_tweet_INPUTBYTES +#define crypto_core_hsalsa20_KEYBYTES crypto_core_hsalsa20_tweet_KEYBYTES +#define crypto_core_hsalsa20_CONSTBYTES crypto_core_hsalsa20_tweet_CONSTBYTES +#define crypto_core_hsalsa20_VERSION crypto_core_hsalsa20_tweet_VERSION +#define crypto_core_hsalsa20_IMPLEMENTATION "crypto_core/hsalsa20/tweet" +#define crypto_hashblocks_PRIMITIVE "sha512" +#define crypto_hashblocks crypto_hashblocks_sha512 +#define crypto_hashblocks_STATEBYTES crypto_hashblocks_sha512_STATEBYTES +#define crypto_hashblocks_BLOCKBYTES crypto_hashblocks_sha512_BLOCKBYTES +#define crypto_hashblocks_IMPLEMENTATION crypto_hashblocks_sha512_IMPLEMENTATION +#define crypto_hashblocks_VERSION crypto_hashblocks_sha512_VERSION +#define crypto_hashblocks_sha512_tweet_STATEBYTES 64 +#define crypto_hashblocks_sha512_tweet_BLOCKBYTES 128 +extern int crypto_hashblocks_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long); +#define crypto_hashblocks_sha512_tweet_VERSION "-" +#define crypto_hashblocks_sha512 crypto_hashblocks_sha512_tweet +#define crypto_hashblocks_sha512_STATEBYTES crypto_hashblocks_sha512_tweet_STATEBYTES +#define crypto_hashblocks_sha512_BLOCKBYTES crypto_hashblocks_sha512_tweet_BLOCKBYTES +#define crypto_hashblocks_sha512_VERSION crypto_hashblocks_sha512_tweet_VERSION +#define crypto_hashblocks_sha512_IMPLEMENTATION "crypto_hashblocks/sha512/tweet" +#define crypto_hashblocks_sha256_tweet_STATEBYTES 32 +#define crypto_hashblocks_sha256_tweet_BLOCKBYTES 64 +extern int crypto_hashblocks_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long); +#define crypto_hashblocks_sha256_tweet_VERSION "-" +#define crypto_hashblocks_sha256 crypto_hashblocks_sha256_tweet +#define crypto_hashblocks_sha256_STATEBYTES crypto_hashblocks_sha256_tweet_STATEBYTES +#define crypto_hashblocks_sha256_BLOCKBYTES crypto_hashblocks_sha256_tweet_BLOCKBYTES +#define crypto_hashblocks_sha256_VERSION crypto_hashblocks_sha256_tweet_VERSION +#define crypto_hashblocks_sha256_IMPLEMENTATION "crypto_hashblocks/sha256/tweet" +#define crypto_hash_PRIMITIVE "sha512" +#define crypto_hash crypto_hash_sha512 +#define crypto_hash_BYTES crypto_hash_sha512_BYTES +#define crypto_hash_IMPLEMENTATION crypto_hash_sha512_IMPLEMENTATION +#define crypto_hash_VERSION crypto_hash_sha512_VERSION +#define crypto_hash_sha512_tweet_BYTES 64 +extern int crypto_hash_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long); +#define crypto_hash_sha512_tweet_VERSION "-" +#define crypto_hash_sha512 crypto_hash_sha512_tweet +#define crypto_hash_sha512_BYTES crypto_hash_sha512_tweet_BYTES +#define crypto_hash_sha512_VERSION crypto_hash_sha512_tweet_VERSION +#define crypto_hash_sha512_IMPLEMENTATION "crypto_hash/sha512/tweet" +#define crypto_hash_sha256_tweet_BYTES 32 +extern int crypto_hash_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long); +#define crypto_hash_sha256_tweet_VERSION "-" +#define crypto_hash_sha256 crypto_hash_sha256_tweet +#define crypto_hash_sha256_BYTES crypto_hash_sha256_tweet_BYTES +#define crypto_hash_sha256_VERSION crypto_hash_sha256_tweet_VERSION +#define crypto_hash_sha256_IMPLEMENTATION "crypto_hash/sha256/tweet" +#define crypto_onetimeauth_PRIMITIVE "poly1305" +#define crypto_onetimeauth crypto_onetimeauth_poly1305 +#define crypto_onetimeauth_verify crypto_onetimeauth_poly1305_verify +#define crypto_onetimeauth_BYTES crypto_onetimeauth_poly1305_BYTES +#define crypto_onetimeauth_KEYBYTES crypto_onetimeauth_poly1305_KEYBYTES +#define crypto_onetimeauth_IMPLEMENTATION crypto_onetimeauth_poly1305_IMPLEMENTATION +#define crypto_onetimeauth_VERSION crypto_onetimeauth_poly1305_VERSION +#define crypto_onetimeauth_poly1305_tweet_BYTES 16 +#define crypto_onetimeauth_poly1305_tweet_KEYBYTES 32 +extern int crypto_onetimeauth_poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); +extern int crypto_onetimeauth_poly1305_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); +#define crypto_onetimeauth_poly1305_tweet_VERSION "-" +#define crypto_onetimeauth_poly1305 crypto_onetimeauth_poly1305_tweet +#define crypto_onetimeauth_poly1305_verify crypto_onetimeauth_poly1305_tweet_verify +#define crypto_onetimeauth_poly1305_BYTES crypto_onetimeauth_poly1305_tweet_BYTES +#define crypto_onetimeauth_poly1305_KEYBYTES crypto_onetimeauth_poly1305_tweet_KEYBYTES +#define crypto_onetimeauth_poly1305_VERSION crypto_onetimeauth_poly1305_tweet_VERSION +#define crypto_onetimeauth_poly1305_IMPLEMENTATION "crypto_onetimeauth/poly1305/tweet" +#define crypto_scalarmult_PRIMITIVE "curve25519" +#define crypto_scalarmult crypto_scalarmult_curve25519 +#define crypto_scalarmult_base crypto_scalarmult_curve25519_base +#define crypto_scalarmult_BYTES crypto_scalarmult_curve25519_BYTES +#define crypto_scalarmult_SCALARBYTES crypto_scalarmult_curve25519_SCALARBYTES +#define crypto_scalarmult_IMPLEMENTATION crypto_scalarmult_curve25519_IMPLEMENTATION +#define crypto_scalarmult_VERSION crypto_scalarmult_curve25519_VERSION +#define crypto_scalarmult_curve25519_tweet_BYTES 32 +#define crypto_scalarmult_curve25519_tweet_SCALARBYTES 32 +extern int crypto_scalarmult_curve25519_tweet(unsigned char *,const unsigned char *,const unsigned char *); +extern int crypto_scalarmult_curve25519_tweet_base(unsigned char *,const unsigned char *); +#define crypto_scalarmult_curve25519_tweet_VERSION "-" +#define crypto_scalarmult_curve25519 crypto_scalarmult_curve25519_tweet +#define crypto_scalarmult_curve25519_base crypto_scalarmult_curve25519_tweet_base +#define crypto_scalarmult_curve25519_BYTES crypto_scalarmult_curve25519_tweet_BYTES +#define crypto_scalarmult_curve25519_SCALARBYTES crypto_scalarmult_curve25519_tweet_SCALARBYTES +#define crypto_scalarmult_curve25519_VERSION crypto_scalarmult_curve25519_tweet_VERSION +#define crypto_scalarmult_curve25519_IMPLEMENTATION "crypto_scalarmult/curve25519/tweet" +#define crypto_secretbox_PRIMITIVE "xsalsa20poly1305" +#define crypto_secretbox crypto_secretbox_xsalsa20poly1305 +#define crypto_secretbox_open crypto_secretbox_xsalsa20poly1305_open +#define crypto_secretbox_KEYBYTES crypto_secretbox_xsalsa20poly1305_KEYBYTES +#define crypto_secretbox_NONCEBYTES crypto_secretbox_xsalsa20poly1305_NONCEBYTES +#define crypto_secretbox_ZEROBYTES crypto_secretbox_xsalsa20poly1305_ZEROBYTES +#define crypto_secretbox_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES +#define crypto_secretbox_IMPLEMENTATION crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION +#define crypto_secretbox_VERSION crypto_secretbox_xsalsa20poly1305_VERSION +#define crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES 32 +#define crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES 24 +#define crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES 32 +#define crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES 16 +extern int crypto_secretbox_xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +extern int crypto_secretbox_xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +#define crypto_secretbox_xsalsa20poly1305_tweet_VERSION "-" +#define crypto_secretbox_xsalsa20poly1305 crypto_secretbox_xsalsa20poly1305_tweet +#define crypto_secretbox_xsalsa20poly1305_open crypto_secretbox_xsalsa20poly1305_tweet_open +#define crypto_secretbox_xsalsa20poly1305_KEYBYTES crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES +#define crypto_secretbox_xsalsa20poly1305_NONCEBYTES crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES +#define crypto_secretbox_xsalsa20poly1305_ZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES +#define crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES +#define crypto_secretbox_xsalsa20poly1305_VERSION crypto_secretbox_xsalsa20poly1305_tweet_VERSION +#define crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION "crypto_secretbox/xsalsa20poly1305/tweet" +#define crypto_sign_PRIMITIVE "ed25519" +#define crypto_sign crypto_sign_ed25519 +#define crypto_sign_open crypto_sign_ed25519_open +#define crypto_sign_keypair crypto_sign_ed25519_keypair +#define crypto_sign_BYTES crypto_sign_ed25519_BYTES +#define crypto_sign_PUBLICKEYBYTES crypto_sign_ed25519_PUBLICKEYBYTES +#define crypto_sign_SECRETKEYBYTES crypto_sign_ed25519_SECRETKEYBYTES +#define crypto_sign_IMPLEMENTATION crypto_sign_ed25519_IMPLEMENTATION +#define crypto_sign_VERSION crypto_sign_ed25519_VERSION +#define crypto_sign_ed25519_tweet_BYTES 64 +#define crypto_sign_ed25519_tweet_PUBLICKEYBYTES 32 +#define crypto_sign_ed25519_tweet_SECRETKEYBYTES 64 +extern int crypto_sign_ed25519_tweet(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); +extern int crypto_sign_ed25519_tweet_open(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); +extern int crypto_sign_ed25519_tweet_keypair(unsigned char *,unsigned char *); +#define crypto_sign_ed25519_tweet_VERSION "-" +#define crypto_sign_ed25519 crypto_sign_ed25519_tweet +#define crypto_sign_ed25519_open crypto_sign_ed25519_tweet_open +#define crypto_sign_ed25519_keypair crypto_sign_ed25519_tweet_keypair +#define crypto_sign_ed25519_BYTES crypto_sign_ed25519_tweet_BYTES +#define crypto_sign_ed25519_PUBLICKEYBYTES crypto_sign_ed25519_tweet_PUBLICKEYBYTES +#define crypto_sign_ed25519_SECRETKEYBYTES crypto_sign_ed25519_tweet_SECRETKEYBYTES +#define crypto_sign_ed25519_VERSION crypto_sign_ed25519_tweet_VERSION +#define crypto_sign_ed25519_IMPLEMENTATION "crypto_sign/ed25519/tweet" +#define crypto_stream_PRIMITIVE "xsalsa20" +#define crypto_stream crypto_stream_xsalsa20 +#define crypto_stream_xor crypto_stream_xsalsa20_xor +#define crypto_stream_KEYBYTES crypto_stream_xsalsa20_KEYBYTES +#define crypto_stream_NONCEBYTES crypto_stream_xsalsa20_NONCEBYTES +#define crypto_stream_IMPLEMENTATION crypto_stream_xsalsa20_IMPLEMENTATION +#define crypto_stream_VERSION crypto_stream_xsalsa20_VERSION +#define crypto_stream_xsalsa20_tweet_KEYBYTES 32 +#define crypto_stream_xsalsa20_tweet_NONCEBYTES 24 +extern int crypto_stream_xsalsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +extern int crypto_stream_xsalsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +#define crypto_stream_xsalsa20_tweet_VERSION "-" +#define crypto_stream_xsalsa20 crypto_stream_xsalsa20_tweet +#define crypto_stream_xsalsa20_xor crypto_stream_xsalsa20_tweet_xor +#define crypto_stream_xsalsa20_KEYBYTES crypto_stream_xsalsa20_tweet_KEYBYTES +#define crypto_stream_xsalsa20_NONCEBYTES crypto_stream_xsalsa20_tweet_NONCEBYTES +#define crypto_stream_xsalsa20_VERSION crypto_stream_xsalsa20_tweet_VERSION +#define crypto_stream_xsalsa20_IMPLEMENTATION "crypto_stream/xsalsa20/tweet" +#define crypto_stream_salsa20_tweet_KEYBYTES 32 +#define crypto_stream_salsa20_tweet_NONCEBYTES 8 +extern int crypto_stream_salsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +extern int crypto_stream_salsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +#define crypto_stream_salsa20_tweet_VERSION "-" +#define crypto_stream_salsa20 crypto_stream_salsa20_tweet +#define crypto_stream_salsa20_xor crypto_stream_salsa20_tweet_xor +#define crypto_stream_salsa20_KEYBYTES crypto_stream_salsa20_tweet_KEYBYTES +#define crypto_stream_salsa20_NONCEBYTES crypto_stream_salsa20_tweet_NONCEBYTES +#define crypto_stream_salsa20_VERSION crypto_stream_salsa20_tweet_VERSION +#define crypto_stream_salsa20_IMPLEMENTATION "crypto_stream/salsa20/tweet" +#define crypto_verify_PRIMITIVE "16" +#define crypto_verify crypto_verify_16 +#define crypto_verify_BYTES crypto_verify_16_BYTES +#define crypto_verify_IMPLEMENTATION crypto_verify_16_IMPLEMENTATION +#define crypto_verify_VERSION crypto_verify_16_VERSION +#define crypto_verify_16_tweet_BYTES 16 +extern int crypto_verify_16_tweet(const unsigned char *,const unsigned char *); +#define crypto_verify_16_tweet_VERSION "-" +#define crypto_verify_16 crypto_verify_16_tweet +#define crypto_verify_16_BYTES crypto_verify_16_tweet_BYTES +#define crypto_verify_16_VERSION crypto_verify_16_tweet_VERSION +#define crypto_verify_16_IMPLEMENTATION "crypto_verify/16/tweet" +#define crypto_verify_32_tweet_BYTES 32 +extern int crypto_verify_32_tweet(const unsigned char *,const unsigned char *); +#define crypto_verify_32_tweet_VERSION "-" +#define crypto_verify_32 crypto_verify_32_tweet +#define crypto_verify_32_BYTES crypto_verify_32_tweet_BYTES +#define crypto_verify_32_VERSION crypto_verify_32_tweet_VERSION +#define crypto_verify_32_IMPLEMENTATION "crypto_verify/32/tweet" +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/twofish.h b/third_party/cryptoppwin/include/cryptopp/twofish.h new file mode 100644 index 00000000..cf289028 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/twofish.h @@ -0,0 +1,64 @@ +// twofish.h - originally written and placed in the public domain by Wei Dai + +/// \file twofish.h +/// \brief Classes for the Twofish block cipher + +#ifndef CRYPTOPP_TWOFISH_H +#define CRYPTOPP_TWOFISH_H + +#include "seckey.h" +#include "secblock.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Twofish block cipher information +/// \since Crypto++ 3.1 +struct Twofish_Info : public FixedBlockSize<16>, public VariableKeyLength<16, 16, 32, 8>, FixedRounds<16> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Twofish";} +}; + +/// \brief Twofish block cipher +/// \sa Twofish +/// \since Crypto++ 3.1 +class Twofish : public Twofish_Info, public BlockCipherDocumentation +{ + class CRYPTOPP_NO_VTABLE Base : public BlockCipherImpl + { + public: + void UncheckedSetKey(const byte *userKey, unsigned int length, const NameValuePairs ¶ms); + + protected: + static word32 h0(word32 x, const word32 *key, unsigned int kLen); + static word32 h(word32 x, const word32 *key, unsigned int kLen); + + static const byte q[2][256]; + static const word32 mds[4][256]; + + FixedSizeSecBlock m_k; + FixedSizeSecBlock m_s; + }; + + class CRYPTOPP_NO_VTABLE Enc : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + + class CRYPTOPP_NO_VTABLE Dec : public Base + { + public: + void ProcessAndXorBlock(const byte *inBlock, const byte *xorBlock, byte *outBlock) const; + }; + +public: + typedef BlockCipherFinal Encryption; + typedef BlockCipherFinal Decryption; +}; + +typedef Twofish::Encryption TwofishEncryption; +typedef Twofish::Decryption TwofishDecryption; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/validate.h b/third_party/cryptoppwin/include/cryptopp/validate.h new file mode 100644 index 00000000..17474b52 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/validate.h @@ -0,0 +1,395 @@ +// validate.h - originally written and placed in the public domain by Wei Dai +// CryptoPP::Test namespace added by JW in February 2017 + +#ifndef CRYPTOPP_VALIDATE_H +#define CRYPTOPP_VALIDATE_H + +#include "cryptlib.h" +#include "misc.h" +#include "files.h" +#include "argnames.h" +#include "algparam.h" +#include "hex.h" + +#include +#include +#include +#include +#include + +NAMESPACE_BEGIN(CryptoPP) +NAMESPACE_BEGIN(Test) + +// A hint to help locate TestData/ and TestVectors/ after install. Due to +// execve the path can be malicious. If the path is ficticous then we move +// onto the next potential path. Also note we only read from the path; we +// never write through it. Storage for the string is in test.cpp. +extern std::string g_argvPathHint; + +bool ValidateAll(bool thorough); +bool TestSettings(); +bool TestOS_RNG(); +// bool TestSecRandom(); +bool TestRandomPool(); +#if !defined(NO_OS_DEPENDENCE) +bool TestAutoSeededX917(); +#endif +#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64) +bool TestRDRAND(); +bool TestRDSEED(); +bool TestPadlockRNG(); +#endif +#if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64) +bool TestDARN(); +#endif +bool ValidateBaseCode(); +bool ValidateEncoder(); +bool ValidateCRC32(); +bool ValidateCRC32C(); +bool ValidateAdler32(); +bool ValidateMD2(); +bool ValidateMD4(); +bool ValidateMD5(); +bool ValidateSHA(); +bool ValidateSHA2(); +bool ValidateSHA3(); +bool ValidateSHAKE(); // output <= r, where r is blocksize +bool ValidateSHAKE_XOF(); // output > r, needs hand crafted tests +bool ValidateKeccak(); +bool ValidateTiger(); +bool ValidateRIPEMD(); +bool ValidatePanama(); +bool ValidateWhirlpool(); +bool ValidateLSH(); + +bool ValidateSM3(); +bool ValidateBLAKE2s(); +bool ValidateBLAKE2b(); +bool ValidatePoly1305(); +bool ValidateSipHash(); + +bool ValidateHMAC(); +bool ValidateTTMAC(); + +bool ValidateCipherModes(); +bool ValidatePBKDF(); +bool ValidateHKDF(); +bool ValidateScrypt(); + +bool ValidateDES(); +bool ValidateIDEA(); +bool ValidateSAFER(); +bool ValidateRC2(); +bool ValidateARC4(); + +bool ValidateRC5(); +bool ValidateBlowfish(); +bool ValidateBlowfishCompat(); +bool ValidateThreeWay(); +bool ValidateGOST(); +bool ValidateSHARK(); +bool ValidateSEAL(); +bool ValidateCAST(); +bool ValidateSquare(); +bool ValidateSKIPJACK(); +bool ValidateRC6(); +bool ValidateMARS(); +bool ValidateRijndael(); +bool ValidateTwofish(); +bool ValidateSerpent(); +bool ValidateSHACAL2(); +bool ValidateARIA(); +bool ValidateSIMECK(); +bool ValidateCHAM(); +bool ValidateHIGHT(); +bool ValidateLEA(); +bool ValidateSIMON(); +bool ValidateSPECK(); +bool ValidateCamellia(); + +bool ValidateHC128(); +bool ValidateHC256(); +bool ValidateRabbit(); +bool ValidateSalsa(); +bool ValidateChaCha(); +bool ValidateChaChaTLS(); +bool ValidateSosemanuk(); + +bool ValidateVMAC(); +bool ValidateCCM(); +bool ValidateGCM(); +bool ValidateXTS(); +bool ValidateCMAC(); + +bool ValidateBBS(); +bool ValidateDH(); +bool ValidateMQV(); +bool ValidateHMQV(); +bool ValidateFHMQV(); +bool ValidateRSA(); +bool ValidateElGamal(); +bool ValidateDLIES(); +bool ValidateNR(); +bool ValidateDSA(bool thorough); +bool ValidateLUC(); +bool ValidateLUC_DL(); +bool ValidateLUC_DH(); +bool ValidateXTR_DH(); +bool ValidateRabin(); +bool ValidateRW(); +bool ValidateECP(); +bool ValidateEC2N(); +bool ValidateECDSA(); +bool ValidateECDSA_RFC6979(); +bool ValidateECGDSA(bool thorough); +bool ValidateESIGN(); + +bool ValidateHashDRBG(); +bool ValidateHmacDRBG(); + +bool TestX25519(); +bool TestEd25519(); +bool ValidateX25519(); +bool ValidateEd25519(); +bool ValidateNaCl(); + +// If CRYPTOPP_DEBUG or CRYPTOPP_COVERAGE is in effect, then perform additional tests +#if (defined(CRYPTOPP_DEBUG) || defined(CRYPTOPP_COVERAGE)) && !defined(CRYPTOPP_IMPORTS) +# define CRYPTOPP_EXTENDED_VALIDATION 1 +#endif + +#if defined(CRYPTOPP_EXTENDED_VALIDATION) +// http://github.com/weidai11/cryptopp/issues/92 +bool TestSecBlock(); +// http://github.com/weidai11/cryptopp/issues/64 +bool TestPolynomialMod2(); +// http://github.com/weidai11/cryptopp/issues/336 +bool TestIntegerBitops(); +// http://github.com/weidai11/cryptopp/issues/602 +bool TestIntegerOps(); +// http://github.com/weidai11/cryptopp/issues/360 +bool TestRounding(); +// http://github.com/weidai11/cryptopp/issues/242 +bool TestHuffmanCodes(); +// http://github.com/weidai11/cryptopp/issues/346 +bool TestASN1Parse(); +bool TestASN1Functions(); +// https://github.com/weidai11/cryptopp/pull/334 +bool TestStringSink(); +// Additional tests due to no coverage +bool TestCompressors(); +bool TestEncryptors(); +bool TestMersenne(); +bool TestSharing(); +# if defined(CRYPTOPP_ALTIVEC_AVAILABLE) +bool TestAltivecOps(); +# endif +#endif + +class FixedRNG : public RandomNumberGenerator +{ +public: + FixedRNG(BufferedTransformation &source) : m_source(source) {} + + void GenerateBlock(byte *output, size_t size) + { + m_source.Get(output, size); + } + +private: + BufferedTransformation &m_source; +}; + +// Safer functions on Windows for C&A, http://github.com/weidai11/cryptopp/issues/55 +inline std::string TimeToString(const time_t& t) +{ +#if (CRYPTOPP_MSC_VERSION >= 1400) + tm localTime; + char timeBuf[64]; + errno_t err; + + err = ::localtime_s(&localTime, &t); + CRYPTOPP_ASSERT(err == 0); + err = ::asctime_s(timeBuf, sizeof(timeBuf), &localTime); + CRYPTOPP_ASSERT(err == 0); + + std::string str(err == 0 ? timeBuf : ""); +#elif defined(__MINGW32__) || defined(__MINGW64__) + char* timeString = ::asctime(::localtime(&t)); + std::string str(timeString ? timeString : ""); +#elif (_POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || defined(_POSIX_SOURCE)) + tm localTime; + char timeBuf[64]; + char* timeString = ::asctime_r(::localtime_r(&t, &localTime), timeBuf); + std::string str(timeString ? timeString : ""); +#else + char* timeString = ::asctime(::localtime(&t)); + std::string str(timeString ? timeString : ""); +#endif + + // Cleanup whitespace + std::string::size_type pos = 0; + while (!str.empty() && std::isspace(str[str.length()-1])) + {str.erase(str.end()-1);} + while (!str.empty() && std::string::npos != (pos = str.find(" ", pos))) + {str.erase(pos, 1);} + + return str; +} + +// Coverity finding +template +inline T StringToValue(const std::string& str) +{ + std::istringstream iss(str); + + // Arbitrary, but we need to clear a Coverity finding TAINTED_SCALAR + if (iss.str().length() > 25) + throw InvalidArgument(str + "' is too long"); + + T value; + iss >> std::noskipws >> value; + + // Use fail(), not bad() + if (iss.fail()) + throw InvalidArgument(str + "' is not a value"); + + if (NON_NEGATIVE && value < 0) + throw InvalidArgument(str + "' is negative"); + + return value; +} + +// Coverity finding +template<> +inline int StringToValue(const std::string& str) +{ + Integer n(str.c_str()); + long l = n.ConvertToLong(); + + int r; + if (!SafeConvert(l, r)) + throw InvalidArgument(str + "' is not an integer value"); + + return r; +} + +inline std::string AddSeparator(std::string str) +{ + if (str.empty()) return ""; + const char last = str[str.length()-1]; + if (last != '/' && last != '\\') + return str + "/"; + return str; +} + +// Use CRYPTOPP_DATA_DIR last. The problem this sidesteps is, finding an +// old version of Crypto++ library in CRYPTOPP_DATA_DIR when the library +// has been staged in DESTDIR. Using CRYPTOPP_DATA_DIR first only works +// as expected when CRYPTOPP_DATA_DIR is empty before an install. We +// encountered this problem rather quickly during testing of Crypto++ 8.1 +// when Crypto++ 8.0 was installed locally. It took some time to realize +// where the old test data was coming from. +static std::string GetDataDir() +{ + std::ifstream file; + std::string name, filename = "TestData/usage.dat"; + +#ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH + // Look in $ORIGIN/../share/. This is likely a Linux install directory. + name = AddSeparator(g_argvPathHint) + std::string("../share/cryptopp/") + filename; + file.open(name.c_str()); + if (file.is_open()) + return AddSeparator(g_argvPathHint) + std::string("../share/cryptopp/"); +#endif +#ifndef CRYPTOPP_DISABLE_DATA_DIR_SEARCH + // Look in current working directory + name = AddSeparator(g_argvPathHint) + filename; + file.open(name.c_str()); + if (file.is_open()) + return AddSeparator(g_argvPathHint); +#endif +#ifdef CRYPTOPP_DATA_DIR + // Honor CRYPTOPP_DATA_DIR. This is likely an install directory if it is not "./". + name = AddSeparator(CRYPTOPP_DATA_DIR) + filename; + file.open(name.c_str()); + if (file.is_open()) + return AddSeparator(CRYPTOPP_DATA_DIR); +#endif + return "./"; +} + +inline std::string DataDir(const std::string& filename) +{ + std::string name; + std::ifstream file; + +#if CRYPTOPP_CXX11_STATIC_INIT + static std::string path = AddSeparator(GetDataDir()); + name = path + filename; + file.open(name.c_str()); + if (file.is_open()) + return name; +#else + // Avoid static initialization problems + name = AddSeparator(GetDataDir()) + filename; + file.open(name.c_str()); + if (file.is_open()) + return name; +#endif + + // This will cause the expected exception in the caller + return filename; +} + +// Definition in test.cpp +RandomNumberGenerator& GlobalRNG(); + +// Definition in datatest.cpp +bool RunTestDataFile(const char *filename, const NameValuePairs &overrideParameters=g_nullNameValuePairs, bool thorough=true); + +// Definitions in validat6.cpp +bool CryptoSystemValidate(PK_Decryptor &priv, PK_Encryptor &pub, bool thorough = false); +bool SimpleKeyAgreementValidate(SimpleKeyAgreementDomain &d); +bool AuthenticatedKeyAgreementWithRolesValidate(AuthenticatedKeyAgreementDomain &initiator, AuthenticatedKeyAgreementDomain &recipient); +bool AuthenticatedKeyAgreementValidate(AuthenticatedKeyAgreementDomain &d); +bool SignatureValidate(PK_Signer &priv, PK_Verifier &pub, bool thorough = false); + +// Miscellaneous PK definitions in validat6.cpp +// Key Agreement definitions in validat7.cpp +// Encryption and Decryption definitions in validat8.cpp +// Sign and Verify definitions in validat9.cpp + +bool ValidateECP(); +bool ValidateEC2N(); + +bool ValidateRSA_Encrypt(); +bool ValidateRSA_Sign(); + +bool ValidateLUC_Encrypt(); +bool ValidateLUC_Sign(); + +bool ValidateLUC_DL_Encrypt(); +bool ValidateLUC_DL_Sign(); + +bool ValidateRabin_Encrypt(); +bool ValidateRabin_Sign(); + +bool ValidateECP(); +bool ValidateECP_Agreement(); +bool ValidateECP_Encrypt(); +bool ValidateECP_Sign(); + +bool ValidateECP_Legacy_Encrypt(); +bool ValidateEC2N_Legacy_Encrypt(); +bool ValidateECP_NULLDigest_Encrypt(); + +bool ValidateEC2N(); +bool ValidateEC2N_Agreement(); +bool ValidateEC2N_Encrypt(); +bool ValidateEC2N_Sign(); + +NAMESPACE_END // Test +NAMESPACE_END // CryptoPP + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/vmac.h b/third_party/cryptoppwin/include/cryptopp/vmac.h new file mode 100644 index 00000000..2da1c7fc --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/vmac.h @@ -0,0 +1,91 @@ +// vmac.h - originally written and placed in the public domain by Wei Dai + +/// \file vmac.h +/// \brief Classes for the VMAC message authentication code +/// \since Crypto++ 5.5 + +#ifndef CRYPTOPP_VMAC_H +#define CRYPTOPP_VMAC_H + +#include "cryptlib.h" +#include "iterhash.h" +#include "seckey.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_VMAC_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief VMAC message authentication code base class +/// \since Crypto++ 5.5 +class VMAC_Base : public IteratedHashBase +{ +public: + std::string AlgorithmName() const {return std::string("VMAC(") + GetCipher().AlgorithmName() + ")-" + IntToString(DigestSize()*8);} + std::string AlgorithmProvider() const {return GetCipher().AlgorithmProvider();} + unsigned int IVSize() const {return GetCipher().BlockSize();} + unsigned int MinIVLength() const {return 1;} + void Resynchronize(const byte *nonce, int length=-1); + void GetNextIV(RandomNumberGenerator &rng, byte *IV); + unsigned int DigestSize() const {return m_is128 ? 16 : 8;}; + void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms); + void TruncatedFinal(byte *mac, size_t size); + unsigned int BlockSize() const {return m_L1KeyLength;} + ByteOrder GetByteOrder() const {return LITTLE_ENDIAN_ORDER;} + unsigned int OptimalDataAlignment() const; + +protected: + virtual BlockCipher & AccessCipher() =0; + virtual int DefaultDigestSize() const =0; + const BlockCipher & GetCipher() const {return const_cast(this)->AccessCipher();} + void HashEndianCorrectedBlock(const word64 *data); + size_t HashMultipleBlocks(const word64 *input, size_t length); + void Init() {} + word64* StateBuf() {return NULLPTR;} + word64* DataBuf() {return (word64 *)(void*)m_data();} + + void VHASH_Update_SSE2(const word64 *data, size_t blocksRemainingInWord64, int tagPart); + template + void VHASH_Update_Template(const word64 *data, size_t blockRemainingInWord128); + void VHASH_Update(const word64 *data, size_t blocksRemainingInWord128); + + CRYPTOPP_BLOCK_1(polyState, word64, (m_is128 ? 8 : 4)) + CRYPTOPP_BLOCK_2(nhKey, word64, m_L1KeyLength/sizeof(word64) + 2*m_is128) + CRYPTOPP_BLOCK_3(data, byte, m_L1KeyLength) + CRYPTOPP_BLOCK_4(l3Key, word64, (m_is128 ? 4 : 2)) + CRYPTOPP_BLOCK_5(nonce, byte, IVSize()) + CRYPTOPP_BLOCK_6(pad, byte, IVSize()) + CRYPTOPP_BLOCKS_END(6) + + bool m_is128, m_padCached, m_isFirstBlock; + unsigned int m_L1KeyLength; +}; + +/// \brief VMAC message authentication code +/// \tparam T_BlockCipher block cipher +/// \tparam T_DigestBitSize digest size, in bits +/// \details VMAC is a block cipher-based message authentication code algorithm +/// using a universal hash proposed by Ted Krovetz and Wei Dai in April 2007. The +/// algorithm was designed for high performance backed by a formal analysis. +/// \details The implementation is based on Ted Krovetz's public domain vmac.c +/// and draft-krovetz-vmac-01.txt. +/// \sa VMAC. +/// \since Crypto++ 5.5 +template +class VMAC : public SimpleKeyingInterfaceImpl > +{ +public: + static std::string StaticAlgorithmName() {return std::string("VMAC(") + T_BlockCipher::StaticAlgorithmName() + ")-" + IntToString(T_DigestBitSize);} + +private: + BlockCipher & AccessCipher() {return m_cipher;} + int DefaultDigestSize() const {return T_DigestBitSize/8;} + typename T_BlockCipher::Encryption m_cipher; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/wake.h b/third_party/cryptoppwin/include/cryptopp/wake.h new file mode 100644 index 00000000..616cbf1a --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/wake.h @@ -0,0 +1,59 @@ +// wake.h - originally written and placed in the public domain by Wei Dai + +/// \file wake.h +/// \brief Classes for WAKE stream cipher + +#ifndef CRYPTOPP_WAKE_H +#define CRYPTOPP_WAKE_H + +#include "seckey.h" +#include "secblock.h" +#include "strciphr.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief WAKE stream cipher information +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 1.0 +template +struct WAKE_OFB_Info : public FixedKeyLength<32> +{ + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return B::ToEnum() == LITTLE_ENDIAN_ORDER ? "WAKE-OFB-LE" : "WAKE-OFB-BE";} +}; + +class CRYPTOPP_NO_VTABLE WAKE_Base +{ +protected: + word32 M(word32 x, word32 y); + void GenKey(word32 k0, word32 k1, word32 k2, word32 k3); + + word32 t[257]; + word32 r3, r4, r5, r6; +}; + +/// \brief WAKE stream cipher operation +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 1.0 +template +class CRYPTOPP_NO_VTABLE WAKE_Policy : public AdditiveCipherConcretePolicy, protected WAKE_Base +{ +protected: + void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); + // OFB + void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount); + bool CipherIsRandomAccess() const {return false;} +}; + +/// \brief WAKE stream cipher +/// \tparam B Endianness of the stream cipher +/// \since Crypto++ 1.0 +template +struct WAKE_OFB : public WAKE_OFB_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal, AdditiveCipherTemplate<> >, WAKE_OFB_Info > Encryption; + typedef Encryption Decryption; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/whrlpool.h b/third_party/cryptoppwin/include/cryptopp/whrlpool.h new file mode 100644 index 00000000..d5b202fd --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/whrlpool.h @@ -0,0 +1,42 @@ +// whrlpool.h - originally modified by Kevin Springle from Paulo Barreto and Vincent Rijmen's +// public domain code, whirlpool.c. Updated to Whirlpool version 3.0, optimized +// and SSE version added by WD. All modifications are placed in the public domain. + +#ifndef CRYPTOPP_WHIRLPOOL_H +#define CRYPTOPP_WHIRLPOOL_H + +/// \file whrlpool.h +/// \brief Classes for the Whirlpool message digest +/// \details Crypto++ provides version 3.0 of the Whirlpool algorithm. +/// This version of the algorithm was submitted for ISO standardization. + +#include "config.h" +#include "iterhash.h" + +// Clang 3.3 integrated assembler crash on Linux. Clang 3.4 due to compiler +// error with .intel_syntax, http://llvm.org/bugs/show_bug.cgi?id=24232 +#if CRYPTOPP_BOOL_X32 || defined(CRYPTOPP_DISABLE_MIXED_ASM) +# define CRYPTOPP_DISABLE_WHIRLPOOL_ASM 1 +#endif + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Whirlpool message digest +/// \details Crypto++ provides version 3.0 of the Whirlpool algorithm. +/// This version of the algorithm was submitted for ISO standardization. +/// \since Crypto++ 5.2 +/// \sa Whirlpool +class Whirlpool : public IteratedHashWithStaticTransform +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "Whirlpool";} + std::string AlgorithmProvider() const; + + static void InitState(HashWordType *state); + static void Transform(word64 *digest, const word64 *data); + void TruncatedFinal(byte *hash, size_t size); +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/words.h b/third_party/cryptoppwin/include/cryptopp/words.h new file mode 100644 index 00000000..a7ac1995 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/words.h @@ -0,0 +1,225 @@ +// words.h - originally written and placed in the public domain by Wei Dai + +/// \file words.h +/// \brief Support functions for word operations + +#ifndef CRYPTOPP_WORDS_H +#define CRYPTOPP_WORDS_H + +#include "config.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Count the number of words +/// \param x word array +/// \param n size of the word array, in elements +/// \return number of words used in the array. +/// \details CountWords counts the number of words in a word array. +/// Leading 0-words are not included in the count. +/// \since Crypto++ 1.0 +inline size_t CountWords(const word *x, size_t n) +{ + while (n && x[n-1]==0) + n--; + return n; +} + +/// \brief Set the value of words +/// \param r word array +/// \param a value +/// \param n size of the word array, in elements +/// \details SetWords sets all elements in the word array to the +/// specified value. +/// \since Crypto++ 1.0 +inline void SetWords(word *r, word a, size_t n) +{ + for (size_t i=0; i> (WORD_BITS-shiftBits); + } + return carry; +} + +/// \brief Right shift word array +/// \param r word array +/// \param n size of the word array, in elements +/// \param shiftBits number of bits to shift +/// \return word shifted out +/// \details ShiftWordsRightByBits shifts the word array shight by +/// shiftBits. ShiftWordsRightByBits shifts bits out on the right. +/// \note shiftBits must be less than WORD_BITS. +/// \since Crypto++ 1.0 +inline word ShiftWordsRightByBits(word *r, size_t n, unsigned int shiftBits) +{ + CRYPTOPP_ASSERT (shiftBits0; i--) + { + u = r[i-1]; + r[i-1] = (u >> shiftBits) | carry; + carry = u << (WORD_BITS-shiftBits); + } + return carry; +} + +/// \brief Left shift word array +/// \param r word array +/// \param n size of the word array, in elements +/// \param shiftWords number of words to shift +/// \details ShiftWordsLeftByWords shifts the word array left by +/// shiftWords. ShiftWordsLeftByWords shifts bits out on the left; +/// it does not extend the array. +/// \since Crypto++ 1.0 +inline void ShiftWordsLeftByWords(word *r, size_t n, size_t shiftWords) +{ + shiftWords = STDMIN(shiftWords, n); + if (shiftWords) + { + for (size_t i=n-1; i>=shiftWords; i--) + r[i] = r[i-shiftWords]; + SetWords(r, 0, shiftWords); + } +} + +/// \brief Right shift word array +/// \param r word array +/// \param n size of the word array, in elements +/// \param shiftWords number of words to shift +/// \details ShiftWordsRightByWords shifts the word array right by +/// shiftWords. ShiftWordsRightByWords shifts bits out on the right. +/// \since Crypto++ 1.0 +inline void ShiftWordsRightByWords(word *r, size_t n, size_t shiftWords) +{ + shiftWords = STDMIN(shiftWords, n); + if (shiftWords) + { + for (size_t i=0; i+shiftWordsdraft-ietf-curdle-pkix. +/// \details If you have a little endian array and you want to wrap it in +/// an Integer using big endian then you can perform the following: +///
Integer x(my_arr, SECRET_KEYLENGTH, UNSIGNED, LITTLE_ENDIAN_ORDER);
+/// \sa Andrew Moon's x22519 GitHub curve25519-donna, +/// ed22519 GitHub ed25519-donna, and +/// draft-ietf-curdle-pkix +/// \since Crypto++ 8.0 + +#ifndef CRYPTOPP_XED25519_H +#define CRYPTOPP_XED25519_H + +#include "cryptlib.h" +#include "pubkey.h" +#include "oids.h" + +NAMESPACE_BEGIN(CryptoPP) + +class Integer; +struct ed25519Signer; +struct ed25519Verifier; + +// ******************** x25519 Agreement ************************* // + +/// \brief x25519 with key validation +/// \since Crypto++ 8.0 +class x25519 : public SimpleKeyAgreementDomain, public CryptoParameters, public PKCS8PrivateKey +{ +public: + /// \brief Size of the private key + /// \details SECRET_KEYLENGTH is the size of the private key, in bytes. + CRYPTOPP_CONSTANT(SECRET_KEYLENGTH = 32); + /// \brief Size of the public key + /// \details PUBLIC_KEYLENGTH is the size of the public key, in bytes. + CRYPTOPP_CONSTANT(PUBLIC_KEYLENGTH = 32); + /// \brief Size of the shared key + /// \details SHARED_KEYLENGTH is the size of the shared key, in bytes. + CRYPTOPP_CONSTANT(SHARED_KEYLENGTH = 32); + + virtual ~x25519() {} + + /// \brief Create a x25519 object + /// \details This constructor creates an empty x25519 object. It is + /// intended for use in loading existing parameters, like CryptoBox + /// parameters. If you are performing key agreement you should use a + /// constructor that generates random parameters on construction. + x25519() {} + + /// \brief Create a x25519 object + /// \param y public key + /// \param x private key + /// \details This constructor creates a x25519 object using existing parameters. + /// \note The public key is not validated. + x25519(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]); + + /// \brief Create a x25519 object + /// \param x private key + /// \details This constructor creates a x25519 object using existing parameters. + /// The public key is calculated from the private key. + x25519(const byte x[SECRET_KEYLENGTH]); + + /// \brief Create a x25519 object + /// \param y public key + /// \param x private key + /// \details This constructor creates a x25519 object using existing parameters. + /// \note The public key is not validated. + x25519(const Integer &y, const Integer &x); + + /// \brief Create a x25519 object + /// \param x private key + /// \details This constructor creates a x25519 object using existing parameters. + /// The public key is calculated from the private key. + x25519(const Integer &x); + + /// \brief Create a x25519 object + /// \param rng RandomNumberGenerator derived class + /// \details This constructor creates a new x25519 using the random number generator. + x25519(RandomNumberGenerator &rng); + + /// \brief Create a x25519 object + /// \param params public and private key + /// \details This constructor creates a x25519 object using existing parameters. + /// The params can be created with Save. + /// \note The public key is not validated. + x25519(BufferedTransformation ¶ms); + + /// \brief Create a x25519 object + /// \param oid an object identifier + /// \details This constructor creates a new x25519 using the specified OID. The public + /// and private points are uninitialized. + x25519(const OID &oid); + + /// \brief Clamp a private key + /// \param x private key + /// \details ClampKeys() clamps a private key and then regenerates the + /// public key from the private key. + void ClampKey(byte x[SECRET_KEYLENGTH]) const; + + /// \brief Determine if private key is clamped + /// \param x private key + bool IsClamped(const byte x[SECRET_KEYLENGTH]) const; + + /// \brief Test if a key has small order + /// \param y public key + bool IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const; + + /// \brief Get the Object Identifier + /// \return the Object Identifier + /// \details The default OID is from RFC 8410 using id-X25519. + /// The default private key format is RFC 5208. + OID GetAlgorithmID() const { + return m_oid.Empty() ? ASN1::X25519() : m_oid; + } + + /// \brief Set the Object Identifier + /// \param oid the new Object Identifier + void SetAlgorithmID(const OID& oid) { + m_oid = oid; + } + + // CryptoParameters + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // CryptoParameters + CryptoParameters & AccessCryptoParameters() {return *this;} + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPublicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-X25519. + /// The default private key format is RFC 5208, which is the old format. + /// The old format provides the best interop, and keys will work + /// with OpenSSL. + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Save(BufferedTransformation &bt) const { + DEREncode(bt, 0); + } + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \param v1 flag indicating v1 + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPublicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-X25519. + /// The default private key format is RFC 5208. + /// \details v1 means INTEGER 0 is written. INTEGER 0 means + /// RFC 5208 format, which is the old format. The old format provides + /// the best interop, and keys will work with OpenSSL. The other + /// option uses INTEGER 1. INTEGER 1 means RFC 5958 format, + /// which is the new format. + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Save(BufferedTransformation &bt, bool v1) const { + DEREncode(bt, v1 ? 0 : 1); + } + + /// \brief BER decode ASN.1 object + /// \param bt BufferedTransformation object + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Load(BufferedTransformation &bt) { + BERDecode(bt); + } + + // PKCS8PrivateKey + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const { DEREncode(bt, 0); } + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \param version indicates version + /// \details DEREncode() will write the OID associated with algorithm or + /// scheme. In the case of public and private keys, this function writes + /// the subjectPublicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-X25519. + /// The default private key format is RFC 5208. + /// \details The value of version is written as the INTEGER. INTEGER 0 means + /// RFC 5208 format, which is the old format. The old format provides + /// the best interop, and keys will work with OpenSSL. The INTEGER 1 + /// means RFC 5958 format, which is the new format. + void DEREncode(BufferedTransformation &bt, int version) const; + + /// \brief Determine if OID is valid for this object + /// \details BERDecodeAndCheckAlgorithmID() parses the OID from + /// bt and determines if it valid for this object. The + /// problem in practice is there are multiple OIDs available to + /// denote curve25519 operations. The OIDs include an old GNU + /// OID used by SSH, OIDs specified in draft-josefsson-pkix-newcurves, + /// and OIDs specified in draft-ietf-curdle-pkix. + /// \details By default BERDecodeAndCheckAlgorithmID() accepts an + /// OID set by the user, ASN1::curve25519() and ASN1::X25519(). + /// ASN1::curve25519() is generic and says "this key is valid for + /// curve25519 operations". ASN1::X25519() is specific and says + /// "this key is valid for x25519 key exchange." + void BERDecodeAndCheckAlgorithmID(BufferedTransformation& bt); + + // DL_PrivateKey + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms); + + // SimpleKeyAgreementDomain + unsigned int AgreedValueLength() const {return SHARED_KEYLENGTH;} + unsigned int PrivateKeyLength() const {return SECRET_KEYLENGTH;} + unsigned int PublicKeyLength() const {return PUBLIC_KEYLENGTH;} + + // SimpleKeyAgreementDomain + void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const; + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const; + bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const; + +protected: + // Create a public key from a private key + void SecretToPublicKey(byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]) const; + +protected: + FixedSizeSecBlock m_sk; + FixedSizeSecBlock m_pk; + OID m_oid; // preferred OID +}; + +// ****************** ed25519 Signer *********************** // + +/// \brief ed25519 message accumulator +/// \details ed25519 buffers the entire message, and does not +/// digest the message incrementally. You should be careful with +/// large messages like files on-disk. The behavior is by design +/// because Bernstein feels small messages should be authenticated; +/// and larger messages will be digested by the application. +/// \details The accumulator is used for signing and verification. +/// The first 64-bytes of storage is reserved for the signature. +/// During signing the signature storage is unused. During +/// verification the first 64 bytes holds the signature. The +/// signature is provided by the PK_Verifier framework and the +/// call to PK_Signer::InputSignature. Member functions data() +/// and size() refer to the accumulated message. Member function +/// signature() refers to the signature with an implicit size of +/// SIGNATURE_LENGTH bytes. +/// \details Applications which digest large messages, like an ISO +/// disk file, should take care because the design effectively +/// disgorges the format operation from the signing operation. +/// Put another way, be careful to ensure what you are signing is +/// is in fact a digest of the intended message, and not a different +/// message digest supplied by an attacker. +struct ed25519_MessageAccumulator : public PK_MessageAccumulator +{ + CRYPTOPP_CONSTANT(RESERVE_SIZE=2048+64); + CRYPTOPP_CONSTANT(SIGNATURE_LENGTH=64); + + /// \brief Create a message accumulator + ed25519_MessageAccumulator() { + Restart(); + } + + /// \brief Create a message accumulator + /// \details ed25519 does not use a RNG. You can safely use + /// NullRNG() because IsProbablistic returns false. + ed25519_MessageAccumulator(RandomNumberGenerator &rng) { + CRYPTOPP_UNUSED(rng); Restart(); + } + + /// \brief Add data to the accumulator + /// \param msg pointer to the data to accumulate + /// \param len the size of the data, in bytes + void Update(const byte* msg, size_t len) { + if (msg && len) + m_msg.insert(m_msg.end(), msg, msg+len); + } + + /// \brief Reset the accumulator + void Restart() { + m_msg.reserve(RESERVE_SIZE); + m_msg.resize(SIGNATURE_LENGTH); + } + + /// \brief Retrieve pointer to signature buffer + /// \return pointer to signature buffer + byte* signature() { + return &m_msg[0]; + } + + /// \brief Retrieve pointer to signature buffer + /// \return pointer to signature buffer + const byte* signature() const { + return &m_msg[0]; + } + + /// \brief Retrieve pointer to data buffer + /// \return pointer to data buffer + const byte* data() const { + return &m_msg[0]+SIGNATURE_LENGTH; + } + + /// \brief Retrieve size of data buffer + /// \return size of the data buffer, in bytes + size_t size() const { + return m_msg.size()-SIGNATURE_LENGTH; + } + +protected: + // TODO: Find an equivalent Crypto++ structure. + std::vector > m_msg; +}; + +/// \brief Ed25519 private key +/// \details ed25519PrivateKey is somewhat of a hack. It needed to +/// provide DL_PrivateKey interface to fit into the existing +/// framework, but it lacks a lot of the internals of a true +/// DL_PrivateKey. The missing pieces include GroupParameters +/// and Point, which provide the low level field operations +/// found in traditional implementations like NIST curves over +/// prime and binary fields. +/// \details ed25519PrivateKey is also unusual because the +/// class members of interest are byte arrays and not Integers. +/// In addition, the byte arrays are little-endian meaning +/// LSB is at element 0 and the MSB is at element 31. +/// If you call GetPrivateExponent() then the little-endian byte +/// array is converted to a big-endian Integer() so it can be +/// returned the way a caller expects. And calling +/// SetPrivateExponent performs a similar internal conversion. +/// \since Crypto++ 8.0 +struct ed25519PrivateKey : public PKCS8PrivateKey +{ + /// \brief Size of the private key + /// \details SECRET_KEYLENGTH is the size of the private key, in bytes. + CRYPTOPP_CONSTANT(SECRET_KEYLENGTH = 32); + /// \brief Size of the public key + /// \details PUBLIC_KEYLENGTH is the size of the public key, in bytes. + CRYPTOPP_CONSTANT(PUBLIC_KEYLENGTH = 32); + /// \brief Size of the signature + /// \details SIGNATURE_LENGTH is the size of the signature, in bytes. + /// ed25519 is a DL-based signature scheme. The signature is the + /// concatenation of r || s. + CRYPTOPP_CONSTANT(SIGNATURE_LENGTH = 64); + + virtual ~ed25519PrivateKey() {} + + // CryptoMaterial + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // GroupParameters + OID GetAlgorithmID() const { + return m_oid.Empty() ? ASN1::Ed25519() : m_oid; + } + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPublicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-Ed25519. + /// The default private key format is RFC 5208, which is the old format. + /// The old format provides the best interop, and keys will work + /// with OpenSSL. + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Save(BufferedTransformation &bt) const { + DEREncode(bt, 0); + } + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \param v1 flag indicating v1 + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPublicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-Ed25519. + /// The default private key format is RFC 5208. + /// \details v1 means INTEGER 0 is written. INTEGER 0 means + /// RFC 5208 format, which is the old format. The old format provides + /// the best interop, and keys will work with OpenSSL. The other + /// option uses INTEGER 1. INTEGER 1 means RFC 5958 format, + /// which is the new format. + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Save(BufferedTransformation &bt, bool v1) const { + DEREncode(bt, v1 ? 0 : 1); + } + + /// \brief BER decode ASN.1 object + /// \param bt BufferedTransformation object + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Load(BufferedTransformation &bt) { + BERDecode(bt); + } + + /// \brief Initializes a public key from this key + /// \param pub reference to a public key + void MakePublicKey(PublicKey &pub) const; + + // PKCS8PrivateKey + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const { DEREncode(bt, 0); } + void BERDecodePrivateKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePrivateKey(BufferedTransformation &bt) const; + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \param version indicates version + /// \details DEREncode() will write the OID associated with algorithm or + /// scheme. In the case of public and private keys, this function writes + /// the subjectPublicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-X25519. + /// The default private key format is RFC 5208. + /// \details The value of version is written as the INTEGER. INTEGER 0 means + /// RFC 5208 format, which is the old format. The old format provides + /// the best interop, and keys will work with OpenSSL. The INTEGER 1 + /// means RFC 5958 format, which is the new format. + void DEREncode(BufferedTransformation &bt, int version) const; + + /// \brief Determine if OID is valid for this object + /// \details BERDecodeAndCheckAlgorithmID() parses the OID from + /// bt and determines if it valid for this object. The + /// problem in practice is there are multiple OIDs available to + /// denote curve25519 operations. The OIDs include an old GNU + /// OID used by SSH, OIDs specified in draft-josefsson-pkix-newcurves, + /// and OIDs specified in draft-ietf-curdle-pkix. + /// \details By default BERDecodeAndCheckAlgorithmID() accepts an + /// OID set by the user, ASN1::curve25519() and ASN1::Ed25519(). + /// ASN1::curve25519() is generic and says "this key is valid for + /// curve25519 operations". ASN1::Ed25519() is specific and says + /// "this key is valid for ed25519 signing." + void BERDecodeAndCheckAlgorithmID(BufferedTransformation& bt); + + // PKCS8PrivateKey + void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs ¶ms); + void SetPrivateExponent(const byte x[SECRET_KEYLENGTH]); + void SetPrivateExponent(const Integer &x); + const Integer& GetPrivateExponent() const; + + /// \brief Test if a key has small order + /// \param y public key + bool IsSmallOrder(const byte y[PUBLIC_KEYLENGTH]) const; + + /// \brief Retrieve private key byte array + /// \return the private key byte array + /// \details GetPrivateKeyBytePtr() is used by signing code to call ed25519_sign. + const byte* GetPrivateKeyBytePtr() const { + return m_sk.begin(); + } + + /// \brief Retrieve public key byte array + /// \return the public key byte array + /// \details GetPublicKeyBytePtr() is used by signing code to call ed25519_sign. + const byte* GetPublicKeyBytePtr() const { + return m_pk.begin(); + } + +protected: + // Create a public key from a private key + void SecretToPublicKey(byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]) const; + +protected: + FixedSizeSecBlock m_sk; + FixedSizeSecBlock m_pk; + OID m_oid; // preferred OID + mutable Integer m_x; // for DL_PrivateKey +}; + +/// \brief Ed25519 signature algorithm +/// \since Crypto++ 8.0 +struct ed25519Signer : public PK_Signer +{ + /// \brief Size of the private key + /// \details SECRET_KEYLENGTH is the size of the private key, in bytes. + CRYPTOPP_CONSTANT(SECRET_KEYLENGTH = 32); + /// \brief Size of the public key + /// \details PUBLIC_KEYLENGTH is the size of the public key, in bytes. + CRYPTOPP_CONSTANT(PUBLIC_KEYLENGTH = 32); + /// \brief Size of the signature + /// \details SIGNATURE_LENGTH is the size of the signature, in bytes. + /// ed25519 is a DL-based signature scheme. The signature is the + /// concatenation of r || s. + CRYPTOPP_CONSTANT(SIGNATURE_LENGTH = 64); + typedef Integer Element; + + virtual ~ed25519Signer() {} + + /// \brief Create an ed25519Signer object + ed25519Signer() {} + + /// \brief Create an ed25519Signer object + /// \param y public key + /// \param x private key + /// \details This constructor creates an ed25519Signer object using existing parameters. + /// \note The public key is not validated. + ed25519Signer(const byte y[PUBLIC_KEYLENGTH], const byte x[SECRET_KEYLENGTH]); + + /// \brief Create an ed25519Signer object + /// \param x private key + /// \details This constructor creates an ed25519Signer object using existing parameters. + /// The public key is calculated from the private key. + ed25519Signer(const byte x[SECRET_KEYLENGTH]); + + /// \brief Create an ed25519Signer object + /// \param y public key + /// \param x private key + /// \details This constructor creates an ed25519Signer object using existing parameters. + /// \note The public key is not validated. + ed25519Signer(const Integer &y, const Integer &x); + + /// \brief Create an ed25519Signer object + /// \param x private key + /// \details This constructor creates an ed25519Signer object using existing parameters. + /// The public key is calculated from the private key. + ed25519Signer(const Integer &x); + + /// \brief Create an ed25519Signer object + /// \param key PKCS8 private key + /// \details This constructor creates an ed25519Signer object using existing private key. + /// \note The keys are not validated. + /// \since Crypto++ 8.6 + ed25519Signer(const PKCS8PrivateKey &key); + + /// \brief Create an ed25519Signer object + /// \param rng RandomNumberGenerator derived class + /// \details This constructor creates a new ed25519Signer using the random number generator. + ed25519Signer(RandomNumberGenerator &rng); + + /// \brief Create an ed25519Signer object + /// \param params public and private key + /// \details This constructor creates an ed25519Signer object using existing parameters. + /// The params can be created with Save. + /// \note The public key is not validated. + ed25519Signer(BufferedTransformation ¶ms); + + // DL_ObjectImplBase + /// \brief Retrieves a reference to a Private Key + /// \details AccessKey() retrieves a non-const reference to a private key. + PrivateKey& AccessKey() { return m_key; } + PrivateKey& AccessPrivateKey() { return m_key; } + + /// \brief Retrieves a reference to a Private Key + /// \details AccessKey() retrieves a const reference to a private key. + const PrivateKey& GetKey() const { return m_key; } + const PrivateKey& GetPrivateKey() const { return m_key; } + + // DL_SignatureSchemeBase + size_t SignatureLength() const { return SIGNATURE_LENGTH; } + size_t MaxRecoverableLength() const { return 0; } + size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const { + CRYPTOPP_UNUSED(signatureLength); return 0; + } + + bool IsProbabilistic() const { return false; } + bool AllowNonrecoverablePart() const { return false; } + bool RecoverablePartFirst() const { return false; } + + PK_MessageAccumulator* NewSignatureAccumulator(RandomNumberGenerator &rng) const { + return new ed25519_MessageAccumulator(rng); + } + + void InputRecoverableMessage(PK_MessageAccumulator &messageAccumulator, const byte *recoverableMessage, size_t recoverableMessageLength) const { + CRYPTOPP_UNUSED(messageAccumulator); CRYPTOPP_UNUSED(recoverableMessage); + CRYPTOPP_UNUSED(recoverableMessageLength); + throw NotImplemented("ed25519Signer: this object does not support recoverable messages"); + } + + size_t SignAndRestart(RandomNumberGenerator &rng, PK_MessageAccumulator &messageAccumulator, byte *signature, bool restart) const; + + /// \brief Sign a stream + /// \param rng a RandomNumberGenerator derived class + /// \param stream an std::istream derived class + /// \param signature a block of bytes for the signature + /// \return actual signature length + /// \details SignStream() handles large streams. The Stream functions were added to + /// ed25519 for signing and verifying files that are too large for a memory allocation. + /// The functions are not present in other library signers and verifiers. + /// \details ed25519 is a deterministic signature scheme. IsProbabilistic() + /// returns false and the random number generator can be NullRNG(). + /// \pre COUNTOF(signature) == MaxSignatureLength() + /// \since Crypto++ 8.1 + size_t SignStream (RandomNumberGenerator &rng, std::istream& stream, byte *signature) const; + +protected: + ed25519PrivateKey m_key; +}; + +// ****************** ed25519 Verifier *********************** // + +/// \brief Ed25519 public key +/// \details ed25519PublicKey is somewhat of a hack. It needed to +/// provide DL_PublicKey interface to fit into the existing +/// framework, but it lacks a lot of the internals of a true +/// DL_PublicKey. The missing pieces include GroupParameters +/// and Point, which provide the low level field operations +/// found in traditional implementations like NIST curves over +/// prime and binary fields. +/// \details ed25519PublicKey is also unusual because the +/// class members of interest are byte arrays and not Integers. +/// In addition, the byte arrays are little-endian meaning +/// LSB is at element 0 and the MSB is at element 31. +/// If you call GetPublicElement() then the little-endian byte +/// array is converted to a big-endian Integer() so it can be +/// returned the way a caller expects. And calling +/// SetPublicElement() performs a similar internal conversion. +/// \since Crypto++ 8.0 +struct ed25519PublicKey : public X509PublicKey +{ + /// \brief Size of the public key + /// \details PUBLIC_KEYLENGTH is the size of the public key, in bytes. + CRYPTOPP_CONSTANT(PUBLIC_KEYLENGTH = 32); + typedef Integer Element; + + virtual ~ed25519PublicKey() {} + + OID GetAlgorithmID() const { + return m_oid.Empty() ? ASN1::Ed25519() : m_oid; + } + + /// \brief DER encode ASN.1 object + /// \param bt BufferedTransformation object + /// \details Save() will write the OID associated with algorithm or scheme. + /// In the case of public and private keys, this function writes the + /// subjectPublicKeyInfo parts. + /// \details The default OID is from RFC 8410 using id-X25519. + /// The default private key format is RFC 5208, which is the old format. + /// The old format provides the best interop, and keys will work + /// with OpenSSL. + void Save(BufferedTransformation &bt) const { + DEREncode(bt); + } + + /// \brief BER decode ASN.1 object + /// \param bt BufferedTransformation object + /// \sa RFC 5958, Asymmetric + /// Key Packages + void Load(BufferedTransformation &bt) { + BERDecode(bt); + } + + // X509PublicKey + void BERDecode(BufferedTransformation &bt); + void DEREncode(BufferedTransformation &bt) const; + void BERDecodePublicKey(BufferedTransformation &bt, bool parametersPresent, size_t size); + void DEREncodePublicKey(BufferedTransformation &bt) const; + + /// \brief Determine if OID is valid for this object + /// \details BERDecodeAndCheckAlgorithmID() parses the OID from + /// bt and determines if it valid for this object. The + /// problem in practice is there are multiple OIDs available to + /// denote curve25519 operations. The OIDs include an old GNU + /// OID used by SSH, OIDs specified in draft-josefsson-pkix-newcurves, + /// and OIDs specified in draft-ietf-curdle-pkix. + /// \details By default BERDecodeAndCheckAlgorithmID() accepts an + /// OID set by the user, ASN1::curve25519() and ASN1::Ed25519(). + /// ASN1::curve25519() is generic and says "this key is valid for + /// curve25519 operations". ASN1::Ed25519() is specific and says + /// "this key is valid for ed25519 signing." + void BERDecodeAndCheckAlgorithmID(BufferedTransformation& bt); + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + + // DL_PublicKey + void SetPublicElement(const byte y[PUBLIC_KEYLENGTH]); + void SetPublicElement(const Element &y); + const Element& GetPublicElement() const; + + /// \brief Retrieve public key byte array + /// \return the public key byte array + /// \details GetPublicKeyBytePtr() is used by signing code to call ed25519_sign. + const byte* GetPublicKeyBytePtr() const { + return m_pk.begin(); + } + +protected: + FixedSizeSecBlock m_pk; + OID m_oid; // preferred OID + mutable Integer m_y; // for DL_PublicKey +}; + +/// \brief Ed25519 signature verification algorithm +/// \since Crypto++ 8.0 +struct ed25519Verifier : public PK_Verifier +{ + CRYPTOPP_CONSTANT(PUBLIC_KEYLENGTH = 32); + CRYPTOPP_CONSTANT(SIGNATURE_LENGTH = 64); + typedef Integer Element; + + virtual ~ed25519Verifier() {} + + /// \brief Create an ed25519Verifier object + ed25519Verifier() {} + + /// \brief Create an ed25519Verifier object + /// \param y public key + /// \details This constructor creates an ed25519Verifier object using existing parameters. + /// \note The public key is not validated. + ed25519Verifier(const byte y[PUBLIC_KEYLENGTH]); + + /// \brief Create an ed25519Verifier object + /// \param y public key + /// \details This constructor creates an ed25519Verifier object using existing parameters. + /// \note The public key is not validated. + ed25519Verifier(const Integer &y); + + /// \brief Create an ed25519Verifier object + /// \param key X509 public key + /// \details This constructor creates an ed25519Verifier object using an existing public key. + /// \note The public key is not validated. + /// \since Crypto++ 8.6 + ed25519Verifier(const X509PublicKey &key); + + /// \brief Create an ed25519Verifier object + /// \param params public and private key + /// \details This constructor creates an ed25519Verifier object using existing parameters. + /// The params can be created with Save. + /// \note The public key is not validated. + ed25519Verifier(BufferedTransformation ¶ms); + + /// \brief Create an ed25519Verifier object + /// \param signer ed25519 signer object + /// \details This constructor creates an ed25519Verifier object using existing parameters. + /// The params can be created with Save. + /// \note The public key is not validated. + ed25519Verifier(const ed25519Signer& signer); + + // DL_ObjectImplBase + /// \brief Retrieves a reference to a Public Key + /// \details AccessKey() retrieves a non-const reference to a public key. + PublicKey& AccessKey() { return m_key; } + PublicKey& AccessPublicKey() { return m_key; } + + /// \brief Retrieves a reference to a Public Key + /// \details GetKey() retrieves a const reference to a public key. + const PublicKey& GetKey() const { return m_key; } + const PublicKey& GetPublicKey() const { return m_key; } + + // DL_SignatureSchemeBase + size_t SignatureLength() const { return SIGNATURE_LENGTH; } + size_t MaxRecoverableLength() const { return 0; } + size_t MaxRecoverableLengthFromSignatureLength(size_t signatureLength) const { + CRYPTOPP_UNUSED(signatureLength); return 0; + } + + bool IsProbabilistic() const { return false; } + bool AllowNonrecoverablePart() const { return false; } + bool RecoverablePartFirst() const { return false; } + + ed25519_MessageAccumulator* NewVerificationAccumulator() const { + return new ed25519_MessageAccumulator; + } + + void InputSignature(PK_MessageAccumulator &messageAccumulator, const byte *signature, size_t signatureLength) const { + CRYPTOPP_ASSERT(signature != NULLPTR); + CRYPTOPP_ASSERT(signatureLength == SIGNATURE_LENGTH); + ed25519_MessageAccumulator& accum = static_cast(messageAccumulator); + if (signature && signatureLength) + std::memcpy(accum.signature(), signature, STDMIN((size_t)SIGNATURE_LENGTH, signatureLength)); + } + + bool VerifyAndRestart(PK_MessageAccumulator &messageAccumulator) const; + + /// \brief Check whether input signature is a valid signature for input message + /// \param stream an std::istream derived class + /// \param signature a pointer to the signature over the message + /// \param signatureLen the size of the signature + /// \return true if the signature is valid, false otherwise + /// \details VerifyStream() handles large streams. The Stream functions were added to + /// ed25519 for signing and verifying files that are too large for a memory allocation. + /// The functions are not present in other library signers and verifiers. + /// \since Crypto++ 8.1 + bool VerifyStream(std::istream& stream, const byte *signature, size_t signatureLen) const; + + DecodingResult RecoverAndRestart(byte *recoveredMessage, PK_MessageAccumulator &messageAccumulator) const { + CRYPTOPP_UNUSED(recoveredMessage); CRYPTOPP_UNUSED(messageAccumulator); + throw NotImplemented("ed25519Verifier: this object does not support recoverable messages"); + } + +protected: + ed25519PublicKey m_key; +}; + +/// \brief Ed25519 signature scheme +/// \sa Ed25519 on the Crypto++ wiki. +/// \since Crypto++ 8.0 +struct ed25519 +{ + /// \brief ed25519 Signer + typedef ed25519Signer Signer; + /// \brief ed25519 Verifier + typedef ed25519Verifier Verifier; +}; + +NAMESPACE_END // CryptoPP + +#endif // CRYPTOPP_XED25519_H diff --git a/third_party/cryptoppwin/include/cryptopp/xtr.h b/third_party/cryptoppwin/include/cryptopp/xtr.h new file mode 100644 index 00000000..3d1c3382 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/xtr.h @@ -0,0 +1,219 @@ +#ifndef CRYPTOPP_XTR_H +#define CRYPTOPP_XTR_H + +/// \file xtr.h +/// \brief The XTR public key system +/// \details The XTR public key system by Arjen K. Lenstra and Eric R. Verheul + +#include "cryptlib.h" +#include "modarith.h" +#include "integer.h" +#include "algebra.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief an element of GF(p^2) +class GFP2Element +{ +public: + GFP2Element() {} + GFP2Element(const Integer &c1, const Integer &c2) : c1(c1), c2(c2) {} + GFP2Element(const byte *encodedElement, unsigned int size) + : c1(encodedElement, size/2), c2(encodedElement+size/2, size/2) {} + + void Encode(byte *encodedElement, unsigned int size) + { + c1.Encode(encodedElement, size/2); + c2.Encode(encodedElement+size/2, size/2); + } + + bool operator==(const GFP2Element &rhs) const {return c1 == rhs.c1 && c2 == rhs.c2;} + bool operator!=(const GFP2Element &rhs) const {return !operator==(rhs);} + + void swap(GFP2Element &a) + { + c1.swap(a.c1); + c2.swap(a.c2); + } + + static const GFP2Element & Zero(); + + Integer c1, c2; +}; + +/// \brief GF(p^2), optimal normal basis +template +class GFP2_ONB : public AbstractRing +{ +public: + typedef F BaseField; + + GFP2_ONB(const Integer &p) : modp(p) + { + if (p%3 != 2) + throw InvalidArgument("GFP2_ONB: modulus must be equivalent to 2 mod 3"); + } + + const Integer& GetModulus() const {return modp.GetModulus();} + + GFP2Element ConvertIn(const Integer &a) const + { + t = modp.Inverse(modp.ConvertIn(a)); + return GFP2Element(t, t); + } + + GFP2Element ConvertIn(const GFP2Element &a) const + {return GFP2Element(modp.ConvertIn(a.c1), modp.ConvertIn(a.c2));} + + GFP2Element ConvertOut(const GFP2Element &a) const + {return GFP2Element(modp.ConvertOut(a.c1), modp.ConvertOut(a.c2));} + + bool Equal(const GFP2Element &a, const GFP2Element &b) const + { + return modp.Equal(a.c1, b.c1) && modp.Equal(a.c2, b.c2); + } + + const Element& Identity() const + { + return GFP2Element::Zero(); + } + + const Element& Add(const Element &a, const Element &b) const + { + result.c1 = modp.Add(a.c1, b.c1); + result.c2 = modp.Add(a.c2, b.c2); + return result; + } + + const Element& Inverse(const Element &a) const + { + result.c1 = modp.Inverse(a.c1); + result.c2 = modp.Inverse(a.c2); + return result; + } + + const Element& Double(const Element &a) const + { + result.c1 = modp.Double(a.c1); + result.c2 = modp.Double(a.c2); + return result; + } + + const Element& Subtract(const Element &a, const Element &b) const + { + result.c1 = modp.Subtract(a.c1, b.c1); + result.c2 = modp.Subtract(a.c2, b.c2); + return result; + } + + Element& Accumulate(Element &a, const Element &b) const + { + modp.Accumulate(a.c1, b.c1); + modp.Accumulate(a.c2, b.c2); + return a; + } + + Element& Reduce(Element &a, const Element &b) const + { + modp.Reduce(a.c1, b.c1); + modp.Reduce(a.c2, b.c2); + return a; + } + + bool IsUnit(const Element &a) const + { + return a.c1.NotZero() || a.c2.NotZero(); + } + + const Element& MultiplicativeIdentity() const + { + result.c1 = result.c2 = modp.Inverse(modp.MultiplicativeIdentity()); + return result; + } + + const Element& Multiply(const Element &a, const Element &b) const + { + t = modp.Add(a.c1, a.c2); + t = modp.Multiply(t, modp.Add(b.c1, b.c2)); + result.c1 = modp.Multiply(a.c1, b.c1); + result.c2 = modp.Multiply(a.c2, b.c2); + result.c1.swap(result.c2); + modp.Reduce(t, result.c1); + modp.Reduce(t, result.c2); + modp.Reduce(result.c1, t); + modp.Reduce(result.c2, t); + return result; + } + + const Element& MultiplicativeInverse(const Element &a) const + { + return result = Exponentiate(a, modp.GetModulus()-2); + } + + const Element& Square(const Element &a) const + { + const Integer &ac1 = (&a == &result) ? (t = a.c1) : a.c1; + result.c1 = modp.Multiply(modp.Subtract(modp.Subtract(a.c2, a.c1), a.c1), a.c2); + result.c2 = modp.Multiply(modp.Subtract(modp.Subtract(ac1, a.c2), a.c2), ac1); + return result; + } + + Element Exponentiate(const Element &a, const Integer &e) const + { + Integer edivp, emodp; + Integer::Divide(emodp, edivp, e, modp.GetModulus()); + Element b = PthPower(a); + return AbstractRing::CascadeExponentiate(a, emodp, b, edivp); + } + + const Element & PthPower(const Element &a) const + { + result = a; + result.c1.swap(result.c2); + return result; + } + + void RaiseToPthPower(Element &a) const + { + a.c1.swap(a.c2); + } + + // a^2 - 2a^p + const Element & SpecialOperation1(const Element &a) const + { + CRYPTOPP_ASSERT(&a != &result); + result = Square(a); + modp.Reduce(result.c1, a.c2); + modp.Reduce(result.c1, a.c2); + modp.Reduce(result.c2, a.c1); + modp.Reduce(result.c2, a.c1); + return result; + } + + // x * z - y * z^p + const Element & SpecialOperation2(const Element &x, const Element &y, const Element &z) const + { + CRYPTOPP_ASSERT(&x != &result && &y != &result && &z != &result); + t = modp.Add(x.c2, y.c2); + result.c1 = modp.Multiply(z.c1, modp.Subtract(y.c1, t)); + modp.Accumulate(result.c1, modp.Multiply(z.c2, modp.Subtract(t, x.c1))); + t = modp.Add(x.c1, y.c1); + result.c2 = modp.Multiply(z.c2, modp.Subtract(y.c2, t)); + modp.Accumulate(result.c2, modp.Multiply(z.c1, modp.Subtract(t, x.c2))); + return result; + } + +protected: + BaseField modp; + mutable GFP2Element result; + mutable Integer t; +}; + +/// \brief Creates primes p,q and generator g for XTR +void XTR_FindPrimesAndGenerator(RandomNumberGenerator &rng, Integer &p, Integer &q, GFP2Element &g, unsigned int pbits, unsigned int qbits); + +GFP2Element XTR_Exponentiate(const GFP2Element &b, const Integer &e, const Integer &p); + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/xtrcrypt.h b/third_party/cryptoppwin/include/cryptopp/xtrcrypt.h new file mode 100644 index 00000000..0248788c --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/xtrcrypt.h @@ -0,0 +1,55 @@ +#ifndef CRYPTOPP_XTRCRYPT_H +#define CRYPTOPP_XTRCRYPT_H + +/// \file +/// \brief XTR public key system +/// \sa "The XTR public key system" by Arjen K. Lenstra and Eric R. Verheul + +#include "cryptlib.h" +#include "xtr.h" +#include "integer.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief XTR-DH with key validation +class XTR_DH : public SimpleKeyAgreementDomain, public CryptoParameters +{ + typedef XTR_DH ThisClass; + +public: + XTR_DH(const Integer &p, const Integer &q, const GFP2Element &g); + XTR_DH(RandomNumberGenerator &rng, unsigned int pbits, unsigned int qbits); + XTR_DH(BufferedTransformation &domainParams); + + void DEREncode(BufferedTransformation &domainParams) const; + + bool Validate(RandomNumberGenerator &rng, unsigned int level) const; + bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const; + void AssignFrom(const NameValuePairs &source); + CryptoParameters & AccessCryptoParameters() {return *this;} + unsigned int AgreedValueLength() const {return 2*m_p.ByteCount();} + unsigned int PrivateKeyLength() const {return m_q.ByteCount();} + unsigned int PublicKeyLength() const {return 2*m_p.ByteCount();} + + void GeneratePrivateKey(RandomNumberGenerator &rng, byte *privateKey) const; + void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const; + bool Agree(byte *agreedValue, const byte *privateKey, const byte *otherPublicKey, bool validateOtherPublicKey=true) const; + + const Integer &GetModulus() const {return m_p;} + const Integer &GetSubgroupOrder() const {return m_q;} + const GFP2Element &GetSubgroupGenerator() const {return m_g;} + + void SetModulus(const Integer &p) {m_p = p;} + void SetSubgroupOrder(const Integer &q) {m_q = q;} + void SetSubgroupGenerator(const GFP2Element &g) {m_g = g;} + +private: + unsigned int ExponentBitLength() const; + + Integer m_p, m_q; + GFP2Element m_g; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/xts.h b/third_party/cryptoppwin/include/cryptopp/xts.h new file mode 100644 index 00000000..6eac379a --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/xts.h @@ -0,0 +1,224 @@ +// xts.h - written and placed in the public domain by Jeffrey Walton + +/// \file xts.h +/// \brief Classes for XTS block cipher mode of operation +/// \details XTS mode is a wide block mode defined by IEEE P1619-2008. NIST +/// SP-800-38E approves the mode for storage devices citing IEEE 1619-2007. +/// IEEE 1619-2007 provides both a reference implementation and test vectors. +/// The IEEE reference implementation fails to arrive at the expected result +/// for some test vectors. +/// \sa Modes of +/// Operation on the Crypto++ wiki, Evaluation of Some +/// Blockcipher Modes of Operation, Recommendation +/// for Block Cipher Modes of Operation: The XTS-AES Mode for Confidentiality on +/// Storage Devices, IEEE P1619-2007 +/// and IEEE P1619/XTS, +/// inconsistent reference implementation and test vectors. +/// \since Crypto++ 8.3 + +#ifndef CRYPTOPP_XTS_MODE_H +#define CRYPTOPP_XTS_MODE_H + +#include "cryptlib.h" +#include "secblock.h" +#include "modes.h" +#include "misc.h" + +/// \brief Enable XTS for wide block ciphers +/// \details XTS is only defined for AES. The library can support wide +/// block ciphers like Kaylna and Threefish since we know the polynomials. +/// To enable wide block ciphers define CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS +/// to non-zero. Note this is a library compile time define. +/// \details There is risk involved with using XTS with wider block ciphers. +/// According to Phillip Rogaway, "The narrow width of the underlying PRP and +/// the poor treatment of fractional final blocks are problems." +/// \sa Evaluation +/// of Some Blockcipher Modes of Operation +/// \since Crypto++ 8.3 +#ifndef CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS +# define CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS 0 +#endif // CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief XTS block cipher mode of operation default implementation +/// \since Crypto++ 8.3 +class CRYPTOPP_NO_VTABLE XTS_ModeBase : public BlockOrientedCipherModeBase +{ +public: + /// \brief The algorithm name + /// \return the algorithm name + /// \details StaticAlgorithmName returns the algorithm's name as a static + /// member function. + CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() + {return "XTS";} + + virtual ~XTS_ModeBase() {} + + std::string AlgorithmName() const + {return GetBlockCipher().AlgorithmName() + "/XTS";} + std::string AlgorithmProvider() const + {return GetBlockCipher().AlgorithmProvider();} + + size_t MinKeyLength() const + {return GetBlockCipher().MinKeyLength()*2;} + size_t MaxKeyLength() const + {return GetBlockCipher().MaxKeyLength()*2;} + size_t DefaultKeyLength() const + {return GetBlockCipher().DefaultKeyLength()*2;} + size_t GetValidKeyLength(size_t n) const + {return 2*GetBlockCipher().GetValidKeyLength((n+1)/2);} + bool IsValidKeyLength(size_t keylength) const + {return keylength == GetValidKeyLength(keylength);} + + /// \brief Validates the key length + /// \param length the size of the keying material, in bytes + /// \throw InvalidKeyLength if the key length is invalid + void ThrowIfInvalidKeyLength(size_t length); + + /// Provides the block size of the cipher + /// \return the block size of the cipher, in bytes + unsigned int BlockSize() const + {return GetBlockCipher().BlockSize();} + + /// \brief Provides the input block size most efficient for this cipher + /// \return The input block size that is most efficient for the cipher + /// \details The base class implementation returns MandatoryBlockSize(). + /// \note Optimal input length is + /// n * OptimalBlockSize() - GetOptimalBlockSizeUsed() for + /// any n \> 0. + unsigned int GetOptimalBlockSize() const + {return GetBlockCipher().BlockSize()*ParallelBlocks;} + unsigned int MinLastBlockSize() const + {return GetBlockCipher().BlockSize()+1;} + unsigned int OptimalDataAlignment() const + {return GetBlockCipher().OptimalDataAlignment();} + + /// \brief Validates the block size + /// \param length the block size of the cipher, in bytes + /// \throw InvalidArgument if the block size is invalid + /// \details If CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS is 0, + /// then CIPHER must be a 16-byte block cipher. If + /// CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS is non-zero then + /// CIPHER can be 16, 32, 64, or 128-byte block cipher. + void ThrowIfInvalidBlockSize(size_t length); + + void SetKey(const byte *key, size_t length, const NameValuePairs ¶ms = g_nullNameValuePairs); + IV_Requirement IVRequirement() const {return UNIQUE_IV;} + void Resynchronize(const byte *iv, int ivLength=-1); + void ProcessData(byte *outString, const byte *inString, size_t length); + size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); + + /// \brief Resynchronize the cipher + /// \param sector a 64-bit sector number + /// \param order the endian order the word should be written + /// \details The Resynchronize() overload was provided for API + /// compatibility with the IEEE P1619 paper. + void Resynchronize(word64 sector, ByteOrder order=BIG_ENDIAN_ORDER); + +protected: + virtual void ResizeBuffers(); + + inline size_t ProcessLastPlainBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); + inline size_t ProcessLastCipherBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); + + virtual BlockCipher& AccessBlockCipher() = 0; + virtual BlockCipher& AccessTweakCipher() = 0; + + const BlockCipher& GetBlockCipher() const + {return const_cast(this)->AccessBlockCipher();} + const BlockCipher& GetTweakCipher() const + {return const_cast(this)->AccessTweakCipher();} + + // Buffers are sized based on ParallelBlocks + AlignedSecByteBlock m_xregister; + AlignedSecByteBlock m_xworkspace; + + // Intel lacks the SSE registers to run 8 or 12 parallel blocks. + // Do not change this value after compiling. It has no effect. +#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X86 + enum {ParallelBlocks = 4}; +#else + enum {ParallelBlocks = 12}; +#endif +}; + +/// \brief XTS block cipher mode of operation implementation +/// \tparam CIPHER BlockCipher derived class or type +/// \details XTS_Final() provides access to CIPHER in base class XTS_ModeBase() +/// through an interface. AccessBlockCipher() and AccessTweakCipher() allow +/// the XTS_ModeBase() base class to access the user's block cipher without +/// recompiling the library. +/// \details If CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS is 0, then CIPHER must +/// be a 16-byte block cipher. If CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS is +/// non-zero then CIPHER can be 16, 32, 64, or 128-byte block cipher. +/// There is risk involved with using XTS with wider block ciphers. +/// According to Phillip Rogaway, "The narrow width of the underlying PRP and +/// the poor treatment of fractional final blocks are problems." To enable +/// wide block cipher support define CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS to +/// non-zero. +/// \sa Modes of +/// Operation on the Crypto++ wiki, Evaluation of Some +/// Blockcipher Modes of Operation, Recommendation +/// for Block Cipher Modes of Operation: The XTS-AES Mode for Confidentiality on +/// Storage Devices, IEEE P1619-2007 +/// and IEEE P1619/XTS, +/// inconsistent reference implementation and test vectors. +/// \since Crypto++ 8.3 +template +class CRYPTOPP_NO_VTABLE XTS_Final : public XTS_ModeBase +{ +protected: + BlockCipher& AccessBlockCipher() + {return *m_cipher;} + BlockCipher& AccessTweakCipher() + {return m_tweaker;} + +protected: + typename CIPHER::Encryption m_tweaker; +}; + +/// \brief XTS block cipher mode of operation +/// \tparam CIPHER BlockCipher derived class or type +/// \details XTS mode is a wide block mode defined by IEEE P1619-2008. NIST +/// SP-800-38E approves the mode for storage devices citing IEEE 1619-2007. +/// IEEE 1619-2007 provides both a reference implementation and test vectors. +/// The IEEE reference implementation fails to arrive at the expected result +/// for some test vectors. +/// \details XTS is only defined for AES. The library can support wide +/// block ciphers like Kaylna and Threefish since we know the polynomials. +/// There is risk involved with using XTS with wider block ciphers. +/// According to Phillip Rogaway, "The narrow width of the underlying PRP and +/// the poor treatment of fractional final blocks are problems." To enable +/// wide block cipher support define CRYPTOPP_XTS_WIDE_BLOCK_CIPHERS to +/// non-zero. +/// \sa Modes of +/// Operation on the Crypto++ wiki, Evaluation of Some +/// Blockcipher Modes of Operation, Recommendation +/// for Block Cipher Modes of Operation: The XTS-AES Mode for Confidentiality on +/// Storage Devices, IEEE P1619-2007 +/// and IEEE P1619/XTS, +/// inconsistent reference implementation and test vectors. +/// \since Crypto++ 8.3 +template +struct XTS : public CipherModeDocumentation +{ + typedef CipherModeFinalTemplate_CipherHolder > Encryption; + typedef CipherModeFinalTemplate_CipherHolder > Decryption; +}; + +// C++03 lacks the mechanics to typedef a template +#define XTS_Mode XTS + +NAMESPACE_END + +#endif // CRYPTOPP_XTS_MODE_H diff --git a/third_party/cryptoppwin/include/cryptopp/zdeflate.h b/third_party/cryptoppwin/include/cryptopp/zdeflate.h new file mode 100644 index 00000000..36ae33c6 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/zdeflate.h @@ -0,0 +1,174 @@ +// zdeflate.h - originally written and placed in the public domain by Wei Dai + +/// \file zdeflate.h +/// \brief DEFLATE compression and decompression (RFC 1951) + +#ifndef CRYPTOPP_ZDEFLATE_H +#define CRYPTOPP_ZDEFLATE_H + +#include "cryptlib.h" +#include "filters.h" +#include "misc.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \brief Encoding table writer +/// \since Crypto++ 1.0 +class LowFirstBitWriter : public Filter +{ +public: + /// \brief Construct a LowFirstBitWriter + /// \param attachment an attached transformation + LowFirstBitWriter(BufferedTransformation *attachment); + + void PutBits(unsigned long value, unsigned int length); + void FlushBitBuffer(); + void ClearBitBuffer(); + + void StartCounting(); + unsigned long FinishCounting(); + +protected: + bool m_counting; + unsigned long m_bitCount; + unsigned long m_buffer; + unsigned int m_bitsBuffered, m_bytesBuffered; + FixedSizeSecBlock m_outputBuffer; +}; + +/// \brief Huffman Encoder +/// \since Crypto++ 1.0 +class HuffmanEncoder +{ +public: + typedef unsigned int code_t; + typedef unsigned int value_t; + + /// \brief Construct a HuffmanEncoder + HuffmanEncoder() {} + + /// \brief Construct a HuffmanEncoder + /// \param codeBits a table of code bits + /// \param nCodes the number of codes in the table + HuffmanEncoder(const unsigned int *codeBits, unsigned int nCodes); + + /// \brief Initialize or reinitialize this object + /// \param codeBits a table of code bits + /// \param nCodes the number of codes in the table + void Initialize(const unsigned int *codeBits, unsigned int nCodes); + + static void GenerateCodeLengths(unsigned int *codeBits, unsigned int maxCodeBits, const unsigned int *codeCounts, size_t nCodes); + + void Encode(LowFirstBitWriter &writer, value_t value) const; + + struct Code + { + unsigned int code; + unsigned int len; + }; + + SecBlock m_valueToCode; +}; + +/// \brief DEFLATE compressor (RFC 1951) +/// \since Crypto++ 1.0 +class Deflator : public LowFirstBitWriter +{ +public: + /// \brief Deflate level as enumerated values. + enum { + /// \brief Minimum deflation level, fastest speed (0) + MIN_DEFLATE_LEVEL = 0, + /// \brief Default deflation level, compromise between speed (6) + DEFAULT_DEFLATE_LEVEL = 6, + /// \brief Minimum deflation level, slowest speed (9) + MAX_DEFLATE_LEVEL = 9}; + + /// \brief Windows size as enumerated values. + enum { + /// \brief Minimum window size, smallest table (9) + MIN_LOG2_WINDOW_SIZE = 9, + /// \brief Default window size (15) + DEFAULT_LOG2_WINDOW_SIZE = 15, + /// \brief Maximum window size, largest table (15) + MAX_LOG2_WINDOW_SIZE = 15}; + + /// \brief Construct a Deflator compressor + /// \param attachment an attached transformation + /// \param deflateLevel the deflate level + /// \param log2WindowSize the window size + /// \param detectUncompressible flag to detect if data is compressible + /// \details detectUncompressible makes it faster to process uncompressible files, but + /// if a file has both compressible and uncompressible parts, it may fail to compress + /// some of the compressible parts. + Deflator(BufferedTransformation *attachment=NULLPTR, int deflateLevel=DEFAULT_DEFLATE_LEVEL, int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE, bool detectUncompressible=true); + /// \brief Construct a Deflator compressor + /// \param parameters a set of NameValuePairs to initialize this object + /// \param attachment an attached transformation + /// \details Possible parameter names: Log2WindowSize, DeflateLevel, DetectUncompressible + Deflator(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULLPTR); + + /// \brief Sets the deflation level + /// \param deflateLevel the level of deflation + /// \details SetDeflateLevel can be used to set the deflate level in the middle of compression + void SetDeflateLevel(int deflateLevel); + + /// \brief Retrieves the deflation level + /// \return the level of deflation + int GetDeflateLevel() const {return m_deflateLevel;} + + /// \brief Retrieves the window size + /// \return the windows size + int GetLog2WindowSize() const {return m_log2WindowSize;} + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + bool IsolatedFlush(bool hardFlush, bool blocking); + +protected: + virtual void WritePrestreamHeader() {} + virtual void ProcessUncompressedData(const byte *string, size_t length) + {CRYPTOPP_UNUSED(string), CRYPTOPP_UNUSED(length);} + virtual void WritePoststreamTail() {} + + enum {STORED = 0, STATIC = 1, DYNAMIC = 2}; + enum {MIN_MATCH = 3, MAX_MATCH = 258}; + + void InitializeStaticEncoders(); + void Reset(bool forceReset = false); + unsigned int FillWindow(const byte *str, size_t length); + unsigned int ComputeHash(const byte *str) const; + unsigned int LongestMatch(unsigned int &bestMatch) const; + void InsertString(unsigned int start); + void ProcessBuffer(); + + void LiteralByte(byte b); + void MatchFound(unsigned int distance, unsigned int length); + void EncodeBlock(bool eof, unsigned int blockType); + void EndBlock(bool eof); + + struct EncodedMatch + { + unsigned literalCode : 9; + unsigned literalExtra : 5; + unsigned distanceCode : 5; + unsigned distanceExtra : 13; + }; + + int m_deflateLevel, m_log2WindowSize, m_compressibleDeflateLevel; + unsigned int m_detectSkip, m_detectCount; + unsigned int DSIZE, DMASK, HSIZE, HMASK, GOOD_MATCH, MAX_LAZYLENGTH, MAX_CHAIN_LENGTH; + bool m_headerWritten, m_matchAvailable; + unsigned int m_dictionaryEnd, m_stringStart, m_lookahead, m_minLookahead, m_previousMatch, m_previousLength; + HuffmanEncoder m_staticLiteralEncoder, m_staticDistanceEncoder, m_dynamicLiteralEncoder, m_dynamicDistanceEncoder; + SecByteBlock m_byteBuffer; + SecBlock m_head, m_prev; + FixedSizeSecBlock m_literalCounts; + FixedSizeSecBlock m_distanceCounts; + SecBlock m_matchBuffer; + unsigned int m_matchBufferEnd, m_blockStart, m_blockLength; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/zinflate.h b/third_party/cryptoppwin/include/cryptopp/zinflate.h new file mode 100644 index 00000000..db9b9425 --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/zinflate.h @@ -0,0 +1,164 @@ +// zinflate.h - originally written and placed in the public domain by Wei Dai + +/// \file zinflate.h +/// \brief DEFLATE compression and decompression (RFC 1951) + +#ifndef CRYPTOPP_ZINFLATE_H +#define CRYPTOPP_ZINFLATE_H + +#include "cryptlib.h" +#include "secblock.h" +#include "filters.h" +#include "stdcpp.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// \since Crypto++ 1.0 +class LowFirstBitReader +{ +public: + LowFirstBitReader(BufferedTransformation &store) + : m_store(store), m_buffer(0), m_bitsBuffered(0) {} + unsigned int BitsBuffered() const {return m_bitsBuffered;} + unsigned long PeekBuffer() const {return m_buffer;} + bool FillBuffer(unsigned int length); + unsigned long PeekBits(unsigned int length); + void SkipBits(unsigned int length); + unsigned long GetBits(unsigned int length); + +private: + BufferedTransformation &m_store; + unsigned long m_buffer; + unsigned int m_bitsBuffered; +}; + +struct CodeLessThan; + +/// \brief Huffman Decoder +/// \since Crypto++ 1.0 +class HuffmanDecoder +{ +public: + typedef unsigned int code_t; + typedef unsigned int value_t; + enum {MAX_CODE_BITS = sizeof(code_t)*8}; + + class Err : public Exception {public: Err(const std::string &what) : Exception(INVALID_DATA_FORMAT, "HuffmanDecoder: " + what) {}}; + + HuffmanDecoder() : m_maxCodeBits(0), m_cacheBits(0), m_cacheMask(0), m_normalizedCacheMask(0) {} + HuffmanDecoder(const unsigned int *codeBitLengths, unsigned int nCodes) + : m_maxCodeBits(0), m_cacheBits(0), m_cacheMask(0), m_normalizedCacheMask(0) + {Initialize(codeBitLengths, nCodes);} + + void Initialize(const unsigned int *codeBitLengths, unsigned int nCodes); + unsigned int Decode(code_t code, /* out */ value_t &value) const; + bool Decode(LowFirstBitReader &reader, value_t &value) const; + +private: + friend struct CodeLessThan; + + struct CodeInfo + { + CodeInfo(code_t code=0, unsigned int len=0, value_t value=0) : code(code), len(len), value(value) {} + inline bool operator<(const CodeInfo &rhs) const {return code < rhs.code;} + code_t code; + unsigned int len; + value_t value; + }; + + struct LookupEntry + { + unsigned int type; + union + { + value_t value; + const CodeInfo *begin; + }; + union + { + unsigned int len; + const CodeInfo *end; + }; + }; + + static code_t NormalizeCode(code_t code, unsigned int codeBits); + void FillCacheEntry(LookupEntry &entry, code_t normalizedCode) const; + + unsigned int m_maxCodeBits, m_cacheBits, m_cacheMask, m_normalizedCacheMask; + std::vector > m_codeToValue; + mutable std::vector > m_cache; +}; + +/// \brief DEFLATE decompressor (RFC 1951) +/// \since Crypto++ 1.0 +class Inflator : public AutoSignaling +{ +public: + class Err : public Exception + { + public: + Err(ErrorType e, const std::string &s) + : Exception(e, s) {} + }; + /// \brief Exception thrown when a truncated stream is encountered + class UnexpectedEndErr : public Err {public: UnexpectedEndErr() : Err(INVALID_DATA_FORMAT, "Inflator: unexpected end of compressed block") {}}; + /// \brief Exception thrown when a bad block is encountered + class BadBlockErr : public Err {public: BadBlockErr() : Err(INVALID_DATA_FORMAT, "Inflator: error in compressed block") {}}; + /// \brief Exception thrown when an invalid distance is encountered + class BadDistanceErr : public Err {public: BadDistanceErr() : Err(INVALID_DATA_FORMAT, "Inflator: error in bit distance") {}}; + + /// \brief RFC 1951 Decompressor + /// \param attachment the filter's attached transformation + /// \param repeat decompress multiple compressed streams in series + /// \param autoSignalPropagation 0 to turn off MessageEnd signal + Inflator(BufferedTransformation *attachment = NULLPTR, bool repeat = false, int autoSignalPropagation = -1); + + void IsolatedInitialize(const NameValuePairs ¶meters); + size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking); + bool IsolatedFlush(bool hardFlush, bool blocking); + + virtual unsigned int GetLog2WindowSize() const {return 15;} + +protected: + ByteQueue m_inQueue; + +private: + virtual unsigned int MaxPrestreamHeaderSize() const {return 0;} + virtual void ProcessPrestreamHeader() {} + virtual void ProcessDecompressedData(const byte *string, size_t length) + {AttachedTransformation()->Put(string, length);} + virtual unsigned int MaxPoststreamTailSize() const {return 0;} + virtual void ProcessPoststreamTail() {} + + void ProcessInput(bool flush); + void DecodeHeader(); + bool DecodeBody(); + void FlushOutput(); + void OutputByte(byte b); + void OutputString(const byte *string, size_t length); + void OutputPast(unsigned int length, unsigned int distance); + + void CreateFixedDistanceDecoder(); + void CreateFixedLiteralDecoder(); + + const HuffmanDecoder& GetLiteralDecoder(); + const HuffmanDecoder& GetDistanceDecoder(); + + enum State {PRE_STREAM, WAIT_HEADER, DECODING_BODY, POST_STREAM, AFTER_END}; + State m_state; + bool m_repeat, m_eof, m_wrappedAround; + byte m_blockType; + word16 m_storedLen; + enum NextDecode {LITERAL, LENGTH_BITS, DISTANCE, DISTANCE_BITS}; + NextDecode m_nextDecode; + unsigned int m_literal, m_distance; // for LENGTH_BITS or DISTANCE_BITS + HuffmanDecoder m_dynamicLiteralDecoder, m_dynamicDistanceDecoder; + member_ptr m_fixedLiteralDecoder, m_fixedDistanceDecoder; + LowFirstBitReader m_reader; + SecByteBlock m_window; + size_t m_current, m_lastFlush; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/include/cryptopp/zlib.h b/third_party/cryptoppwin/include/cryptopp/zlib.h new file mode 100644 index 00000000..b5fca51c --- /dev/null +++ b/third_party/cryptoppwin/include/cryptopp/zlib.h @@ -0,0 +1,65 @@ +// zlib.h - originally written and placed in the public domain by Wei Dai + +/// \file zlib.h +/// \brief ZLIB compression and decompression (RFC 1950) + +#ifndef CRYPTOPP_ZLIB_H +#define CRYPTOPP_ZLIB_H + +#include "cryptlib.h" +#include "adler32.h" +#include "zdeflate.h" +#include "zinflate.h" + +NAMESPACE_BEGIN(CryptoPP) + +/// ZLIB Compressor (RFC 1950) +class ZlibCompressor : public Deflator +{ +public: + ZlibCompressor(BufferedTransformation *attachment=NULLPTR, unsigned int deflateLevel=DEFAULT_DEFLATE_LEVEL, unsigned int log2WindowSize=DEFAULT_LOG2_WINDOW_SIZE, bool detectUncompressible=true) + : Deflator(attachment, deflateLevel, log2WindowSize, detectUncompressible) {} + ZlibCompressor(const NameValuePairs ¶meters, BufferedTransformation *attachment=NULLPTR) + : Deflator(parameters, attachment) {} + + unsigned int GetCompressionLevel() const; + +protected: + void WritePrestreamHeader(); + void ProcessUncompressedData(const byte *string, size_t length); + void WritePoststreamTail(); + + Adler32 m_adler32; +}; + +/// ZLIB Decompressor (RFC 1950) +class ZlibDecompressor : public Inflator +{ +public: + typedef Inflator::Err Err; + class HeaderErr : public Err {public: HeaderErr() : Err(INVALID_DATA_FORMAT, "ZlibDecompressor: header decoding error") {}}; + class Adler32Err : public Err {public: Adler32Err() : Err(DATA_INTEGRITY_CHECK_FAILED, "ZlibDecompressor: ADLER32 check error") {}}; + class UnsupportedAlgorithm : public Err {public: UnsupportedAlgorithm() : Err(INVALID_DATA_FORMAT, "ZlibDecompressor: unsupported algorithm") {}}; + class UnsupportedPresetDictionary : public Err {public: UnsupportedPresetDictionary() : Err(INVALID_DATA_FORMAT, "ZlibDecompressor: unsupported preset dictionary") {}}; + + /// \brief Construct a ZlibDecompressor + /// \param attachment a \ BufferedTransformation to attach to this object + /// \param repeat decompress multiple compressed streams in series + /// \param autoSignalPropagation 0 to turn off MessageEnd signal + ZlibDecompressor(BufferedTransformation *attachment = NULLPTR, bool repeat = false, int autoSignalPropagation = -1); + unsigned int GetLog2WindowSize() const {return m_log2WindowSize;} + +private: + unsigned int MaxPrestreamHeaderSize() const {return 2;} + void ProcessPrestreamHeader(); + void ProcessDecompressedData(const byte *string, size_t length); + unsigned int MaxPoststreamTailSize() const {return 4;} + void ProcessPoststreamTail(); + + unsigned int m_log2WindowSize; + Adler32 m_adler32; +}; + +NAMESPACE_END + +#endif diff --git a/third_party/cryptoppwin/lib/cryptlib.lib b/third_party/cryptoppwin/lib/cryptlib.lib new file mode 100644 index 0000000000000000000000000000000000000000..446c5e2057df1be7ae7232267f2f8d393ab7703e GIT binary patch literal 17818586 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%0ApI9ve1ElaoVdcvNuuM6_S|WNy0d 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

KYA{5wsgPnx`Cg5t!rl^#?a`uboX;auc3{%P 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≻tkkhNF2`j?f)h6e3z0)J2=~$@PwxdKK|>&m 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

4kvnN<)wQB>~J_->f^x76F5%K z-mhwa2??B&Ur~F$Ltya8F1!3e^~|aioV{P23S7UyI@yirea0ibF97$AH1tT%cLVc` zz`5!96=2>-Lyz>l+gC8Ihnp@pJs%Cse1UV*^YH@12;v_*J(C=M;JO6XO^zrq!vg1| zXOiPmV7_LeXYViH1?CQcbCcsffk`LF!@xZ+ux@hv4VZrmoSPi`ezib31UFr7_E-SS z@dD>2N4>zf$uSo%8-Ys*teYGc0CTCpxykW8VD2>0v$w}n!2CksoaCT>@$Ur2O%5v8 z{+xod&%gfyZl|wtJv+%!3VMeDQ)|W9l#>x)2CO(sIZ6DD0`pZX&W7HPfO*J@v(O{{ z{s2tj*DZ3`&^rW}PgrpldQ@ID3Jf0E<?tq|h=1(LHPYWcDL8xoI~cg51=h*`X#O|^j4E($ z@{Ry=UK)B-PF@4dw@vg?^JOV;+ktsW;KVpmNn6t=!2Czx z+~nB*$^zvu+;nkzsd5m1i-0*n;N0YB5Ew=f|Jcbve%hRZv-i_3;35L+BnRd5vpv$g z7`U&dp+|cD5imcs;%v&bzXS8W6=x~eh`;@=Do~EZO_wf*4ZQ|nI;=PgJ>u_lU@j6k zH$V6~FgK>5NB;a1V4gA2OZ5X92Yv;ZcTMzCaa3RKbv2h2kL+^tgM(9W_I_{#aFqh9 z>(8PW((?*nA_C{8mtkPGq@hQ8`6e*`XQG!XFXi*Qfq6jSobm_p{iML)kzICrq4w!B zz`Y`{ZgRW_%=Bw4er3@M$#Ez!M+=-&J|{V|{5=57AFMc=d|7ZU=3Q{p<;LI9z#M1A+0Z)?7}bii*sT<4 zZ3X5UE6#@AeZV|v#aX@^qjKYQU<$7@%Hi|beP4Enz#s~{d~;H9M6VLK#x(Q@7X@ZZ z8r)vMeN$jqqWFiU%k)yVNeiQP$!)+rBe2|`!JiH86~bI^k(Z{K%HkS1v-!4@}I8 zv-knoV+5G53!JVO3y%Eid%!&D0rxU6{}ni0FBbmhf!+Z(VtfcUUAi2Wbcw$XU^WVz z&Y#6@rNE5}3?A8KXE$nJeai!GI&j}l!J&M%q`MTjJ5q3|en8(y?kWiR%Q9 z?6Q-C^spucr|~BgS8^T7O1 z;LLWD^a!{6w+fVnxao4^uM?O)fpg-ICbfEx>&(FuxW!k?wZxr&7Jz>0;lt5@hg%e0nBAqoJ9^Quf7G$&jrp+ju(OXhZ&b52g&;% zVCH;>%i+df88AUB&cfeZ&|3}6xdP|L-{*k2+Kfx#kMhyCf%%~oXGxdJgZqJb&y2IR z@3dPAl)Z7&CHPB8m+VmrOr5|@$KSGik^aK`512~?&P{*U0`rI!XOV;S_X04}ziZ;p zR*v0(In<0xk%RPi3^0q+;7E=dVAcwpn;d5V^9_M>@_X{DyMcK|;GFbKxaWcSo4~oH zJMDXz&%;fZ8*V8urwE)Ie`f)6iNHDWNBR6Kz}%jO9_jDrz`Q4LZv4%u_rU>*}VGk=T~_RkO!dJ&kG+c!^ z=~A$$!mj|tqa4me7;>5c;B?jNR4_rg2TpT

Q@Ye&cm|l)1WwnprQJmKExHT& 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

EYLWe^(4@K8KR^lF4dII@I9r2? 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

    0GVTb4^(DO&yLaan`_D=JP2rmBgs`LM!IFCF|<+ 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

    T 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

    C4T!~E|&$vdOBmW80908nFf@lxvf;h-l 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 z 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

    Uj>VHJJpB=_?3NTd%WvGvbvpIzto%%yk=F(Wh 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

    {;JdDUX_blN_C{LggQl2u{V~>}q@u=X5DQCY* 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

    (+GZtByh2 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ξfGR`-9o|iQ2%qO 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

kKYovKn0=yA6J-2ly_{&8 zrb7Q6+%xZC6tUz1k)`ylTR68F`r}eVui+OcS!~9wjHzGFk$44~N1B>sYVhnCXD>AY zk!f&&r`qt|bSCC~E}D#~CXw`zKQ|vfMSmCW-Mm+NV1ETp?TpO_anrjIfk85A`l2%z zCdImj``(kE$AX_%nD_lmP_FW1pPzY6zYO>4v9H4fVQCm2LWg$3Q|8^{__5ZqL^AK% z%zIz-^Qju4Enl0qrYFeqwdvvXFP5)OZCUvGun9~m68S2DPXu3kWaTT>poK$C&~BT` z@86T(`!v7g=0OkI1?CozQf4+(S~f$+ZBm`1>#ChTjf%Cq*uL}$nCsIR@u{F`-)uhp zi9Ur|4$m0Zy_!F8Lojg#=7ykgRbA-mK7GOvN}EQyKJCM}0&{&DW#c+2TU=kIPZiBG zT%U^Q6EIgB=|S|VTW<5BP*vz4FtVt-6|XA8m-P4zqYnkmGu%*J#iMNqHFw26sIkR^ ztv_3Vxv{u;Ec_U}Vjuhc7kIb+x%U3Z6a-fEc?_Xz_Kc%g(da#r48UpP?%%~#Ej5e3Qqv(BZ`z&%O(3lK(%Zj_6R0awS~;tqebr}f zCR+{WtDyffS+rdn_VC#%sDJL*WZg(cAF}E;H`+e~2CcHI9%QtOvqXEHiS`iFUNYJ; zHY~^-<)_>TX_TL`5u)kZ&?w(#ZMb>qjl0t!~Cf`3NSwc!_&;K~ne0^F~UvPBJq`>uS< zw#mN%LYvhNoBVcnrDxk+w7$h?d544!300yM9*QP6k7lS2U;5$80r+CxL!}(UAXl2$XlAh0=d$a%U~BKo{*Z2KD*Wa=hJN$+ z0Dd9NHu>8Gn%$W-C!sEpwstd_+}7qYoPCB_!YjtM_SbV3_JUA>$6@}h2!Z!0%*W5Y zPl2U2lYZ7hv}TLZp4+<=*xs|NVtHgI%eJ1~)H?iF9_<|pEJVCFft@w8o*DZhelOw2 zVb>q<`)~Z%0kZ|+P=Z6BKjZfret*I5b^PAIkHg;`_;KLEA@XPVeU9Hw{5bI9@Gb|x zZusTm7sii6Bep^uj<9j(0EYvzA^35KG!(xB@#D~h0}c*$M&ri;+F1P9s!qU<<7JLk zr{c#Uay@=$P$NAveaNYN3dLCqI0|AFj=YPUJ2|BL(Sq6(X<>J1=q$P29w1Xe|csgtZ+Gk zOB-%Lc4?yz(s>dhAY9 zVg3>(;=)@xV!wd-YnU&=yc=dA(y$&T({c~YufV()CI_Ftf%zUx>;c7g_;?PMZ`$xq z@rw;GYhYqp7UKfjBQO`k+ys-0a(q7zCgd$*m%zltF7_>$kHY*R%*SBf>3`?4&=YuX zgZU)P7yS1>!+aX=@4`f%!blw_x)7hcI7+$#E?dx5v18`#Man zs$f1Ai^ALn^Hi8`!kiEDEtqkbe}~CM5Zt;JyA$R+Fdv6W_kV!-K1?oE`~&7t3# zYZYtrsgU=uVlOK82gSB2_LgEiq$vLJkRqv|cZgz#DR#7ClN4L3Sc76eRqW@AJ)+oF z#qu!UlW@EHRM6X7F)SkbaXD16QHq_Z*jb8Qq}Zj3eOs|B6~i3U50{s0NqRBw^D(T+ z``GUlJM5{lid*lmivsMsGAquhhU zCEuqY&7jy|#g0{Ms$wTAMqvy|$GM7KsMspSE?4aPiv3WrhZWnR*l!hkQL%Q#c&b^# zE%K?5*GI8q6vJHwzCG@nNP5p!>;lEUq1g8o`=Mh0rP$9DqYS^#Kc5PEy%p=H*hPv_ z4o~9D^#pPIZN>hk81L*9d!H!AJ39sY8rBrV?a4kB^cE=gb;X`j>;=VMQ|zybU5W)m z@vp_Fg5I|kyHc^gC`S20iOW9}+o9MG!q&eVd@AVOuGpQ5od{K267ESp1zrA%EmCZ? zV&7EkI>pv1c70Fl-;F*6@gK#0u2^l6wKv13g5Dg(<}1bnG7`VNd@AS-Qf#PV!Cuy0 zPoD~U`zSV0v4r-ELaVh=0!o?;&=Hgte>d$3Oh zy_t%gqS)n%eM_->6?;IjFwXBCW#UroQ_zc`SiNG`Dt5hMPbl_`V(p6MV$Xs;2ffig z74nW$>V_427btd%Vz(>yvSNQ!EV!R_ z+ta6l-l?D{MI7?x_!RECQ0#ui-c;=GiczD4xE=DJbD)y0LpDK390XB@od z#d`P@_EQu)TCv57EmLf*VmB%FoMJC1mOIFXQQ%WSZx*QIONP#DRzls&5Hd@v0o^LBaU3j)gzAEFcJyiB-Q0yc~$gHi*lJ*(N8Se z<~iu67M+z59p|FYS-UCdvx3TjzxvVvUz>@;emv^e^wt`bI^~ebLB@`0}xl`(yk#{>O~(^5T~J7)aqa3fA+4-}XV} zv<5Halw!IE@yTN&WpAJN)v|5pmHA0h|Ht3QWL;7nH%Wk|xLy^l#`DBPFH-hdq-e@# zt@kl?+YhdcZ>}hNH&S$UTcq9aCEb$(IHgq>Jg5>9X?vQCJP_?(Cu6+F59rk9QQyGZL>w zBJsKpgiZ1gTORUB|50#+_1iwfEMWvk&V@b%R@q(YL%1IUQtCt)j8gMEl(+(Lg4|$+ zZ^Vze_ym3n4upURV!?bPKPbpyg*V6t=E>>!W!J4Rex#AAXoI^nsfsOtM&c(@6|%)I zN8=6i@C6U+Gxx;@f$r<$A9eF$tfV_&R=|YZY^)aM=P*x&*$#6B%$!^=#`9?1V15^7 z0OqwY3t)23zdOtaUvG-vX!TcB|Rz6~=$zC6rePH&5$(5u2Fo(e0 z8|G-3`@$@Pxj#&5R~!hFqV~{w96J@}Aeg7aJQ!vS<{>bl(2JUVW8Z>#I84eCjD&e3 z%uz5m!W<3rHJD>y7J(m(|9gm6BYwyKOKa595TTZ-ElG@A_2G8=HsII>z2OpW=0amzN+qI+iPkZH)Uc<|<56EQ?VI z`}&vStrsJPRq=PBlrS-|d)bbnDLWFE?Zo-Y@hxldrKtG>csM@J5yJ8y&S3jmH!I>T zbcn$~EnB@{~jE(Rj;J1QNj^_(b1m(cNMEHY|t?-w-L=x*$??%tj1$7PNNr z1F9_Bu^= zGs<{hi+6c=NA+Yg5aIjR3_jF3d35&N^UVP01ZpJV@L~Y0u_a~`n|_pv+H^o`91s+jSOK3PFe4jS3=m6*`v zUty9i?*$2+g}pempg`tvi1YRMF_i^K4dX!JL2@yzo8z>MSq%*^$ZG0~EC<5ugdm?B zu~LOo!f1TL!*a-;uQ%xH4B~mGK;0wD=BY5T*ka!I^WPaXdY9NFm~&tr3v({a88GL; zWSfi{5W58CGMH^JF;+LyZjCU>m~&w=GcSZ$0TYc*j2Vs-+_5DvFM-K=aVg9ZaQ_P8 zCp`eEptne|vwbS)U7*-E6uVlnA1HQfdr`4JDE5|O?<&TgTH;4lcM`wD z6&s`2R~4JA*fhmXQ0#ie*f)!R-1(6(xbq{}cEvc?5$sdN+7-JFZI8Hx45Du@9vQnS zGSYjQ!GEj(b8$g)d09Sx>rd)Tke#jrR?;ojFlmo zkCL*RnrjYj8#$WwJG+B zVy`KN9P;f2d@AT2r5LA562>gW(6Ra0R>huB>?OtiTd_A4`@3QvE5;foVe~~KD{&s+ zQ*x#9fD_HqsOmwB{h_^meXP_fs2cvNyHvXJe6YQSw?w>aE(MOZR+kQgBAjdP!66~8 zl$w#W>Km$V9ar6Yeql6GUW^N;a~j{NSpA!m;6v1`QevU9hzhU(RJZZ{=dp<}hZfKr_(AmcH#v(pOnV{8G|XG5 zysKtqd&9Jv_#-uCpVt&k+8o8iq&x~XUI=w!fhtTZVAKE{URBn%40kHZqW1RvpuNjq zdTrl}0d4jMXr9hu}4CWAgpfvjY)la zfvBPutS4*Y&)1ZFRMfH&Vb#RnuG;WAV*VL9frLT-S5?{b4f|D@^_(%E~oMLk@$y+6LQK|Hs6IVxDJ}EvgjBfdYoNB5r z+g^;~LM3MBn;Hg9Z`G|eDCd={Q`g?B;#++SHESaGq7m^>qL)KalF$83HNziX0Cy&S z(Rju9WaQ!xl|5E8X+xwv&{TBSV~1?Pr2M&8bKhkxtr@k$^TP{nApKN^3ka{P#U8heWVv-YicYi-yOX%Dw1s&WwR zH7$YF(3w}c1`z6P%^GaoY^{!0ln$#|`Im+fRq@{;%Gw_J`5ujjiz{14td1t8qg?_I z|4Nrk;PhxBY$Aa2$EKrZ_&*S0cMbnByj|OX>@%$m{fV^h2Yw9wy#Lrl<*&#XVZTJBw%Za6EFVY44$e8y zdmtwt+Csu!cVyeX-6SifYqU=T4|C1*aq{=5*{ESz9W@b&ma3-_T+9Rs5iMX;Dn{&d zgB2Sr3hYI^KVzbb`yybE>te)iG4}32c3koQxO)@8D66Y|{7z=FFf)*Z&4362A|kj% zKtMoD*i1A)6kO^?0tBG~!4SmV2>~S?(_*dFs;y|Sp{@PC|NkcM-1DCI-gEcuoO{m|w_JJ?54Jqa97xqvFBNHaBCSQNyTi+q@ZY(9R!L@DYR+7sYP@EG>XCRLa)OFgUiszKFo}UQaK;$2GML$5Mg|efkyuOwr8X9! zGs4MZ36I5GA+=a*OG?&|rFFA>)_ceb@P387Yh|URo++Wb2MMG1f*}bEq z^P|Bd{olHyb^E`0e7!?}_q#hZ;Vv6A4rj^T1b&oHEjeR<3=@O&u_Reps^lHJAAQkT zhv-lsS>>%QJ=?$j{ETsqGz9pq6~0Rhdv24tnMWdiSvk>y*oR&Uz5@&kW9LZ|eiPRU$`$(v6%a`6#yWCk?l{Jg7`V>b&sVJ2@0(bUp9m0z-=Sq+2y z?$1&8z|uV*f5~rPjmT=iR6xHC@RivvsZzm)mC%zA`zI<_es)%7G=Ct|!bXeRnQE2` z-=0Oo9u_QFmPE^UW+tQ?d_1Fe7d0N!FXi^8-5r$D{>%!-q6XA5!?rQ8iqhm zPAE7Q0cK9|>K$87B3!7+ap9hTFyj*LF7$)!IZH)#o%WhvL9^VirJ88vLX0cH`KBXQ zi`T^C(b(^hAw|pLFO~=|!M=sCITV3%vQdl(za?(Rh5VU2T{E{c^kLch3q>T$bin1P zM=2MlY2FBlER%xgw|nKAZtGwoej)G43QW4}hfIn>t=1D>0S)qHVNZsh67j%VEh3SjpR>e7-_q``R_1?#XW;OQhoELh<|6ZUO z9rozvinU zEClG0dN(o!#hMk(a|(LWX}%gt3Ym>KO`##u_J{B>LyfM?AwEqiR(3}!LTOX65)7-> zsrZESCa;?7FVt>~aaM5Ec_`Ej=vjd-B&m>@xojZZ!XGe8tdx-h_#hcsm&??F$}9b| zY>tN7&n%^I&}*~vW%hZn>1PX-ZC1T?ORAgHNrJ&EdsWO|FrLn$RWUC~{;aUtkXC)a zL)ws5eLpSb?|YOz+waP%xye~I*Zb-(qQ5gsC$0KLp|73TR=#SZD3=;4%B8xcD3{`} z#8t&UQn`1B<_118CuNMyV4iUrsh#0eU^~h5Fip1JYqNDYV$RC>qp|XBT8)8QTg{JaUT+=TO2z#;n|FbEt>6XC!Rm!VcXygkz?qmcsTR= zE1tjMVIi}%v#oHZ$dQnRd>|gSc(!Ba*ui)>Lu94owY{V9P^k=OW#jQ2g@^O1Qas-N zCzj61csNVoeBd-Zr{m$isKt0V8{qz^bCEMtGSdUHgciVDV5f)86ife%23Jo{eaD~<#D3%46Ak7ExE<*FDXjv0Ca}@g~A|m1em``)yEvfnAjA&H^Sz`neSEhor}_y zc)#1ebH#Nj-XDSu@ks1x`~A1DoA8bdf|^tlI|X(e_AJ;C{KO!VHfvx*k&F2u?6t73 zgnbum;#*)Nd9jaSV>%zh<}ib7h+)&0`3dY%u&;$Z3HEicD`C?=kEZ<$_Ia>xfPE?K zwXoO1z7h5l_MHo?oAAzM)X!n(gs_Hz&EE7D*oVQs19l1Q+hB9~b35$QU?UGiISaop z#5>)e2m6<>sg&g&*f+sO-o&^rx*ztvupfYZzkTQB2oK`@N!ZA{*e2MJ6~$hFP5)HZ z@;K~Wu%Cdv+rE==@D$#A!+sKW5$s>XE{5F#dzgLawx)G>KN|LW*eAlKKk_)9f&D4U z=LI~o_jUXWfJ?h*cx2?O)4!70eK5)354%ZcRTWrM z!%<$QxT778s~N@3cesTP$1V9v4;wkGyVVYNxx;bFtnN5LR(el5T#Li~-r@e>aDR2U zFB}dVek{FxEfh8fINVT&8|83g9qwp{JJ#WrI^1%HV?UsAhDs+J=er$_DwZ@I>m3d% zkt`0%imcx^9qto{gNh;R4jV_UyDSUgK$F9bbU1EV*SJh`xY-Uj&*9E-I39!5`2E7+ ze(7+$zCh{maEH1JqCG1v+d^T}&Ea^YOx^K#tGYYF;lAT=+(@tPE^@dAhr7k$c&Js~ zZE(2F4)?Od@yM&Xd(YuMa5$>+*0`K$p|Dx%aLXMoj4?&sb+J&`R6AUa!=3GL96L4K zA3Ge6lq&94hvSh_#jSU^jSlys!@cTopF7;w4%au^i{AhXg-waWO>($Ohnwke(Hzfj zo`u4u(BX<4Zl%MmcDQRC?s|uN%Hh^I+;)e1#o<15xIa7Gex1Cy^tVvh9N}1Fh;m&rrWe&H> z;hG!{8%b=vy23(XbBn|M!r?YM+*XHs%i(r7+%cFHX+520ACrXyrOWDTXW-`W>V>!{eo6J2!VHjA%(rzRY3obz7=QAG zFsfhzs|K3lWaA1aYdT;P3Y%5EBw{PL@r> z6$(>pmM*P6vt|ZZ^^hWQ7L&4piu^A%dwYK?3AKAKWxDJdpQG7znaeIhVbg#(D2^GY zxNQ!{j8hzU$Q35-k6Bps22K#NO#ItoChvnA0&%0@;EMQX6>;46^(8ibKQ0?Hp8o*U zFptd*tJ8LgnSM z=BZx@C5V%=;W}5Ya4SSG5ZvSLKW{?|Hht`eEi_hs9>>0p$+^2jlyu`hG)TJt9DjTD z>DMIf6Sx7_!`&vKMmA2qMlOjfmW%2r18<&swFcWX`JSdFpFD94d1<~bnKVsyjLE-2)DzXUQj+3`%rX`ig(pkMSKUgI#i6^ z&5bG8@enLq_1pTv+@X@k9Vrprd#K?yM~^Ct|ASI;?<_!h{H^k)(+j3HU6kk2(XYH| za!w-(0GC-^iYVIjm&Uu4$0rvwRTPIHV4ofTicy5Lesw&*c|xEm5MRIjgZ)o{X?Pbu zuLNI=tdDPQcxU+V;eTECPR6(ye zuu6u!@X|*TO!utv#*N75jXCAa>jsq7Z4mw6K+*pVxF-%l^Hx1v|J4~ejT-c|NdF6X z1z2v%6=3QBWqrid-Sm%)J|UMiqC>ZbP2I;Y<>&S?NcmZ7{ZjsZh`h@7Cj%OdmJu>P z0A#PA0;JbXWx=1~D3RPQ?#OjlDgPCKR8r5msY0B6D#QwtEVI8Hquntn{m$EPH3Z>3 z0-K72)%d#V)Fo8;;sx~!suz+)$6n?#EVzC0t3)p|O4v%|bdM66H)c?>pAe8c8M?}D z=w^g?p|pF1c)48ogePKI-U1xBCV^$>LF85oyn(syiOh9-z+vL)myjImv4Vr;{bnJ` zC5oDZg|kR8-%EnX$(V@ClspkX^!28Q`19ckn;T(N`8X-6`BkRMjq3FzpNo=UMN%sH&9>s7h!g7=ak9Sa2uD*NCWjGjro&>;? z_|XN0XC>mJTx7Pq1nVk!pAr~ns<3?|3kQ^=COeR2dO&(J*q2SmF)~@fhNB_d%0P7U zBhw&l%z~EqP&C-h%YWYY;YAjFQ<+gc& zZE!q^rCW)9E4ay!Ck)0lW?hn`3V%T#mDM|%u>wrsHY81>R$Stbqm?wRxVi&(Ztw&k zuTx`@QO53d&+ID);)}gx+mkRgiu0im>?iKqP%p_>9e5I^6=`q9Sn(4tDgGk15~dZm zbx6Xr;&_|MrgO(oEM|5CbCn#&RYlhL@al*}1S|*}2f4QC^!^vCyOJ z*?w0pJCE|ddc6c?E|fB%`ZzP%L6kDx4=K}7U|735Drx%107yTOi+Ok+!Hk8i-n$N= zElCqQ;0PX1s>CkWFHK^lqvVJKEPFtXsa1G5OrD2_Mcp#+GNg=7g3B|M)2yA6+LI2SDpLaYhI z28-Mb{y!&>TVQhv^&ISzU_TEVvJ}b%V)w(|4!Z^Ri?E-y@0{ShjCW3k@Wi?x#;?N8 zhs}3RyIzA`2>T7#2f=<5_Td&k4))u4zZ*8rn8aFOzXSU@*zdxA0rnqYQ&l3rqso{+ z!u}NDA-=d5aSA(3XTTg10|uSX#HuFNowuaEwz6`}n6@X|DPjt5rpV#S&J;Z%1dBjT zd!h=Ki04XbwfCBAyHoeydYTS%v)}((nhru*$?sNn4xuon%pPv3g~FmfK;1Pu+)d8i ztq#X}sO}zixb+UV(c%8&a34F|7Y_Fihs#F&QhE^!g+=7AI4(j6K{1(gN7WCC<8BLe z$0eBJsvVBU(G_>L!!2{TRSwtWa5p;KEe^NY;kG&)WilErWilGZerOkp>u;g3VVhCh z;SN{sa8n(Q`?S>^B{515Bb~)@=vLfs9B#YAQU0oadCi5o;~lw*`;mphvfop2lz^(c z_0HW!hkMcCUUj%5Gd+5x77ClG4tJcxEpfPdhl@GfN{5@4<FODq&N8y#+o!|imq zT@D8Y8teicU;FQ=$WG+L=>-eWGw2UIgGsZe+9Gw! z6+`#bJFSIpZ-Uwa*r(=#TbBw!j(Oz26KW||AKXJEhn(;A!h_8+EJQtkgo~SK#Qf8k z7|YcJOpH@{zDt4NofCop?0Wk>X5X=q#e{(0YTvincTP6x{&%pU*CLjS@Pe@ShfViG zU}wUn)+VrbMb`!2ziZ!Fw=nRFtm$`%r%p}?h0Su%RNMs?3Uecq#l;1nkVX&)VLltCf1#Ik1lvUmNfKS}(Rb3mEBxOn0kyY412>%U9D>H@=W9 zt-k`Udf}mcRd@V|S)Ev}wJRR3{rt@^VN0Li)wK6 zPLK4F5vQh59J36)ftJm90^-LS#7u2%ivM%Xc$jO(zI_4QCd?Qy>eB3D&pG`^G#6CN*Rtws*N+3AbMbI8Q2 z>Cnzk^hj{cJ$X936H-2d;u`JOFwUTP?(TIsPGzr=R>sK$A@l-()bA1tL2VJBKH{#$ zLbyN!nXWh-5EBRrs2y&)!?mqouzp;tvp2zWtN3<~uiInTuTlc@XYn zqr~&|`={FqAe$$k0Qxr)Mp=9t6gw1DG%ZVPf8hR+oco~<;W_IhtGzVmLO)7Tn;L%vNcBUP z#U<3jHgY-=yRfLxEDH^9`8X@yIG^4cSxY!$lj0h_RU*%o)(!-Tl~!?i{H)Q`-+Tsi zHD#bBoKFLDYO%i?y2}1&`0uhKjh!r z0v!ZM=?w=oPUy`6q;pi}^Ra@v3D7)&c=T_AKyLz?jTVY?s;H!22tBOOOqqP;1wGY* zBj0SY;4pJB+}|5A5137DEPfDJPg-)GrSzyE&5iWEvox%_iksJtMRxnp^JR9!C%oEP)E)(^W zoAEdE7;-6btmf?h%Kj+a^CGTs;Fgp^ z#Lu4zb4V89HeBrmJlYql=dlLC*G>(SDU*-P&+3aKp&7xRJP{nt3TGV_?Hbz@?cOcg zy+^dDhqr>^>Ls=>G)dxl5b2^Ca8mbggwV`y=pW5IbU$B!HuoF)yX^1QW>Qrl!NGwc z=2MsbS4;APZDzmvxhU|MnVpmkUiLSjAt&9}_Pr8ISCAqtSQ^ETA z3zkZCo`&FGkQ(rDpkLs-NkJ5hV*y5o#9m{Hejy%x`z|n^{FX3yQep=X$c!Uijv( zZNEe>fh`%aciNTXZlo(5>5RSOuTq{IH};M{Fa7W!EOm2`mYaH`cSOj1ev_usaK5}l z@<4ys1*qY&_k1jS$!6TsvX^Dcdd20hC-r>}RWkz5Q9O(GF9IrE*J6xd#|@50W5 zO|}(!v{(!_&Kbonh20JI<*>WMz7}>5*qrM^CM$~3_koSa6u|BeyEklh&wXH5+ILE} z_|8^|@i_Jf?7py{hushM=de4&=9G}`J_Y?t@SM8W>x$MZ_{0E~vXbb)GXB31kHcg! zh_t3No>2F{5RYO1N8&N^|42MW{U3?P=#IqWAXJ{$(C&4ON+@j3cDQ90(jyS+uF2u< zaPD~eR{e5Dt?qv1aDQ~T4;@bSWk|Sa_15oF3q{Owhr7(-;tqG4!`6 zF*@Am4#$&r>Mm@duo>iVLmaNj;hG(8gTwKZuBP{8hofF6#qrW54db5<$EzY0*Tq6% zb1~-G&)_X$R#*t@c|hu}#X@1T)#0`|+*=OE*}8`NH;4Pu;dW-B-;^*YIVKb~^;i}k zA-Hob6gJ-gnkYCP0U{JOJTo>^a6B_cC~Tsgj5$egc@_$r9|1Z=aMxH!ID&&w*dOAN zGesrH36Z^)rNz$Q3v7A{X+rZI$Kg=g-U+53cV|Rtd`p@=ahj6O<4j&Ww|xd+;z&*! zZho>5K%M3xHf@hIg(a9Ga7F-EJ}w=Z>hxHQhiCDvw7?tk3xW0wN~F~Zs6*@tsO9*m zT>>F({)%gYFU8$!p$HF-TO5XZfg&8#ElzH%pcd`IcmwaL0^2C};jhcaHoT6PW!Y98 zDlU1@kBvKko)C}5a1TYS;T?n9DK_*-AW~VLouahs?yPR?SFAK$th9VE2O!##?L<>@lz_ zV2_1;B5Wwom5XqWgw65eUC`0WLP#%OR@`FyRWDvv+{F$@j*Q|sJ5;~7IvhtA#bI7& z-4$9$MV*#QS$g8|KR=2N-ZTwC)r#N8sV+{6#hWPY8@p>#{Ow7(6J9SJ``q$8C})MP z^})Qzqqy{pGoD7JTMI{}k5lxim!Oo!q0U(DL75ta_EvD!O2=-Q6#pO4*gkYy^J?Cv z(y*THOLHGC4NMJgpEPzIz)q8LkN&!B-8-3O!#DFwhK1w8$SfPU*{OPuv}cve#W@!B=x1 z4&_Z49qP2~q|*3vc*&QSV{#wPC>tol|_l;i}Lo9Gh3OPq*17BsF zk7H~vtD!n(FgOcJk2s_PcA?}aZms(`{*232ul;?2+At-h{ap{jWO*#0N|>_|xqe(u&W5LuFaj`VJG#nP0tNv2{hZ4%_z2;{7fYw90t~V_k^rFy>V2 z2^wzPnr+H|!)V@(YlciG}`nWC%DE(D8&bH=SfdiGLr; zHk2F||H0U;P*cWbx!>A)q=g zni-7bK!;p38qDEnsY#i2!juJdOY8MaRvA)Tf(JV-BsEn0HA3FIr=ls-KVE z$j#-fgr$}0&Ci9nKogSPFoJ3DZ@Iq+U!uW=$$pN6-)Fh{3^nZU_cfEgfb)E%@eyn| ztd$SoJRhmkfjlNe4Wufa19 z&wM-!@SKl_X}=H;Q~EJu z9}r_-fSG-aQXzDGG0wyI&W6o*jze_E2HFgp(>&r2v+pBee;@B0@F1;@O@X}z_6*op zz&^{qb0p$Bn-RaW`S6|1?1!+~a3E}nZGe3ZY))LSg}n z4u|8wr0%fs$kN;2;SO{-Hhgu*ZdAi1uSId+akvW{?h=Q)&f$x6=n;q_6hkMZBq8L~-et8zsc|huQXgbZrSgDsNw3=vMCKJtO>B`IE zm+inDXj1(7X_#)7HkSmNL2>w&$I&p%t88hKk^o&c>*1glEbojFf zq9q%#c($}D-0;rs-PvYnA54B07L8u_hi;KKN}GBkU7RS({CL9d&^3664@{i%0*~m; zu=Th_MkdaOfU-`U(ay~&A~HG^5O0VN$(>6x0R;^caFRgCeVJfyM72)6-)thXhmE)& z>{rn7s7X7)mXUo5^cCyMDP?}0m`@Lo;f*bBfKV$8uybb%hOlG-t}QF4{}tOj?O|v7Ky7@(WuAgzp#QY zstNgce48fU{*JCLF`gcati_<0eMB@kJ&H@qhISw3`}$pe&C;(N{JMk3-W}&SM?{LC zO_v&Vi$tR?x&HRNtc-+`269T{5@g~u;=S^I2!`~|GFhM}>ak7s^{lv3HM~5-==a5- zG&_B2cv&Pbi6>PCdo12>l=liV3^j!F62GU!ko$nRS|}0bkgGujlcXD$XfA|ekEcy1 z17|PIE6X@?Q%<2|NI_9JKXOa?j48YpsMsZsH$HG zAuMiy!(l>UaaTFqjShEOG?3w2y#=X@h*gs?in9d8JSs=jsP zVVOS4>5@zaA)KCiyA!!&)!i@XYs%Rtg|2nBc96i z8Gv~%C-sHaC9NC>lgHNuoec`cbVtYf2~y>C9*muxh_jbq=fN0YBCat=v})#uXP8H2 z$Wv16W09Qx(hcgYv^pw^(^f}Fr>Kf+ge%4Uz(Nr!xwJU8D|Ppv!?ifv28SDsd{B4e zEY!golKZf&BCFF^k^V_lWFUy2n!8c3x%&Q`|yDCB`Y-0GPxRn+PQ){Zl{m9|&bGU~b zZk@wD<8Z7ZN{>}U!yp?u??keZE8?XE(u6Bh?s%oo5wI6Tv`Sic7{O=E%$&oWarTdCqv6W14OTD+hE1l9=du zFlJ$-NoFda1y`(ARd~1|L5*+DJELaK1hV4CEnB=4de3U+7J_S3cTi%Nap^*QuCA}G zI|=>MMBIq6c-fK^$Hn6dQTwLV=w-kU9M-CH%9mhOb$=gU0DX^ zYC-gv34%A0U{-Kn*+RliKs~zqxkn@P^H}UI=@N}(dL3m?Ow&0_^K+7h(`h((033F9 z+D@p?-oGpAIy%aWW*^{3a^D6RTiFNrCx9N@et$d?{c#kDWxg;1jPGf9s8oPqF?s2> zg?Rlo3(mGlPj4~{2Pf?9%?sLbw_@0{j&ai-7I9`09-1>l%CMggyN7*e8S;H5>;yp&Yk0&vIJJ0XoHRgW! zPz2YW zdAL^{?oEe#-{C%TIC5>29;Z)A?@)*1=4ZuGB&F_n2uN{0g`rP?;OQw%2k{jH_vZTU z_QgLvZ%f=hZP}vPHFeYHC5hW*hW@Q-3uVz2dQpVUxECYhNWU<*_-T^We#xC8S|o(R zW(B?}?otbdMFWcBUUoQM5xskD3*JL`KE<;I&)k$;V`oFd7+m*nTZX_aUfD$$qdXAOJa|Kk53Nh8#u}l5A0qO!|TRIA_I+b9K*!p6cH~wG!S14 zTV=sR8+T%eZIayun;Q9@W@95yuNX`ZOHO?{E~jOAMCN21GT|-;UKC!%acO>8^AqGQ zkKGK(E)r7FG#58g;_F}$C0D>t@tR5TDrln>kvf$*eGfhiCacY-$1%!=VHg2BC> zBHy(*l~Y#?#0c8B1XX+<*qQ180x zXb>6tfaF@n?&l}P?IJlbLsAY>~MG#pUlv80jba*va@NDl4+i{ z8|r2&n;My?Aj^I|_u&zNct%RD#-Tw~@|8MqS}hiqY}z=g?BEsT~~5l3rX)v~N=v^4knlQmX0io2iv_oL_aBM7pJ@|u&mnPR?n zD=ecO=rcm*Yd|WIVT)2Z%m6?thbaN1a+sq5sl4WA4&n?$aXb*KRDKLdDQ|T+%qUW} zOEqS-J{^qjR&4pGtX&E%w6)wZF(IFw$y$Cg`#=+AlDi5O=P(4WfS+VdH|GQfn4?9c!(H@m z3oZxZ5bre0vZXbZbv5TKs9m;H_m?m-$QyHqIOSYckJtZF-c`%p$(ZdbsY9^8F0rD0 z5g9|_PV7Bydx&HOar524$Z(wUD2R;0ZywOmJZ>S=!_5cPjAH>H?0JXAore4_% zjJ|m_<3w|n`O-X#D+?0=*=-jE4Y|?0e%^9*qR#;ZZU`)+;k`%%3+R!-aOCJnIifI9 zB9fmK#KmlpLvaY`a6C}%84XA9lkIMU<0iB;!ZqHcMs}?9^T?x~SYq?$#gafpdcoQv zr0Oq{vXP?TcM(#ymI*UI2~H1;3?%m0B;*&8C1=6YAXH(9DrJRnmh-p|?!}!SOeb*b zA@1`eAYLZBmflfOvQ2H!e>bNmgj+Ewnppr5oWBe`5!{MN$dAl|y%oUmcr8^wuoiMr z#1RzNJncaMN8USm!s&da6~J-#!Ik1EA%G)8ip=n~1#ny-E)`eDN*+^krV&gpfLn2X zS^*pbzgWnq0FH7zB||x1dI8*u^Sx@CP5`&!9Pg`V`_+MRdnT%G<3wn$JO%)d(q)Cc zNZPO(TQxuW&&getg>EZ$PRsl7B(R8bf9l=ym=}(S(r)bLi<%@@Lq&Qxd+HEL8RdW*i6fZu=j_(6ZTNppTLg6{tWgi*f`cCSA=~5oAS0V zVN+&;nL+Fu*x$hBkpjklJnRgl=NQ-_*w?{^rr{XJY^IYOKdRNyMJgdxD5AI}_G{S0 zoV%3{N3MdpyUXF8ceocF?p=p_-{CqVAJlKYg~B|-WpVu-j+{YtN6sK29F1_e6%L1O zUe+BXR@U86-Du=t#;cjubbq@E8!)~J%{_g!`TuIVL*!!_274v$5Y)Fe)E(BVKJ1IBLQpu@@(hh*HR?(ejeVEGv@ zzRs1R-#mO~G^Ph^G>9ZM201-ogA|qwyVgQHo?%{{iyubCV=grs?J|A~ymlFc!sZ;f zQQY|!3iC!oi~G65ZFab=4p)Kz)bAt<;fAXj{;OXac9L0{tY%~_Fq7k7O^xrWh`(DF z|8!FB!*>-Gg23dJf6iUG4PS@!h*AT+(A?08?kE+j0I257k}M@pg&_$ z{AvBPd(CQ4DGPpFKK7HkO_On}%a~1<-VPLv=Ya}8R9Kj>vjFa1vj#57Z?IpLQ&5I0 zXo@GTURX4E5)Tbb9{wz(5eZk6Ok7^Hmh`PA4(Lo{l6_Z(oa$GfR`LNpnl)sOlu%_x zmApI68XjUR=RB(Pq8iZeQB=@*2#D<`WUhD6t$=hjcsC&K+zZKC<86VS1MW!h=R)Qq zKg~Lq=pHZ9)aJRpj=wvT4qYKJXCzlgpWhTM?qi*wu|qfi5?`L zcv66)DQ^e)J+}696;qG5fLWwhGw~1@+x7xDRHJf|TD((!&a=xq(5kq^D#lxiJ~ytK zw8x4DUNqSVb8`N4;0B9V{sgcZhXw}VNMfMitLMzASpuze67n>Bnj+|}Xwlw^6SBop zzbm%&GsV>aNmzFfu9WwuA($BeeHy2TI=B}Q8!r3#aKim7JUnGT58cgSJrauLSdl$b z;sNGgQ7pF>zIh@(H|a$DuwtaQ)q(gtpmLZ!Ugw7bL3aoYGsg9NJU3qeBufet&_qdb z(;c&tCE+_OM`rc~K+){Pq?GSo0=-EpJ5movcdW~t*D+%`Q=$oD?!`)p1F13ePo@iO z77b2Q#F*LG))QkPbcM|g;oV_3z{YYmwh}hokqr(NF|qH%-WT>Yu=~JX3wuA&Pn| zTnL5D9K=O&%n`*cb-3jYca_8a#NlpnxL-IN1q4cuvsI->$(Q2ZcDNw&Lvh&_!nKzU zw~xb(aX9j8lpgo`s$cdCisRZqaSaalbBDXl;T~|fM;vZ4`pQk{JtL;vLSfSaNa<~` z5QIq%$KF-L{lMXNI^1UDY+s>At{)*t*PFjrg2aD_NA{VO;0xF|6qppp&MU^?_eOnq zQlNAMSdzt%bd-;K>D|bT(M>Z(PiPJWnkJ5G{4ytZ#bxkK@khz;5?@+UHuiy&@xJVkvN(>UJy#Zgf}eM<;VcMaM|0(o{XqYFqmb*8)c z9zaQ@axuBnZ+!j$gyFwZrJEP3SqDzR<x;pnjTQ4LhQ8}m~sf* z6#0mJjS=KP=tkKKUkOJvxAyh13f3r2ep%M+hI3)BwD^OKvI-EN81aX~W`UH##_mhb z8)8MUhr=EU`*7Hd%_!J&V2_5q5cU|@SHngX5^W|&!u}cF$HQiqPk*dqq{~UdGl++F zafI~N0mUt~U&E%+xnq-3cRzQy+Z^r@hhqrp?k$Jg;cz=0ZkNLiK+$TrgDe!5V}FVx zQ(ozv;N0=_kK$f)IBrT-+@Bndtxa*L9|A>0$C=_Fb);A&e>JS~-Ltvols0-Ve4Usw zCCtM&nkb$haSRpXYol%L4M0PkT03{ayam;>7uM)hF{Sb+cE@14kiPOKmTbC{cOXJ< zW2u(ckvX3RR4i2734G4m1_PCDPS>$z9}{L{6yIQBt`W4lq@O%C^K zhkM%L-gCGQ9FD`Y`sMJf^eDYl9BY^2z#6o;%?_7PMKB!4nBQ3WVm)sAJa2TGv6ha-aW?<5uuU{h)VCv&8vS<)o%W3(3NzKvY@NqyiBX&JEqh)rH1J4}9 zlg=EP)X$~H5yPS_<#oh=bs_k@qbw#%f$+p+E`0kk&036ZtVgJY?F`~s- zmj}Y;NL~aRGY&Htc7NC-VI$UN2<#!S4}#6Q2}W}aqc|^zh?T-FhJ7^bVX%*bJskE) zu<4(@B^VnqE;x>W&31!DfQ;~b=Lk>MiS~4a!q~gz;pSTix^^7yT!-V*Mg9KN;r`}u zUpgGw0qX8-3x&-)4hNBfe1(1>w0Cv4%|cx2AOcZC+xUCjl&nPD58C387jh?&DUtY!PfLt8vG!CRb~;4LX?f-f%;iXN8{H#F>G2n`z;^ej)& zuc+ZIl<_A;(XVAZ+Wk|ac-Lb#uCZ!(W1yr%m#4`6@*;=Z%KT4U=# z`Lj_qL*^PlR1p#~KL@1hYkvu-T5t~mQuVc{%2s{tOMp~;?VEs9eeItBCG#AAfcz^@ zsqdT^_rpV*iWt@S>U(1NLk-s#t2j1A^^docWq%>D$(+_o^T__9f>tZ}T)zt1Z`zst;K&CaPZTN8MwRhm7uh;H{X2k;6 zW|fqvemGfr<&W`A%$(ZA^A?=Btgf0ncV==@j-`QBKQ!NS1e@i+Zk^ruX%>GZx>e>X zI4sg_m%_&4j91CZ>Czdnr{f*0+t_ztW5FT|w3A>jz&rR0vG2h?3ihY4FC^~Y;BTc= zguP~UecN&9i2lcKI}RPu{m7y6Rg|^%rG&z=7hZ97_N#83R@|iy_Y3EjJ%jpv%;BDL zxUp#SpSLA`&t=XLIBiQFB+47F*RCdvCyTukOLuwxpSeg&9J2g&1GQHD$p+x%e1^iTN3q2cBU(3y}k8 zc2@Ex<9LkU`y;Q29{`)_7zmqv4f9m18KJPS6%}`${R%ak&RvVcmCQJiGqklpB+t;+ z0E0uNWmG5gX?b&HPFeG@IUfLNuvd6r%5~|&C)Ztz*I8#koQuO~5Z$_I)(aJoK=Wcg zVs)P76X+^pYZrLd=@U4WW`ZPsA|RbKoeF5Y;LZkgl0aNp^v6gVGAjTjPlm|1n~_rZ zm%-J3cxdlSK#Z?XnTA_wPUMB)mDNzVHD=7r`E|9+%jeBJZ%NJ61xsZMmy~}Arg}J4 z3fC$8fI%|1p;UH|(5{9=F+*6~|Lj38OL5W_0!wc$HBcPQHHY96D^h|XH&7T0>Zz^< z{A%pkMdhPMvaAcmW*DX6Vw#KV`Ag%-B?^;k=%KZw|j8;KI|_N_t;UGd2Dyx zfU(x20lUD#yk6%JtdBWkp}KIAJOsYR;W-Y^@p#U`vmDR4c)XjkST$Ntvkp64+CU3F zG81w7lbJ~V9lJfIm%BM6lel8u=8(QjNZbFiOj8#$TkV91!|Lq4o)C4QGVJx#NE`F% zsJ+@y355;ovEn#&Q`~BYyWHV86;OBgIovvjd&c43cesxn?rVqpr^8)^S`(Lno%@>! zh0QKN8phu&6sA5*Qz-7nS*WcEz83l^qh%_X|ty&cefv;4FbigD#?7P;UC^p&=!rLGSxKtf@|xt!v-Sx9j$4!6PK zeA#mskki`9o`*Yxl>kCJr~M1QdVrqL({*RKc6AKg?K!ZE_)hm_Ppt`hfvro zg(t-=w-5xp4#(_KcM!&wCB_Zk2%!VXR(3&$fnrFwVjp%Qv@dYUJwID}s`kx7;81}j z1y`U0Q?q(${oFBQW=StUYj*YAS=DuQ)#uH^rjc1z80U4HE8&Op#4^uolCA1W{5Kg4 zM<>f0I+<&OeQpZ@lUId*&{Kmd9An(j`O7dq%HEdseXvBWD@OLQ#0vgoAxw zSNti2Uu)XTmDEgOc$@L~Go@1}&6F@~&TYoJOd+IIs#Y?EDIpYweA#oyu}9sd&6HZq znnEIT8#ZC7SB zYFGj23Mt6b9PTVY3#6Er0n&-%DnQCbV@**m8W}jr-N$-#_^Dju>)?tDEZRK7uf{iV zY+sFur`ur6m}*sbQX^e;{{uL>$OSmmACef#>d`dwaL#By?BAG_zZRjfXCDX~Gsp$! z*T^(5F;}d`DhC?S;AAeQRA4aI*NKb7r0_g(L1HZAeSH(ekw^`$p~>xqSz`Y5Xkl0H zI0Yw$-sMAH&8039ws)3pYm+)r+|wkHLAP_I>S&oLu0=S^C%g3K`ssF{m=~BRGB3Cp zj;UhW!TCno6J77gzVIK_}T-R8o zeV-4T?mvb7I-c6So>=Z}Wl5Q3vM%_lj(1DrTEs<7cB{HDIiK4jnMaOIrg-yR>ToC3k5p$lNnh#hdMOo)82My9RK~@8O!b8>CR@t zKfAYuu)Xe#&34g$xI0U&C}}z~U$yzRIx}5&|HyS`gmf30;x0qV6?eadBIaR-d)eXG z;ak6GQ`bv3b(w|2=4C)ij~$!3n~Bb8fVgAFMks84<#6jAZimCY=WzdOch;|i-PtQh z&Ho3xvlo%MOWNtq?jON)(d=o4me5022IY~9suxeji72e3$Bd!UG`VCx7F!!2DjaHd4$5yt>EE) zVj;|~9B#A2z3*^jAzHs^cTY)IMs^{gFwgbcFm_rfY`7(Gpt$3iQ$k_GPEBziI9wKD zq`0t!+F~p2c|rRB^BEjRmb!MjJl;X7rsG{+g4e3O-ds@#(z?@ocg6pHr&sJ>rv7(l zbqu;gogVXPZ#%vJ#;lGFxZywD<#nL)r0Mj0Rq5O6^mL~8k?Zydh0WE-1I3XIpty|= zx5eQ&JgB>!4tF)$-W$@LU1uTf_N+VLlpediBG>H^3L7p`6~{%Y;&Kop#YHW&_uXE@ z*ObI89~ygX-9SWi*?^4=1aNY9U7IUYk9U{L+2O=JEq2$vi`%-kFh9PXwQea0C)TwJ zH3Fxr-YebLn*iym_bx!X>U|Q>G03}+c^Z(edVd2bdDUBj9J(u|&jf=_u{g2KhLGN3g361*bw=5_VT-LdS5lcUHG( zei7Evenz05i#U#cz(t%&F5>ZREV{jI*w-My)`r|ePsQ+_Zl$J(`CtUes50obyXRrL zt8XpBW5%}KJ(ID>oKP;JWEk0q?4Rf3@eJz?SKVYopJtI~XDAb~4)##s>R}Iqy$tr@ zuyOf7Y%1(?Vb8Je7ua{MJNccfd44BTF#|oy6MNlX|8G{@G(CM%#rs#-kJ^uaidL=+ zNJ3$9DvaW|c2(Rr4u^(gaa8B3?yy(h;-D(VP@P8vJ0cWAWlA8_VObmd9VPZ%^Y+rI8gw zHy+a*9bXoF$zl;&S$q>umzMD44bGWf2o-%eVp@8}(-rY8JU)cWBVVFIPiS~(5nrtw z3U=$|NXuMgTF8(QIY%J2EQPqP$PyfjjpC*d{*d)}n8B%&+yII%58r4%urB~HF_E^- zu3oxej+IG@uk@Lg1&f!~)ai+z8@jq~H(6}H9}b=9 zo*UgT^q#rfWSiIUunR6i+yZ9S^m+5dSwbdb0&#P+`5jKZ(%D3H=GPpr3F#)@c#K-* zt)JkgpMd!j9_nSV)Me|LIOIX3p5pUkaPy<)4LpqQalotTiGE%^Vkg%0g>z?#j6~Jb z=BM@)R!2LIP$joxflnlrGGw z#&4a(irbye7Rr^7y#&!*f)EoWHX%KZa-(+bp3zR(7$7oZZ+qhi1*#kt{JQ>Tp>xOh zb1Ym2vv?$ENtQ$qC##k%)Yx%QoGAh7byw8uwp8AENn|2mZb<@}P}=iB=ksGBVsj4z zVJ@H`efKOf5KcKLF=8D3XN#=gF0nQI;y*)m9;sGDgBM40!fn%~B$6EweS3LPi-C+% znPT~-KRFJjFugB!VKFb5LrfaOVoY}6VIC)|ju>7n0<;o%VCD7=ePuwgYE2JF#pTdf z2^1?SP^_ffk3~+5b)^+>rOC;kfx-Jf+4iveV%EZ8W5$eISiNZW-0E5LhF6aqSv`AX zb@Ab&ibsteJ#YA7hZhf@JA3r-(W6Js8*#*VWEuBW$i|9ousy^6VKZJJTNi!?@jvZs zVr(rpz-G~*sSl5 zz-G036!rzMAB24|>?dHaf&Ch1^&;Xt;-QTKy}ajnBqyQ|`OrM>#4b~(jWAa^dn zm=Q75_)19ida1h-ysNv!;a8kBl8cx+m92WVJ`Cm9k0WwscV1c3*u;U;r{Ph?qn`Mf zs+PPM-#Gc>d5wCsIW<0}%c2@8ZJz}>^ti;NKg|V9yn+n!Gwk59XHJI>OB#XL)pr)^ zskbh5Mg+#^?=Q}mq--0_lXvbAMPr8PCtXUR!1|NuQoQ}hOcDdPJ%o3QHUoe>9R!ca z_XrFCE+Jj_up~?(YY;5{-EO%lM(gv>U415`D$W(x4A+X|3`lW5b-0Hd?lFhsCP#Jm ztiyFhpo(LODZPUnuGrzq8qXV@Th?4!$VpXVoA?koNIf;23*t1~lRUb+fcWth^W<}> zdkANJ#*A4$AA=@G`Mf?!CCEmjhNpxRqtak>*BF%|7&{ZlGl&dDGohrW6KQ>CU=pn| z(86{%m`o{Qsvu?D=*Umoj(DmWlcNitwq^YsReEAnVU1_B7z>i%h~jNkXR2(~NMH2K ztJIyhzqUm`*%dt@Jt?ZV`S7KxZ52r z&b{BsWD1cQ{*02nTG`az2a2JpD zp%8t1tv;ZrGmLP;!?Glt3C@q))MI_kcj2IJ1LqG1QzB<@r;qia5W~q*AMJ$mUFS<7 z`a&yfCmiYr*BnrYKDzEPoQ2MpLiAOjzCr;LT7g%XLiyF7#m;GIqkYh{JX7y{D@5PL>brN?^set@ zdV@l5Q0NT`y@&POL7$_16wYxJ6e5L@N}+Gm^sSGWzH`H-@61l7?}!}JcUbRT1v`4S zkjeo*D(5;X3XuwRa3aP+xTQA|B7Aqd!gQTPGe}M8wi%cVEVS{mQaxHj}+)~z`|3t!&lmTa@kT2W*3M;3}lzk(M~eQ zgpb$x6?qe$`M&d|5Pf~FzIx=C9`&6~kGWCP0~f3GsLS6$UlshZ<_FHVLiGKO`0k&X zVKOmx(s(}jRo$_hRfyTAKIm!%9?ztsodLF1(Db)XJi3U4rIs9m(k0EeJ)+KKvY#BG z+Y5?BvvKo=XXuj@wRjol?&6N$y|4*i;c`JC`spGr2lF!x$FqF|h1@Z{1!`Tq$CyGb z-s82Fc?l(jAG$ykVj%ko9jOp$d|c^#C`2Cv#YeA#4AbeeL`|;47k*77^iXjJl*wh( zt+~okRET~K6qkcNCv-hbP)z9I0)@2yk+C_YchSBg>uobFv?Xaq?@#)VU9bu<*wI3{ zz2X0A=Sv~_8ZW-~T+YXcJ9tPc=bt!=3X$R@aha6-se)qiD+Nkl&U=o;cU&aM&hrc} zF9;g^7=;*#8LcC6nv2A&HX>1PVi|jm#C#Wt8@w36{;7+ELX5=h){!{NMPhNAkyxD( zh@f|!ki8?bCDFSc;tT8s7nni}>};Xee_)Ooh*f9Lmm%K3WIc1Hb~v7I_Q>joqpLz3 zwbVCVUE-_V>B3pA;lL%0N0+&uh>Jq(9+WO=uG$0Li!5EF1@SkCzd`)XUd5kb#P<*m zFABi&hfB)|Oab=rt0liTx|~&rIol*YaLk8`_$8iWeo4%buM#)>=AUohLUlu;%BEjzXk!op_W%r5+%R=YwC>9ZNtV4l3${uKX!Z zNBc&l4VN??T|~lCOAbNllIB@-ZcRG6w+Y=|MNm^dcVE+WL~qj-_d+F>N)RZ(H|wbO zyR4%Rh#wMNlEGg!x40Zph%x%5xE$;`VeURGD0V!L351(sVPubi>96y?ZBk%DyF{jQ zB&879a|(f}XD4yt>&;CWFNUto$;46G+&!)K*1O32XWzHF$ScGUpKKlZXI$hr3zWg) z+>6!TZ7vvv7|e4*Y0snGYvPXKai4`}e&Hx8M2g$RMwcAB2K(}k`O{rp8-R?!Kw1e#6_n)zVc z%oCiwV!E*AE=NZp()ovYY;RQmrSqi_eFc!a=;YeqRQYr6Zs%Je`p#D0;bb1u*! z_c&h)(O2iRzWm+cz0Q|H^wq81m@Z>r*4*cOD@5PD(uOHD&HB3E`BI3!`la>dkLd%> zmqPTlzxcAlfGakBNz{+S#0`T!m_OD$=%^_~KSRake9sB%271K#AI^?IdGF z(n@Ex=NI-vE(C=b!Wbdqp9=d^_^|V#5Pg)0kN){tCci#xqI1Eqn@N0PP-9zE_iT#_ zv6EJxr2hmS&!h`uiiTmGcrij`EH#Fw{@B|oUD8~K$1~~ZR%mKjXXi%Ty3U)P&?oN% z(`lkY4C#1{4OeC<6AgY!~pSg}M9eTN!>_$Uiu4rD6<|A}&O}hAgSLgnQ|ug^SqRzFE%`E@BEXV)51y`;m*-)dK0P$MU(V7Q>U_<_Z~%dFxkD z1f&Xa&ZFH8Tew0|Y&!S^jH`!&S+SfYrq{@b*?+{fq5T7ELT#n!{36xTkx0>6m!bj; zX`Xq~rAQ&B=-SpP`ngNdtpa7qJgz!pJn2Y+m`i_kY0-Fh0nVmi46ZWC_^NB@!i>wa z3eBDudG|;#r0!qj{mR8wA;$I>;xegX+%G6rjE4kjz1*!gt25ePQ2fe8z(1P(+C@Mi zMu3XIgQg0Q%rw?%kTXsD^tU+r6X?^L7Drzp(%&F1=X*|A^M4~KCUBdE#+;Vwq}iRZ zFeATTj_Eg|o9TD|zPozu*k?)4svfSwvu5d-$+6=N7Za)`^UOLI6NMO)m&D~@&k1Al zmW#>n1uA5}WJKIWUO0TT-`cUV#XAY7l_=kDFQJy#|pF` zpy>h)05n6O0|1>U&_RH{BhX=hP7{cwe1Je)NDURJ1keK#?i4_pwZ{UwNpQzG+<=+p zn~Y;Z$7CIob9uC)%jezu_Uu_OviFESgA4xI_u_(r!XX|bNs3?)JbFe0LTENfX7js} zlllAPn0+uP?t{T=pJCm0g)~h>YZu z1u6z~sz8SW8YEEn65N-WlIH_VuYQ@P^9XEQ4fHn3ScV6f^?35|Xm7~e`yZEQJMre3 z4MH0~Mj@u;i`IF@MTt%ng92%9SR#@OUE8)WH%g?MkcL96vKBYryqGa0G$gCn0iD3f z9%y=u7+`t?`WOsPOCnWpXU&VSS*tbT%&@40$j^`a3VWlAxIzpxOI!}7QyLa_uAo@h zT?L9tH(n_bUn9TUuBF>;K1^l%NnvJcqPR~{p+X0BzZ}Xhu|;9bitOmL&B~uD6WrgMKp;8U`$~L)mTS9c(`rOgoRp6uV9AOo*t+@U6X3h3V2MeJwt>H(B>ijShK~&Mj<#dMdEU>=Y)lDu%H;5 zVu4zZPV;exR4*)0de>iz{RuxYy#qfs5$QT0GeaQE^H~xY>0U{q);#B;pb!Eu!zGl| z6>N*=1@>0wOCkC?LVdNdg1yui=5L&Dh3NYz^?g>3ISb6h&NH*nEYUP~M5^%7{Dwc) zJnwufMBkIex3bpIhG0A&{HpHQO)12pQ6F>_^TjM3?PHZTT+(=S5eZ8zIRvFkn!I4d zGwJ9aCv*cB=9mj1p;`_J)me~GWz}h=j(c8Vzu;1=5JNmkW5wKl88dCX!!&n0rp(fDy|A2Lu)e z3U>9}(S2LjmOR^L7>(~nFoMI@p0o(i1>zro8B223yy!wwh@X~;%fX%##_M81u@N^2 zg!5%Efozds-xw0Bx|di1m1W;6ed?0gbhqTk{QV6(Aj6*zWTe2(Kl7nLtkPc##L@B} z0`+weBd-e_PM2Piuf>201>(r9P|xq1TY?$agw76S{V_9qVst>48?*8%b9!ZT-JW53 z4UJ$oU2p8B>t%YO!|S>$Z%3Dw;=&A;=0`o+$)JW~I0sEZ_0N zJZlyd^K6YktvkNE&4Jl_n3w-VyppU;Q3$}i;$ol>9GNS{Wfea&^y@Xune8(AUv+d8 zBApw=V_S@Vb;s7C5Q|QI3;;9^k7v@+zC~$UC-gysNLXqNKM{h`CC$ZnJd=*@okBN2 zzDhk4&t0Sm^O{SgLJZ};RzCdv#@C$>h3MlE@v-Nn+|%NYq5GF|Z#s$!k>XS0axk6J zFyb2p#X9q>K&|V{o|kejiceDH{LwSNbrDbqj?7kZSw$xd{1pxIc+)GTW1|BWxh|qu z^c83(D|YJg7LGQ zceqF>gdof}5>6GJG6I?6G2_W3i6WP4o_WX7P>3{g#FI8@e1`FS@T@#p(MgjgrIau^Jb5zbD8X?yU^WpP8Nzg67z3xd>6!Y_*IDM>@69R&j*UuTII)H4x}2VMu*<11gE9t$h8X4d;q(Z0N43Qr`ysp~ z4{YOIT${BT!UZnhc5zjR!HsSm*HRbPNdjpjSj%XZfEsqK-GS|G87JhJX&q<^Q(aUR zF%H(e@1mj*qjI#ktfC8MS)~Skm+|-e2l1;le{wVwB8?g1DS%Z|56ByO%!Ca&NRMIp zJLqXRf2{ey`BsR&zazf=W25JTU)3EOl0s}q>VvNC!{eEBv}Y-8>%^mrNLXsgAt+ta z+~g5;E|dM#Xo}mIbw2L%{h>>-LJaY&4(HcL&bLDJeRjL~rS6zt3NgRb2UCAP9?zts zy}Zr*N`#*XLFtm_W{)WBbaXG$6qklgX??aChxvUTYDykzO5U*O4tjo_Kh}KgQmqhE z-6$0D!E@*ehE`WFw7L#U=5!=?96u2EB>1SMN^7U1tPm+TiOa#BE4G3k3W{CWRRU?p zA*Uo|uC2^Fde)93tIXV+QDFiFVN)1tf(p%O-gb+laB7q zLf39|+LgH@=(dpx*Ux(Wi%YFS4DAk$Q9tmPG2QQm6t}g}N&RprP>5Zw`eqn6v$U*9 z7tXy&DfeQ5C84L}Kw1(uY+8_o*Dqpz5W zf#Da{aKB;Df01DLWw=Dz|DCW4kZQqOg~Hn9nf5~Yy9?#uHbZgc+bR?<1lsL|@(&lv z0TPPd1yERDTU)rW7FW}>XP$61pbUPs{_!Yha!#gF*yMao+Y4VWIbSpP!q+Fx*QtBq z>-WyrEaz)KfetVS98_3ecOEY7K^7I-+iPkH1+N#}08Y7LrjYjr6fUwi4He>&Sh#7= zu#TOK@U%G;AvU@^Y0nS8(cchp&1O+75SztFfmrX_ZXj|$lK)1elH^pBc*oxN*kURX zj^8j=2S^OqV!k8k@_#4H7E`_$7cMNATUvMKvPCtE>pLD`NeVRvc(4nQ>ICqgVi@3L z??CXs7u0YU)ReSA`9o&ZjulrdmvQ2=b>tF0=w8c_C937vc1M@+r*+{t7t+KIg;XxC zIua7IZ(41AIj_ZFVb#q2_wsOx%fsU(&J)r1)C@kbaKX~T#s81J_YR9<*}8{k9CN^& zJ&KBoA{i4Zidg{_6-7h^1Q7*6f`SPI5woa>Ib+7eG3T6fz?^f=V)j>iSLiMpJ)V1? z@44R}Z$0){vwE$)s&-db_w+P9!QsaE^BdI1ILa^FLKi`gZ@Q*tX6jCB>R(7)dV~xm zan&=Fy>Z*%{`}YMjRX3JL=YRTn@^N6{E~xluuosVUc~qpzay+B8Taz;UoG6&$B#@8 z0sRBQ1IVZz?B}a#n?);x=%L5zA0|zzhD}c=Y}lFoF=_De08RvyVWggZLD5%QO8_iE z8k8R<8Z(CaKjkn%UDY0Hp1Ka+^dJVU4HK<}(+#Dys*~Jas)@^n>;Yb~>d;JSV^F zk#Z73TL#g2uYRW+ht4n+Pt3BVuxpD4oBV#S=FJ3aNY>;m1HxJ;qeYjKG`!z6csjD7 z!Lu|vhzkvd`2v2O_xJ7P=>ZkAcW##Pw5UOJ!->_y$k(d8in&&o=N)UBiDjrue6r0;r}1Nwf}x%QqCS|JN~r& z^aKame@wI=&a9R8D>XXWPfBZfyEFfPM)ZUB=-*FFv}G{PXv_YzNAw&3dXz4DbY5z6 z<{n*<)@JSre}DbI?vZkKLRt%QB(-<)r&TL5G8ah6e^ zY0%&8Nwl@F-Dqpo9<-I(SMa9i_Rz~WqL=WwOX+3iIqDI zz^KOm_Q(OTGH1mBltej^L5Dzv}^y zMs7I~xn4;GbW1J68pK(SHHH1_+8hyQt%#E<;;jD1IMDuJ!lK)N{6zw(0rpP?IOfQP zZ9zY~!i+$-3hb-es~x|~p)$%tur(yW|CRrrWZ;k(V<&Jt!PX^T8jw*7W3@Ndj7iNO zYo?^u4{KJW7KpXFq(wJ5|!liFacC6d|@tj!>`VOU#0YD2NMoYbPRwvN<>V{Hqm#b9j@sg1ze5mJlA z+8I)d!`fw18;P~sq!y30$D}q2Yp+Qy0c)Q~Z8X+Ml5}IRmYdYJVXY9UZO2+EQX7jk zV^SN3HB(X>k2QG8B7Etu*VQGpiCAk)YLl=Ak1yPWwf3a81#9l4wi#<)q_!1neMl`4 zYayhz8*7oIwg+o5q_!7pq{;tSE{c(mmrMY3)(S^;DWZ+|<2e6l^nZl^Pcv{?Y{!?l z%?c5>f4@gxMr~uFRrcshh_xr!6|A|F+W+m*|C>E}G}*VW;#No`wQE?LL2B2rMmEep zmPcZoA{>!6PBi7- zgU3YYBug%`ZK5QuU-n1_rF`q zJNWa@rex_zmR@8DBTF1v7L#Q^S?-Yq<{I)3?dJ;rWg6K)(^`zl?@)=K0WK$4Q;1!J zEKs1I+!y)|{e?V`V+ytlJ}yEVp-u2*h7nnaEj~Yy{P)`eJoN&4^#XC#3*!PxpwFa0Z*p=itgv`2~P3_Y5PHQ0b~c}m?60+9k6u#rg?o3N7~xfg+){xt5{ z_V<_4U|-?|vYDKv4`|J`HVZ$PbfNri^RGfS^m>iZfd-J@>9z^oPDuw^ zD3C33A-QRANYuaox^+*MA@^(0f78G}9oI+E1yXtfYmid7sF(G)b`BndKiSkIAiPUx zz(0-+IOOpH+wXLifjQ$(|38OOV8qkW0%L@Z7Vw~>1v*4W3v`H%7TCthXyN1bcS)tm z0Ub>aBo*9#SD+19B^9oZk*BNuPRiCnglou#UfjeQ^a8HTWW8DVXUgC2sp^)4$DJ(W zkrn?@xsTCctI+KOZgl&A7u`P4AG&>@KXm&*cIozkJMES2!^h6=whzq`M4(yv)9sU0 zcHw%40p|eX2-QdHOuc|=U8DKTxx zI;&sAl$`KA!>c5Uw+5E^E0uetM8wn3kQ!Ut-K&u`nF z$w!@J$OrscJk2rGl$b7LozpMcp2dj|o|M~X{+cn1KI9=IkNQDP@q-U_^@!gVna=d&9}oJ#^xt+4Sa%w1If>5sa)u|tSEe-ruZ}?ZD{i6eGoq6 z1B+w>eK8RpP*Xg9w_URSe&60+b0Xyx61OI4V-3>Y-EpkBs`->3 z9o5Z*e3B>9vF!piZLF-?_^Vj;L@cP$Sfg~si!c9qaq{3%H=Jg5XyR7;@a>H-?>Dvg zBsUy{hI#q~_;@z+3+opi9OCI85Z))khy1!~MDO07VST)P+jq3<8R|C(&a&`*NSK|c zUnDu@>hB#G=GiMWDul>FJR@t{dA5rPC-<{>cJK@IBR5&lb%6ms79qYqx_58iJeren z{?^O%9Ayf0jIT0a)QJ9e`R4rmd+?08u?{`fUilt#*{weMIK zKGCRt={aX#c)x65qI=lX=Y*m4(3z(7znJdRrP!V`8`Posk1=5b*1gqbLw<`!rZ*J8!Oz- z6*G2w;K#Y&Lv`QdA_`S&|2AW9#lWTo?SCXUb#J`2w#mrH8Q12tDd>=D-ebbpxgXsN z&-E~Div8PSefCmc9Il&o>D$b-*)YEk+ak8?s$F_qpv8}mU54(>mbheS%blz1&q#L7 zwQgGbhnMEvt7mO%R{2%edE@4%dY_rsYjn!3no;p@d{+(H_c1)tso%FsQ^G%PZ}Da0 zwOiqzdR$H^=XqzvIwqst9-I$)Xj-OPq%K0oE4a~u5n8G>krw^&zpL)SN(N!%4Ta{Zq3;DsSzD> z^{H^R{m#Vo*~_(TlyB?ZzUzP1T~fc@j4?xx+P=RXKhn9YXJ{!a%h#O_G7(<)R4CQx1O5v#H#kKv29vz(=W6So_}g>WR-f;Et|c_e<084 zs>9}ty!z_I_0HAf*4ZBI5z;R*&s-z>;0*T{ZG5*hE^hNQ^sRgOiyfYgT5aqbyW+gR zNzwXtskxhceHLN0`$ABX9UpJ=mIZiq>DW*=q=Cbz2RoLpT|e3B;n{K$ydwqf9Cv^EcnZ_pPb#IsbL`tRM;pcBAjVzcqXP-RY?zc{uylljIXL7Il z(6IA{a&uC06hAim$_9?_G!1?+LtOC0^?_QeD(#s)d z^43G`HZ5FcIgaC;KYrW0`p)sE4|069pWT_89qzR0_@GDkJ!@M&=KEjsp?u{Y*{2{eI}(eY;|s`lY&L6uPpAkDr9~ z*ZhiyY;t$s+WdIA3LRJR_fzhUTGY0=t4rEOhkZP(;FerKJ{lBl2?1s>gcJGk(?ye)e6 zD(Z5fO6hx!^M`EdRD6-|y4wQ^_V<4`=+V=~Jv+BNHa^LyX~d95vwybm*qeRIj8erL zeE+O(Sg7~p5~+2+Zn#?gu5YyGv{A7+KkhPJQfZR&o)@jcig?u?Q^I)J&Mh13cX66E z=xm*}DY@2XT-tiCcC<}Yq1=0cFol^41e1*+)(e$+d`GR^k+xSMUe%R?s;b1gcdt$^{ia>pqFvKvaLo~O-u51X<}LFRo;U(OXdYtD{#W) zXTx^i-<4_i=;KvyKki$-?a~=12KPF~+I&m&tV$tG(kJ!4-)U-e_aT;R*3Oz4y7Nkl=zdE)hnQPuw7N9i z!-4a+mi+8pMg); z4~fcux<=JA(JLbUj@F&+x9vlQQQ5O*F}F4x?(Hx#W=8z-*jgp-jhK3{V$9IcJJ;v7 z>vqo9?{nWs$1)j~&A%3~A3Gt%+r4qiPgTuy*FH`Rs2{`sH=Xg-cGcP5!*8DGyJne0 zM~s$dZ(O28fiLs!mMw89_T3x@?-sWU@_BM!^t65%OKcw}w^>L zyVj)*>rVaXzO8cmogM7kmp}S`+p4$%0}rnLIcDOYTaq<@=~Tw z9=Qg5-u!6B)pub&Eh-(_pL=KLkAV)m%C3HM@=^7<=3>6uvf-WcwRL#{2bR1u)Np0? z%~kjN?6)oUdMrP#&06GBq4$AOEobQlXLKFaI$`I?W1fpH?Va%45UDqJbvU@`Ywgr$ z343dFS{Y3zwE2aj$VdN1ksU|H7`ZUaqa* z?&0IV%8TmVihQhS$=`3?YLm;oz&F=bgNA;x^2}qf3~A`LHPwn2_holFF z7!_@0RiyKJt1lJ!`w36Vjmy_vS8-g=@D~d&`P3LQEVbq5Nasb|XOhdbb5CmBtF~#y z(MA_vo|wyVuU@{Br#QE>OzJ#%ebWNP3v-*FVp3*r@6d^O^s4{guGY3(h!wI9IE~f=7!= zjXGvN+W)obyLlgS&u&$^+Qqxcncr_O`tZ<-xIHzmY(MX`BX&%$$o$(=%TD-k#rSSq zqc3xE#9j{c*svf^4!^D8r{ZpWFI-zg*YqjJ!N5y?mKdBgbs@>-;68 zdBOctj((VVdD-1T<5xHYClqT?!M5>OPwUdTd)p)hnRET*S)0?GMsB%Q$@p&RyPdk- zs4?GnA;{Nj>o`=@i>>{#{D%x;J^Y_c!+7>>-^Oji` zzh%I{n=A4x;qmwUaKH9u`||Y6y#H1F&hOG&-0?r1R>U{1{bJ9r*Ll0_94G$Fc7ENt z?SU^M;!In0;q9;H`Z?Jq$gVc${ZoE=7CBebDk-$>`xV0m96GbG7}srI-EYq3HYX-_ zZcs2=j+bqp^X;+eWuZKMT(4E1wlIH?c|?gy>A9SzwAo*w-p0dTg|cGV7-<3`%7J-%6?56-+IjFO@#(tJ-fZr>M19-x63gh-e^WLXd-D$@&-qtRf`F)MYlL|Z6yVm-80qZe8hL=g=aatcYw!ZOs z;`Vzv+Rk(z*YG26KaZ1nocw8fIB(y#q%Xrq&o<(IJYO%<|7!4XM&w=2tMFj>#DPx9 zT{82Yd@(OmeL&-KMK-iw;Cc9U;QYKbD@4ETTWZ*VDh@f!0!nuYPW(D3=Cjkru5n&u zcTZg46zN+vZ{P3F>ek=mwPb*H++(=3OTrjoh!EbSP6Rxe;)9!4!hdX!O zc(s4z%b6KnVuL%SJ>1*><*RSA*N--BvOjHe%UgrXUE0U{@hEMT%eYIP1&l9Et+Ft` zVTqbou66 z@8;w0dA|5O$9?$v66;6i2prMw7Jr|apWNKM{;+;8>+|*JJJ}iStCaUJf6w_xJ1(qy z#JSntMf2WD-L$|K7su*6gm1Svw+x!a_t##h&s@kmX0bn?pZWILIVyXGk4?%7zJ2)ov+}s*Fo(~3o(x!e(Pa0A zDLc$AHO&^}+PpRArLA86@}9EAprN8Q(AXcH!gVlX0O>L(e{)#MkrVMCR=>r*q-@={{kz9KYD* z?q4+L_CtA^o99SqTZOkP&#FC9xk_ERHT&}31?yr8M$9<(WKfjr+O%PNE56)muxt2j z==TXvw;y~}^2dRDu8Biha9yJn!wu&O#VoCAH~s2?9A42c=N`7%QMrllxsnY_WiL5U z%;P;;wYy;%(r?t`=GXFXDjMfkZ|8_%-Z>mUg+E?hcGbc|g?PNr9U2~bZN4z$_}288 z+4ed1&EK=(3vg_`G(0bZD_Yp+84G?A5J))q&~36OP>byYBYsHTd}6J??ePwEUK-eE-Qd z-}_79gQX*eRJpm~?Bb?n7w)!v{2?`Cnr)@}0T=U3UbD6Te#b6f9~Ln>n-Oh)<5-@9 zbI+8kF=+MUrVEYjPFbJMb=r8}=fGvA7m7y2x9@wlRmtP;_mA0GyV{2F^Pgm2);m{V zmByFLxSw91!TpciN^WT3e>XSx_Z#F@#x&I>te!*R28Cw)thVTpkO3yV2dRvW!RM}w<@0ODz`Cz4-gwpRv8luI5es@6EEm7bQ}XTg4*WfzZ~pE04*i}MJ78_C zfqZ;>U2n2>=!1<YZ+ws9 z?TcOE=IPn9u2rYlD-jVP*=pL_Pb;=$#>s_dg{N)Gryo;^^BjAAUA=S1jh~K{eym$o zugG-n8}rPqMb1KDD|tUU=~w1`d_3NQZ=azr7fvpJ^w_+~iz+X$Pwn}re2#plaz1sx z`?0?D_NN{Tci12CwA#42k74ABTCZkYD_`JDx6a4jT~2w-$LD~rrx$g+(`Cx9^v93n z%~5mYtUO#_%B{u$i})EwCMRB)8vaq&!#Q`STuDE?iw|D-;%eW@Dc_5Pg}BYT+GR8E zSHJ1cEz5^Jcvr%EdeZA>+b``hy5agGJ!E{rTSeDjo-(QPx%KA{p8jN0A=_@R!{=5w z>suH6RJzogi5G1Oe2>^=SITZ$?Q-eo+7vCoj~^ASZoKv>yZub~#Izgh_jc>fj}L!E z4|}+@&+?=dZSwEzR4Jrg*O(IRD<9I2Sd*ieXK;jZvBM)9`WAJVnZM8Du4aQuO+Db* zA-3AYo1ym_+%C|e>g0_pTd%)3$iL>Nqm8Q@f17pneMPrN?m_QzWe=a5IPvtRw9Yrn z2hLvIX<@6E{5}8Q;1ygy`bn!X_BXy3D|hMWfn(Y7m2nwadumJnjL@+So1eTf%+YLU z{*`OGtqb0re~f9N`^WBGOl`f<yEXdapJB!kNZ#mj~!S#G<(iZ4$&9|?6*?wN~V2=XVD<3b(+jA$|^rqqG-i&WpeZ|Q;Ka-oM_N~8g zSKGrU`nLX7wseVkr5yI2Zdz+y_A<9!W^Efb&+HO^&-J`NncsU%XkN;>cwiyU&vnkD zw_|=QPv>rNCb7qdeoY*lQ1$Yn5|em8Ive-8cyfhFW=yl}JS(X`=P z&g&}mIQi;tZ=)l8eM02{E)#1taOCYhoBVM8!|bb!IWO{3qKn13A<3EJaG!5o-iCi_ zJ~4adcH|s!+5Gg+!4ocQDzve|j=2^=n|fZHf4=j_m?n9mr)Cg$LGSyX zEq4Fp>tFHs_U+wg@aj)KI|sFMEmLA%T4gRjV!*62M{iQn$=$M@Rx!;MX%MmmBWgBd2xu}Bu zaL)oARu;SV<$U~!Zxw?*J?s?EGWqViWahK&U9hOF?RoOcw_cxwDPt&p2hcunN@}IWDKW*Ws~+QLHX283)ndo?Wm$p*Xa)fas{dps&&f>V0(0FY?Y1@h-mr7=_dl<7_ssS^Lw~kwj$prLx};0~IVU|5 zKMm0s{v^&Kz&ChA4m~{U(x7YH+s`}P!pbU9ua9BKz~DfOAYc5$28vkthLXRh8|Vl3 zKfrx(2K_0`&4w1fem)WYCh%7xs5I!?cOVb=gtwwtg!+1id(*dYx1j<4<|B&&cd|i2 zj?N;S+?!w$)E^L7W6;BopusKOMh`8v(wf>G?w>R0?-McH69^?c-dm@R19xZ|^ugp6 zTHxDf)p%_jxcAPW-$0DWEjn0oYU05Ccn19z@(S(w5!!l@HV(P@g>XudrdJ|0D7jT} zA`t-x1N@Z>wkKm$zZf-#_MP1PK{)W2*>K0;;Dcu5#uRW>_Z=b_^asc-DEztI6g=z zGyZB0^@2a%G3YOoS7_(DKG@CPKuQpBzm;)_=75g{xFL(;_RRm+Bl_< zGhWr6lA1X1M^gqp+_4AS;;+9P_GsgjK~5>sT|VYZYvRBkcNz3BieSu-I_lF-8wav$ z(3=nfjBF@nHF4m#1PyxF`Vi-5#MeM=9Qbh_InH02IB+AZLC>Fv{K?(%k~WSpa&D7O z(Xk7Eo~Ddvy4@=x2liGdD?Uxwqm5IEtTE^xlUIIkc12B`%E;ky?C$!Jn_n}J9~0zU zSH-EUiBknR{CU=Ix?By?#;J-N7|*7p2BnH7PBnrW^y5g9VRra3tWslb98i-y6GCTF zgHlZsr#e9m`gJ4@?DG@yhxgLPsezmgB#sxUL8-2ZV@6Oi*O4}pf4Tw<+78ghsfnEX zWOtoMYEaBHao|2R1N>DVjvvn>S5Ii;z^%*j_%YYSu|!S^i!(iNXofb96>`dv%?L9Z z6iZDUYl0f|e7ldeo*tr&1IICg-k9W&j~{DI9Jp7~poc&E10+QB0k2cIdorcfN?64 zSJ?B0O;0pV z8xvGHe!;O)%W;%AsV{S$S9554nji;$juiI67yb57nQIxWXV;w(xTwM@%tD{+huE|u%@I!pjpmu#dvN^UCD!`r0_%kyDj%g6^)# zB8NSY!{fktuR0DLKRuBHui44sP&|}OS}^OW&*#0!d-7R^G=?9)dTPdxH*&a__oQJn z)Ew&NgPdOE6&&unA0-D*=%LyR)*AFf34zbyJ{m7y*SS8zgYZKUNnwB!43KV@(O2skDEG>gH`7I^g#~5JU{-bICKt&2+IBi`B8JI zS6}2bfmgCL{OG(viA>T`*{8m~a)sPm)dP%m;iNZR8AuVg7$HjW$^GjEIj$azd) zhy^7``p)q7>KHa}s=DW=*M zp&GAnjhC83y&{nF`|UmuIdxTD5gM;S8ZR}6dO-#Z`VbNaKK0#bREeBUkvGzQ5rv%P zWI)6003}l6HJG5v7=zF6TFwxOv#eTpoR%|G;y5pDvQ^6&CUK(7msD1BXupOd2U-sM z&i$t!$fT9IU(v{^smkGSO}}E0qaM#{4)q#=oH=9?t4?a}$rZn7y<(A*T1xrVt`Qoq zILQmnwX_^^h*jnJ)ZxG+Ehk>$^lee_h?X--;#6tju|~@wr@1PxqX&Mp(Q-yhoS^1& zOK3S`Bo3S(syQ@=W0BJUUddvyWE;s;=Iu2OIaXv}&P!@g#;S5iSjefp4)Wn&B z9Qc$0Wyq#w8?DKX-4rfA|MA*Ut;A;rFYYcl9E=Xn}gL$CYsI7yl~Wcni< z_=E*z&}j?O(adqClQnXjWKEnI$gv}@B#pYS+pmAu#+iv6Q&qoaXyVL5PHh$^$Ji(2 zWH57kW+TUwz=cQ+$}CNsIRrK6;Rpro>0AHXI&GY}$Z0?ZDvvWq6K5WBczc>`Zu?Lh zXFhV4tJ*V96K4T(YLQoH&(*Myr`k9Rk&~*5vp^GP5pv+j0&zAzf9#`;vluz>v`*fy zMVdG%$boYlrp zFPmxmwHi65q&>MAFI5v~4RVUH^|{9czShQBtBJEl6Ne06(jL-eEEY}7$V37?RG;^* zC-2EQHhJaq*g8#|G~}3*SJ+;6U$!2qjq^8h;BkArUul{+WZEKLaAe5^wP=^B+Bh4L z<4c-Zgw&vHP{n~W7V-pEvKYj*l!oWu)KPQjv0yWDem^$0Am=)HvWFHF388L7W}PxlCSpob8%8JCOrFD-C&`^q~^jESb0IF65NTr(8?fsfn{2 zIm5^+x%8epD0ZIC6g9uM@~o_v^SO&dEQB za|$_U$Scp!Nll#7e-H;E81xrZaZYREoJG#>_pfuvQSTRLHF3@(rzm-a>~7C-u(CGK z&=NY=@qV4x#JTtfang}cnmAVo zYS8~a&Q;`$C$But6-}IL$gyLb!v!{HagGEd(4c=#UU|Q+Y2w`YgE-{0fW#pOEfMF2 zCeAG>&Jg2y#4_`KaT_`6?S4xW=Z+NTNycOsZJfKv`9@xOzwT(_+>_$i=2*E<8|OZ9 zV6W$K?rGvYkm6+Bo`=YRy_Ls#pov3<3&|nhURlR^j2!j6@kkTr336bbhjBPEyeGME zk~z=hw32wK=dmZ6IM0w{MqWYPqiu=4+Bh(Bd9RA|Mib{9a+<&^S+2I}NKO+o=NTf<;~;O(J58Jq ze-P&*a^R7}JkAGAoQyw+1DP@C)%!(;CeCN%v?8xi&P7=mYy0(utReSZkoJ@V5-FcG zalR7Npsz??AuB0W@{kEBbAF&D^7qtVHF3WGL7X4RQO{%FHF16-CxW~}4l5S3^U$^j zb{T`d8EGaz7yYS;12^%|?*}1{)3mxvv~lResMT@w_^CyGPYxLuBo03gcJnkPlW6Ar zz!@ezp7QNZKmDlVz{9SUINKs3$i_XpCGUK!HkqVsyLB|zyrFKYm6Op<-V@w z&~tTofVa}-D%PFIfXdu=c(6D5j7DB_V_f2?@}hCzVc+DQ6GAW{obgRl$WBQh>2ni& zyGricsYD-@4WW!wacG-i4^`S+byQLfEe9SHu5d0c8N5o%fro`FoYKMNT(ul{V7S8B zGRonhmIDtBS2*)}hfUXV;KAVv$No{F<5~_p9Q@ZDnnSn~z@TqJ(r*MgT<=_7n?rcW zw?RKX2YFmJB#@MnnjFG|ycI9l?rIM8f`@Gz^rPUF#IShLWs24d9*9l$WkMjE3`-f6 z7mWj>g5H|}gr*-G7ShJS2TV)nNaZwf%3~b(1PaBl*ngllP6gzQB>CZeFRzJXjGR(r z#~}^TdF8)MCO-m6$PgbLfp z0hTmQ@-jh=dVjC1@}hC7NO7{Bf2tx!eSTO)69?|xAon_wCctMWyS4Fw+P=e86moB2 z0rGn|gaf6TDh};?b>#5A!!>g)r-sC-)ci<@nnU|#hMcM770$&?a$4AF+fx%cqe+|j z++wC`4~=7voQ)&~%&jF|8<}e3SReG9)^xhf9rmnCv|zhJ*mbEp?wE&r#v*BUvI z#0$n46f2FFjmAsOp^|fJ8PwFrWe4O0l2;fXP#S9DG(yfCkdhMd`h%Y~PGjU`C-XBL2cb05 z#BoGUQ}Rk^x^p$FlGzG^s@u~9IlkmWw*>?t#ZeOnA{g|w$vQHGbdi&qR?yBr&5+|o zUU|QoYT`6UP8}BK^wzAdEw|9bX|9RW5;^@?9JdznWIBhIsr%ImIY(6cPD@Rk*2wA4 z;*=Za+E^Q>4RU6v;Et4^9YF392Mb!F;Ku+p}tEplKp@^R>* ziPH`_o5?nXZ86zo9QmL?ASplXk#jqja(`VrO&nL`@P1`|jk*JJV7v2nyK3TeL=J4V zf}|C_$`r`rnA-_CW5)PD(syK9BbwduHSK+&CHHYqlosqMbhS1%M9{)+(_b$ju zB-@l9-#e?kXdHLs@Ok&`>8w68c16y8^2&Mcnm8WF*+bd`c}(4$F<;xBZpeXOhU0NO zG;utU^ZRYl9XT*l@v-5liPHl)&q-S#k1rFdkq@H;lEy|)+dN#OaM3 z$PbU>r-|c_9LOJ(kH_0y*5i+-X#q@sguq2|!O!x2aM?3wkx9E6Hi0Df;DmaYvP0;$C!A* zcJ*#^dysan8-Sbxs`i9v;)EinFyW9C>Eff8?AOK#L(T?OoKQ`i@IQzXft(AfIN_Q& z1CcYEaNu0j)oBKq&Y)%LW78ny6e1nx=a2(cap*RUL=KEGQo(Ji=Fn{sg&Z=Wpx57T zFYeKL4W@BaUQrsaAsR0=hk6Z_yvC;ZPt$r0LyncoYpBL+xW-G(p2aS||&600@86}n zHqKb&z--Tt?_)G^#vzA%%*C-fVb1xM+BoBpquzJMVH|L-2`{94)*0izqMVcH1k!<0 z$Sdb~YmfmNWQ0Iyi*&k$8swM;xg-$oMGlgza3sGzGh)J!L>=eA`7V@;0)ZndlyQ2_ zfw2xHLvZFX1bP~vuR%tg04SBb?qtwd!hzX^{1yO1-U;M8Lued}EaSjEqfjOal_NvW z3#2zg#tUQ$Lp}&(2ScbA?3H>NSoQjlaYFRG%|?Vr3r8wx5JwH-#gI@D2Y&AsO1PfK zNn?nuXd(P)7nE88abZXufgEDUN`V-`j!H_ro=5J(5a=oGP>cqd#*p2Dvw>%G z1LK4W)n@i<$mG8I2(j2fg$w-vYjER0@43PBPWPn z1Tf^5;LK(Sbx+CC{Uqb)MI00Iy%Ln>dOo837;-~IUce9095-Zj9yNt= ze1vK{L#hd{7Ys2LNX=?!t{W0`X^vkwB&}q@+N$GGvy>n4zW)OKZV#Wylo4NoPp1K)RY!RkTo@ zXUGD(6t&HO*R96`iE8OEPsn;UGscS`%s&W-b z5<|QNa+D#y0?{|5s=)&3z>qkBJZ8uyftWZ@RX#m$b2o+*638@$lorTwhEx(r=|(y% z)dk|g5KDnfXNZkJJ~5=0K%5%uu($~%o*`ZW*~^fA0x9LF!xAZw0EP?^$To%y7f7Qf zC?Y@l&HH|YAtMD6+mv$J>Nw{vL%IpXx*6pR6G$9GN{BeS7~&~71)5V;cY$~^B(Ff0 zGo*k(O1Ge@<^qXiNC$x&Vn~2M^ew3>P#^;tGC&~f7!ocJlU7tUNFY%R86uEl3>hg9 zuhvvmSkE&yiy<`xa*ZLi1!B>Ls=Ni#mmy$1BoIwn6 z6r3FGDW{b{d>P^_Bse`fQI)$uQW;WDQ8C0>aC*2=Rab$eGQ?g{F~mi1dUU2L4}qjI z1dis}aOG|da!!NXlaQW0d-drT7T%A>=5anroFKoTULjGGLA?kPM1HWIL7*Z?m|wV> zW8&P_+Li&I$^SWZ1gXUti5#)EVo(N0*pU+cK9{LPoOc4@s__D;O=?g+kOjTa+?c$B zZ}AYZBX6(>1UZEX7OLS0L~z129D&raAu&pl^*~0iI=mYS0&T8CIFJO&;pq@at$Ji# zHNpWka%!VJC^=#aNKdk?6bSFTf`FHv#EB;h#yZ1^j56 z8K8T>5o@mMt3mt)V$Eca1j1FJ8YEaCT=jw@wss^9@VD|K1X7EU1Y*szI-GN?dEeg% z1ULy~3E=s$=3NyCJNMG*o^h2ehjMbH79WSCNi;v04VaMgh{${k3WN_0-B+#>$ajw5 zNGM2Rz{!d{5)_22!UCsL$PqogBM`_lw8u)*9tDAZ%_a+cFN|?)_|_4KHE`yWB}&5) zNIlpT%w8w}<$ z?5QpPglNnWF`|ZYM2tEG;q95nBir&E?&pZLE!*yJ+Cj6*M{g63;GFrKyz9Zecmoy0 z8fFr>|J0UqtZT7e2*d{VcNl{mImd>N4T0bY-$;1ooP#|jfP&QJbAlP?h|ovEiG?kt23CEMrC-sR#Xnd+p&EhB>Uq-321{%2|Yq zoZ8&IHCKtPGlg>mlFSjY-J`imY-6}rqKaWEy(bX7b}$ukB(Hgr*GB8Y>lD=urb3S7HDBXJ?;8ZK z?@Wap$!meeOHny^fL5nNj^wovReat^Xxi(&E#7Sg?BPs>9LZ~uuBf7!3OSP35>%C=L3ORu4z8#pyv{Kd zawM;%lGj(S18$0{qbCi99LZ}Ls`xmB`H((O2KeWh3OSP3a>=Xjot)zpRpsu~3ptY4 z3RD%Mt952~x|X5$`vDNjRLGIMR!Ux-TgA>&R2P^EIg-~ZRKfOwz4BDcV+9mdtsda0 z(;-LlN|n6c58HB5QO#f~d_M$s6&qA zwH8(C?M0u30{p#9g&fHXj@I-Jc4(pFNVhtQ>M>IxNAg;aD%iisDV;88!uGyB#W*zb zA`mIak-X9*FBlt&s(}}ZbjXps{zg?EvKqX$8&|KVr~;S@Ig)Avs&Wwpsp#^qd$n3o z&15R%NUDvff=ocUIb-rMMRnQ>K^<}=)h1NI`34j?I?$&jz`LJb@JgNt1RN2Y(MOCsF^+JxM+KDRlIHb=G1%3ikAxFx_ zE>!XJ!^G_=rxn$9rb3S7wHsCHY$&RiOobdtwFgz|Y$z%dU)nF^NUFW4GSJmH4i%Lb zQz1uE?Gyb1A&kREVr(Qc6>_9(>=!EVgK?;+jxZH+B(DRgQjbIWq)>4F%v8vcybelU zFb)+}Z+5vCIg-~QRH-wssLnAJawOGZRH-wss2qDkJ9RqbNU9^K;+cnWsHiqE6>=oi zQB+GcvSI+SDg+yQZ|mEN<9u0l{-@*NAfz3Ds?s#)mWxNj-)z)Ds?s#)o!Lj zj-)z?DxM9P4;9rHrb3RSIwkrA{f2Q!pN<0WEc?JKIqm{S%EoD-;^R6>=o6vy#{9c(3t_szLy0bvoooUguDy&b*>p%~Z&dROe9z zpZy{G78&iHC@KfIq)iHPB-I5}!RK)(DHSU`Q&bn33OSPMBC6EmkUkF_ z;7Hj>M-?B3+s9V;TT!Jl6>=o6OQ=$3Ls7k9D&$D2%cxS1Lq%0DkhTyxlIjYo)ZNM6@b1!v|k4r|z)?m_?h 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,|k!G8J+p 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 z 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