From 6182d4cfe95e4539d0cb341089177475bc88c7eb Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Tue, 10 Jun 2025 00:16:19 +0300 Subject: [PATCH] Remove cryptoppwin submodule (#754) --- .gitmodules | 3 - 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 198 files changed, 51291 insertions(+), 4 deletions(-) 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 diff --git a/.gitmodules b/.gitmodules index d01256c2..c8ced6e4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -76,9 +76,6 @@ [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 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 z$Bv0!$+qu)ND1LnNh^_WT}c4NG?mtzS(-`%D5lAxr?OZrMT+587?)YR6+kdu?N{;n z7nmr%d9oh8SzqOe<2d?hJjR|UHr1au)#_v<7MI4i=Tn?SSEmd`9PKc}>YbQ4(g`lf zG_gIpc^jSe&%gK*YZTFSe0@E7E#|LXin%L#=rjGt`haYOtC|SB_J)@u73t+oh2}IL zfDl7P%vSQ0zEf;CtX7(Yas(Tt#Rf8i0`c7m8zfQzdNb-6zxryP$OF}|I)%^xj#I-i zh=VKI$e}GG1JAMrzm}}*qeJX+14#6}=DhgM*rOd+?UqFtT3yH^B*c&h$=+y4xwO_Q zf&^U$ArqGT=xlOnm401f`qOi4ic8p^jF3)@b?nhw8F*P(F9s9d=weu5jn(@-wT|IF zO!cI#n2T6j*-&C~9ciT{SISLFu4ot~&qD&wqMIEhT@*Qr2T^6|^E`Vjg+L35Yc?2e zDH%q_;ppn^5JBVq6;e!>4dY~?##z=yl(T}St&9E8{qr~)>r4r84nPt$x1WV5^b8wP6<9)ZII@J?Qy!Dwi32> z*vgfnGbba4xOdyRr&%g<1?)uTij|=8xx*G}b~;L=X>}B`(d#H0PV=c{wx5t|d6=Tq z^4vnCr4;BpRr-)VNPUPo+!aljC-Ib)QM<`xnf!+?(%{T;G`%+pZ!zZ2#VRgx#ymy0 z&7#}hqRHflC`b|zqfK;l^!jWx!ijx!G|8DhmIRtNdOq&o@OpPTZ$&~gd89}YdA$_@ z;Y<-6piBQ%ieiM+b{vX=1?uM*BvTyA9lZokDNAyIxn119KD)itG&}N@O*(tDJ{~=X z_i!5Rj?M=Zj!-G(4s6kL2fFAvm}H)b4JwT(5r6h0yrl*B>-b{OA4a!BWY1Cnh-BtO zX2b1MW}H^^Cv;1~E-F2H)gRKf4LMyGj;Xy$y`HPY6Z771f|F}==?Sf_)<={NsxyM5 z7&A^XgD-^8@Od`plA~K*zDK;G@Pk7TxcwzK053M_)Sk7fSC#8r4FF z-ua+*a0;1iP`c`F2a(R!p``^3F*=+5Bx=8&VrJG*j?P|uv62~y#o>BiuNT*bIZJe7 zqKh(geAT}WE?u8r-*7m5LKYVb7dT8&TG4I#l7#v9u-23ASxeO3SoOhHm#H|rFgkmy z9GaKHyGbkR;ttl`o6^QOscz%ZO@AQHxGJ$Igdh?bh+@1pxe963LlQR4r2C>uXm~yx z@IffG!_f`<3$I2vQ4z9<8BhF1h{S9@1H!8gNfo~MOu(b3OB`ZLAxX4d*)|1Qds>1j z-K0R+^K4PEA5gv}#W1V4pjh>Y#a$oki$NIVtr)!+A~W`Bqu^or*``59!!hr4i0^%A ztdM1N-8aUR`yL2JWJIZkfN7E z0n`UVnj7)O(o#fpF@%c5KDV!4r0H=K3Pc&b9FM+)H`zG-jVr{UFZ$8S(kB;dasA24 z{C_v)dQ zCx3k{USC=}iUGf>+6@R>yKCKAfMs@7^VwoLpbu{hI~?AT8ZON z;^me2GG2Z1Wch6UaeR5Xc2_t74ECho)Ab$wXi(RwE?!gi)>fsZ`^S7WtLmBaMtGi zr`%0Tfjb~;cQpFq_NI$G>bLHMduN{q)xLvnw|R*sb1lzj=dBHBGLkG0Q(|a&Zl}mr z(4|jK-AR&~FlU)Gea>PIGTr5w+T-++d04bv$0kxyei1t@j&{|>fdz7fJefXQ2yw)= z%Ez?`W44yH`QY_~$r!k&wMA>^oD9hpB7+z{$_0{6Zr;uwgeOr$Bqb%@^PAke&QG!W zC&^$=EzC;->vW&WJgH1Xz6@7$-iw#!0CEEXnrg+v(?Dn?SsDmcrP|9$w7+N96Z2p>+BesJ17TZd>TVyL8Kygl590cde+33v`@{yY>TuAM6 zdzi~gv7>CBYDYmg<&FwP)Su?lb%BG%PfG7tisfjwl#!tFYS&WMMd>Bw@D9`DST%o+ zAZsbfL7w2EnK^?{Mq(YbWFySR^DJGKGO`Z^!$>Z&46{@z z)0G~FI!Bz-0WPG`S<^*ovc)oL7&`7$G|4uMzwWrv;{H;K@uyu<*W20{vCX&|&p91VnBK}r+mIUTMdMixT| zVPG+o@{B8nS;#P(0ZB8&RwCbETdAT3+3ExkoR<|dv|}??Hga=NimA<2DJ1r}-P=kt z*ik4?w4-1V;f`uW#GmG!trXps=Q)xsWk4+%W>UB_8fa{vzzz$sgMhcgBCa8coOUH$DuHo9GNwdKVrA#Lj(}o|hD_ig4kw56) zIlPvhkLMbj2N{yjmBkuThY5pgu|fy>S0s*3iDvc-Hx4lM(JKkm-=-ab$!W1kf;I|^ zP3-ERopdpJnubh;=~rj@kXENbhSXrJf=^D&c_wfzoHHXiiz`SjqDv^<2v?E3M%b{? z-EK74_eG<+b+vIw6uj=giQ+30>Cz6p+Y2kb!Viz%ObNQ!jpZ*~Z(x&|+y`|d^N?vmdH+|y3+03zPWMbq z9hOTBqy=y%r#}NWMBdH`kV2q|lS>apjN(*T|{HHhWQ)Pe>GohY}5$OaHVgeYFFac>?A(c)0 zVFL1#rOjv>W3-c476zuQ?Cm6uE^(#|ZY9GeZtSu?e~pdhos($qY%=Xn@w?nyt>Dp? zac4<7;Ja1J-VVB6i%ABmuotB9k&NJ zui~-lZ7yR_a(evs`Z|WIbF79)alOimPnI4Z?QbSRPcCQjR} zHgdww$8T?@IAg|RTW6vK7z(7|P6&ZKhVle*yHK744GqDRnJDSL!HLZnjNE(V4d86< za~#Vr?YWX59FvIKKn=No!B~(H_c|2V=AFiy8Pi_(gF@BDKv0KgK{vUC_fI){C~n9B z#;cdAbeGL7StK@8Lt&lRpwa`zOp>)wp-D`Fn-=QorL-8w~A;g@hS*c z!l$1fuPJ5cI@^(os^TUb5mMBliD+x{5SHz-e|t4O?q9}-W1MnobUNbu-Qn%^vyr&9 z{`qQqgsAm&G~Pq`!3{!veVS7o@XSK1CNT?5Ida-M;-2kz9A7-c67%G8G`K{PoTIGFLv!6c?j$*=|)56|B|!|h9wD5Dmv zomEt+4cdAcADxU4R2c=c8gmw;9#{{c*_ux|I&aV55m4`x=5rcUf7+MRg3%cLl@D*S zT#5q&J1DIE8F5wHqx$1V^;Q$nY2-hNFMCMI%DW@*Dd}w4)0WF6(Q5#N<&H?gLFCnl zvc%wtPs?lTXgdve8>g5}#H%*_0pp(Tb?3{hh0|4$V>Fibnr*LuVf=54GFe6F=ICN& z@4ktimDgTjFu6@)t5wZ?N^rvR`=z}c=VgfCe)XqXza`CcM+6md$w890YZtFO?~AHR z+)BoS$1s~CIpshuTyI)gdEX?@#%Hf^nw-7|o#|)y{Zbyv^-T8R!DaRQ!&yM7shtRr z9OIyp<`qrmE{@}KvE>V{zyj&o)z?F4{?k`-LnJm>0#bOY^dbW>VOIS2{Q z7&iuq!4yk6Pf~3E_UbA*hYYv+Y8NDvSz|o0^#QJqI;DMO+ws*+JZ@k0ah(pR$cGXN zB15#dEsF~CmT*wwawAF^9VwgpS3ZN{GXcm_IfDpkSJ?sqOXQ3}3*fU&o%~0HPZ@r3;%+zCE zAPXZolxMo@WPf?d^>vr37>aq0O}B_8#k7pJSxOWHyh#OFY7yMUQl6sAXhN_#vUifD zEh$WMY*cUf8kYqQ&aUF4X`&WO4Lutejn^Q-<}1w# zPC1|!IC6QRc{_cD-MMnPnof8$NHRXA!q7QzIQZPct?JDz3(wh30Gg$t&bplB4K+?% zRhDozc*F}!mT8^AMB`(MpNBhi<7@v)WjITJ_%t35E(h^gX!)O|RVi!7XB$r=r#VsE zo09c0!_@{`R0o`&-(KHhPtS;%;aPo4GgkIaP&z-X5az|$Y$o@)sjdyGtRzrX3X%ug zkS`BFq5iGg(R6^Z%saS{o|4`=7&>{k^^>s!Z-H1!lDs6gI1;~xqidW*fCcPfsa@WM9IX9Y($B`aB)71l|_Ox1_|jK=gCS#08%d>U)w zijzb;-UUXHYr+>o<8&9%3))U(q)V+xCk6DFB zG^Dbn5N3j{kxkMrSbU+Aem4hK@ME(TsT&NR4KYwp&R5bD724S99)b7pf4gG~(+z>~6=X?4 ziLDs9M*S;>Xn`lj5+6Z>RE&V)&P)uJq1j+)LXPQ9_2GH!A-sr^{)G@GVk2@+gwK{2 zV&W(4gc#DTfEtpq{fiE=nED{F6!?%z35H`jWulQ1`Ro|84tb+F)j-T7@o+6VQa6L2 z_e6l|Py5bG!!s9((=t~w%%o-~pt*|5PQ$Xr7tm$BA<}OThF5PJ4jIk&+le8D)uGI$ ztR&YEmH4gO_||VwD0X2jrHo0tKOByxn^!oH$3E)hperahlPq$BDCKZU^a>-GSYtm` z<8vC=TeriX4sPrvm0YxaMOiL7iDHG#f@Uw!!$HLzlBIIoXM-X2Fv5oz!(Dl9T3%@N zfhgXRk_owFX_14NfhxUMI-LkFkPUBs=obow3) z&oq8%>u=NUgw&9HF=1yWoEb*4`=^97g~DHvF%i?@R>d}-F%7z?s3|CJ??Rf#SwiLov$uK7jpRg{kPDG`HX7}Y5ZtjUGTA2~ zh37C>2@MCmdH39AAFA-8k^9*(Gd2}Wu1*IhstvzCc4(sTu7&UlseCE`~AEsbGH)0ZEoQ zm8SGSKI#uIM%Vkd*JtsVV;8Xbi2q2^<|t}f%_K^N*?7L}GTM_+CtC3@N#OrPU8&wP}{>m9P7 zVB=r_Go7WFkiGuxI3BZKLT-=P*qrGcSrSkCFYSR-IZ50boR3G7(dASE7>_8Nl zZ!o#;PtRXw4bj1;cC zWEMJ`$eAdDVK`zzrIkOXytlp4aQbp|9gp80#W&-4f(#Wt*d)_csUSd^N;!na2`sN; zaZ_L%!%?1_Aw1QA%;pR6 z0Nx)B&*XZ^Q9gE{nkkN85VwC|>XmPe_VD*dMMdYJ><@Y!FA)dF5l()Mid4M6*gWXG zx?rVtI2tJ%nixK*t`2VEArTrDD-J0=55i5Niettps$9kAMAqTfphL9CePnT_=t7EPzH|v3byF4OL}2TC&wB3Nhat-3~9p)&|XJ zS5Zw9mrZ4>=U-x1cvd^4oSq{DgA=9hQiys&P*|K1XU^v^rZn;h6f5hFPm{v`WKPNWak9-ya!?{ zz-Yx2aWUaA{xZ7aV5dlfcR+EM)d0`?II7J9B=ejr#z`K7z2=gh3TJkR6l}dcNzMrO zfp9u$h6%Ak5)<`C(REV(s=gyKJvIF&V)`mpZY?TSxDCp8eSnqBYG`~{4b2fvHmw$u z3O#Cz@yvYr$(&G>Z$>}}%1Rs8D=%~RahZjyCl^GEPh_1^wIEu&0^uY^UB<+F`b*qZ zLU;A(O&R9qEfw-iX@QxC4K{eWVWh?|B8{%QB=~oA1B>+zA9+j6#-qIsjv~xVV+=ML z9|>XTVdW2vZQxvrd1(!hmX6HDMS85w#__7RCfz^X2=3W737Ddh;aORB>k(!GomIfa zMhMGkaV8ET+`#@Y2nRtS3@=T05>T|?4QL+}mP*ds^YmCTcpMBCQ(g@qU90RBa{1a6 zKDZJ&Z@JmC3oFS_6BErhH=`k4vTk*s6ZbYXPIVv%?z{y~&X=wLCaI#CW;?b^Ok9Wx znxL^|-~$$D^K!r~dMQ@&Vw$)K`ZSo2^SPDlsGUrmdNP8|FxBB$sY=4TWqsW*m$80$vEkMYsQ? zd3-e*_Hn+HnwL~n(rG>J89ga{8Mhz)ZL&_O2r^G2YV@j{_S6kH?MWT1?{U)GS<2I= z&fYKWeAs;%>esMCTMKg`^@}@bi&#&@cs<|Xd0+a9&BE!j|4L4SKfc%;NcY3>42Pf9 z`K)G5N}W86JD}1enRh_p!jtG|v%UVw<4qmz*Zr&A!57Fmk!!?BzZQVaHdLGqMXk-;RArs{87(XUCpYt}0LC)&D-VSazU#KJ zWpp&a>{iQ;@iDMr3f3GN$Bu_e5(*-!+1lAH__ewO>|kI z%5{uN$6{x~ui%BNky!JejY|TRV29p9=N&Vedxr1zm1y73C5vv+Hah1k@lIc6=@oCo z#+0+tx*}UFn3s(I=Dx=v+l?Al=#bSW%L9v!g-KM`{ag|1p;Kuon}gwT(Gs&g2evB` zX6JgsX0{MK8s*l{)b_%lxvN)VU8vNsH+UB^vn|9G=E7tq)@&d|7yZniXr3Km#{=9r zOn2}mJ~v-4AL34A*rfVwhN?f0JT}j#^WIKMvW3DrF#u`UBfiCz?{#%uf1B>pG(O8I zloSr+pqmRLqw`-Q>qbhN`aW)A4WP)&4Jer8cG&bP2!+BOol}Wba)E47*Lmg`Vc_#} zU@?t+F!GSFA)(02jk}SDOg=l^c;KJJnOfIUxpbzjad1D)@dGX>RH-k%n&STHx?#Rk zsXNY^xCy{^r(q#RzJ?%uBTg_zF@{qY5QJ5AUu2l0SKXVyw?1N_py&!iaXX|am%hWW zYp}H7nglNqw0vCgiU~Jd>b=62$wKL7mAIPGi@w!5DCR8*3zu6E5uGp^M6pGY5Xgs) zD7PRY0%=$j337ZEN~A8A<^#@L(o?>`!M45A*%XQ284p4ON?GT`;YeMpTvV7AV09Ve zqaAihQfLXa1oU*ug;6s_%-tlsxKS=H)5D2V%!9)3QY(U^u9ea^Z{Ru$_vL4Pa3wA) zD+Dwz!bF6J&e=In_B&Qije>^n%KaD1m_pH1CS~BAjhZhJ@Pfo_OC(HyrajPMIz@L( z#@ae&GLPyx->eiFl}FN}IyoJfd~%M)qk4zBr7}Bar-QRQ1X&(BoZ`*t-mos@a#y)e zFU58z8V(JTq2T-3v}y)wyZvy7!Dhsgu_PWmNgg?l7rPz}law`oN||n(%Z}&-^$cM5 z_O4=}ye#D1*cG(R$RIj3g9w6Oyd7u;@ECZ)9Qn8H%!UBdYaCe?zVU5#Y?kS}0o3@I z>J3D)Q#tPBtYg9B=PAl-G(Dwc98Fh|+nY)%iCR@PUdy{*k9O5|8>Y#WsX3}ktP)-|fyKNfZ~(LVgs z($e%;M$~vUN5bo+f??ft@~6l4PP2quzEyS)$PU8SECC9 zioN%YUqd=FJ6?ar8~7%^;A33nuzQPqgll$tps!`jKrk_^72ENB9$@-?+8h?hXxa?!L^mZqKy62gAw zWTUWg1jqti8B2+uA5==PipV0F6}L5GRiQXQFAG^^D|`KPNs&$np^+n2Ac_Z=C}t&Q#_^RR zh9#qz8jl3ciyWsUO7Zm*SybD~NoS=X;a}h-+-U=5MHFxswsy)>@ZdIat_q)=IrwRO zfym>{#b`9%yd9oT5nnY%7M*=4od-N{`FTc#)c%|RT)0gj9;Ys6CX|WiS{Y+Oo92(e z-jJDiXL^R*XAaL0>NjC^w&9iON-6%V2w6#!jYWosmOYcSc}kp@y2N`{b9-<{QY>!K zPS1oM)a*9P=!B;~`%Te#=#5i!NYY6{w6(+_ALl`K7beAGEKLX4V~=P^qAk6mm}zv< zoj*H`uG&-%M_AjLXkS~f=}rR^bLmtSnRxhZtqd-)!A4|;x@W{GrI$sAaQ!=UbC1~&+N8P-Qn;cv(BwqENI$LNK|aDh-9ct zyN!2hr?h)yG&$=lD&`rk;?GhGPKK9Px06?Ngi#~>K)49!$xQnL?9+{I=<1K?W;(_Z zG?;hvuVnPHagr^>XLXx@Q{lkq+2G=B^zybpz92vs@$cTo4T_9vkUg`qarC!}@mfKM z=$3|oR6B9@3KgFJx<+MS3{oPCfKG$7$e2oGIjB0HiaO(iJLY8bE_vy&&J z_jogALFr?&^Y!6?3e9}sjg}8FRXV3bo#dz8^G^#6rW}Pp$$9owgQL>4=-5S}YFC58 zk~A{p*`LmNh@Mc0H@kaLP1-cv2SGU8-^W{F|34mx%-l=QN?CEt-sbV(NCD-XOs9>b zkKxSzboS}acb`t0fBIqyLnItGxzRdgbc8&-qB4}ME&J1n^k}~O+=-#B!sUDOQP~iy zF-<_x)eu}JhdowG6wG7I*`Ll?;I5V4`|69u;Q^It;UvI1vOlZAIARCMo9p;Maw4T{ zWn8X9>UFs$b=a(MKae77)}AloJ+wYNX~{!?t`GNfRJxrl<2A|<*KP}K?BY4qz&+Ov zgS45#ev)2k$aZofEq6+EFQNr?N~tY|{u_X2AfzMER4D09n^RWH&?|>fiWYgv zh){W_5CanSXYcZ^nXgJwXUG=MrcIl(wzVjol|`SqemgCy~+kjBo?-w{322IkJ2Y zz~0i!oTnvzUTohKw)F;(a*d|Zt@B1_4(4nYG81R#BgXKrNs%Vz5XJ8tf7|hTRsz`u zn2ik-QO1O=BI{7U9>0`t%SEowpm}w(Icx|RPtG0cY+({v^tI^Rad+=OG@TH z|Cww(Ep|^24>2z33w0lJpru1d<7Mi5fGbm>@CYBBcS&CXOS&|oD|wxua+z8`U_jAA zYN_kuy~AvFO=joKBKEhNFU3WW#d-B&hJOLkvrO`IVGyB>y!!j}h){;(9yTte}}?o4Qh(h+meF-stk+=^|WM!148m}hbO3|v$!uOWwP1r8(88x$v!1b8DPep z&Fz9VYv-`}d-cegaCjn+3l8h?c7<04D+yXk=wK0Z#tsGw%`&0mZ#RSw=`vc2bj6Ml z%aSSbVT)}$ZEg)JZ3|~IamT)%-y_}n>VcO*_jgWJ09yE^VCig zA^hsKwd5>nt-ipz-+1~@yiF`+?m2kg(y2JH4z_ET@wqXZY~l~|C;MbAsx|K&670&` zgLNT{kxPH`*)bkkIPYW}lB$(#Ly8s$>yUSC$AkfH=1-YKui$nL8!=%O+(#{ zpI2*a3HMOJZR0ttvSrfG$vjMmrfrHMjkWRXPJ)P6@&Ac>@rd_k|At0@F!Qq0-A<0; z{ezJkem5vGxU6qK9v-M-pq25{M$Jz+@eJc1g%UNk#an|HnHCPB zFYyxTHD!RKw{g{0+{;J$4tc@nwpZ?-R6Wk5c)TsR_gd-BbBC4)do-oP5`xYJNf1nK zsbT~M!w-+9_QQD z&VLguDdEBKPL_BL+15d&Pq>$^7WP#Sc){U7@qDm)L>+oC$(L9pslI^}%9QA8Rmw*p zz?`aveL5j}?>I@N)b-)bskx z)Xfik`<`we>KsvDb{+yDN`I3);Km2p^on80gr2ww;rY(?Dw=P0jmOD_`H0KsLwBm{ zRs4lBvSkl#xpKMNSx+82Gpc{eEVN@Ti)A#$Vf zJdg}PnzGwUW_&YqF!Fx!`u--~?dgJYaLHgLCye`uywcdedG0kwbg*ZjXB(MMXqC1W z=0~Vs_qfSAnp!*=!dv=wrY~eqr)Ng1^n6IRZs~y(V^o zBGA{5BSx-!MKb)VuLqaP$kZXn; z7V_7Lv=Ag8%p#j20><)W&i1nxY_1MaNp|`wpuS0=MK^*f716OtjqI!f%T?wP7jV-J zSQVuWYTfv_Ub(ZR2X6n<;B$JJ$y*&<^ebN5TrHi9?&$DF3-W)9?N~{A(4rs)ivCZA z;tRQr-(>&R@c$Jx>hHvUM?4a3^*0`5v!*@K@;42|#4<=oDJ&a#EYAivH-!1ZzL%i_1Tzj2;g>P!3`o*0oM7`y;+8_ z@8JSAdQJbGBAPAbi`omp;D3C_3sZN^GD`Px-OGAi$-PlFWlanwk^~F4%bRp`?|+jp z$$GpHI>gJ2oSp1<-CXY`F;@58FSFab8JU=cOF4XyXCI)zr<$DM8)Xf_%mmb|FBY(? zM-qsU{ZAn!#oeIwAwis{Zblr)`Y{7J0l}VMxj5mA9Pc; z9DHB?JGkY4f?LjBd7GvrnZ3#p!HTP7ui5J$h_5R^{M8GQlW1l=?X2qU%z7p`nuZ{2 z;PIARu|Fo_O+YI!Dm^$)vie)2h9h`Z(t}ry3F|S1F7L8SG2RaYc8i$n5+9c8FpJAt z8ODcSg*Vr9zN9p?sR6k76P!gDX!d8=>_7a%Tsx0vH9LxrcO-bW0P!#=r=<7K@3 z^N*Kr$>4lzah$Vu6%&`Pb24i`axsP^ME|WJdgi>^a1Trw^LV(b?xJDGDuIj#37fB= zG36r=4gq@vzF|4%k05a<;Nx(H&8|`!`{O21eU#&8Q?^SgvkVr1@GpZ~hOzc#HS+P# zHMSecUI}d)B zBwtm*hkFiGti=}IDo{38i>FL3L=TU9?z%}0+l}nW1!PxBCB9_-Ats0bCu~txMi-qi zmlFSSmz}|)=hi*b8cx`{spPFvX5}X$-~}c2Kb)|a-tm4_;hW0Ka!sZTz2k@%eT8Lb zGha(-Kq)nKhqQg zMm*mXpLYcVMmyis0_bSrQwqJ$egAsSZ;gv8H$M}h zO7)bVX|km^)t_pzXWH)HoB2i`?D`QZ_>T5HPv&gg`CU)a&y}t2td%^>SDV@`oG0@R zM+mz22GYY5XmfbDNyL-qhhLis+|c3I&jZSmjZBix&R~%n%eW_N#sU)RVSLuQuFtO8 z&ENib`-jcpGAl{SK+{2Ffam~*tuIsSjrPY3Ng;&3h<~jzRUPWpt6%fh)637#GUx?o z_~y57FvH@Ymz&}1-@m~cS_Zw`3@Pj;x1BG~rItaDoS{=h*bYAIV26i!sUN)|0bz2ygkaxPXxPWPnbcQ-J%vfllrqlif>VwqbfMp@@yJc>6-H z+<1nkZhmht^5?pJS7=J+QTY*!L+pFT+nrFwGKDQNJwG7jvB=mgNj0*&R5&NR=b$o zv=Mt7Zx&A!4^PkS*r=L7)lnk|*L4W=T-1JExQl@4c8~sxUGqEE7wJ zWq~G)1y*8F286IGj&@O|PrUc&4OZEaX_B;90Ztn%ou&kNOH|`p6BuPMg&;LlV?$M9 zEcbIwjAwXCBXtaA?kAhA(w7zcm|UCXI{69t_Gg<~8R!0V^UY2WE9)XBXzIy=s!O+) zyzkk&4GCj3*71*`e9bQ}-v08UQLo`Y5&naJjCuth@^3b<%B#aflR06Fk1tJ_D$Bul z)G=i_Uz&82{)0*PN6|5}zToI(Qz!Kg`98f%jsw$PvCmDKb8y4ALoJwS-i702%atf} z6YfkrrD*r9Fm#YGbt!v(8FTT0%O~tzip$6tHtP$HUN&{bjGkkKZx)_M&?A0NkTHrb z-ww54qInmNlkJ&gOp$iq3PTGCEjexi6B1Z@Iuk@#uXbIO5)}ru+&bucsJ@8Xk5k^# zlFeT$FXi3KyrdKa@*C0PvOj-ogrVR85RL@YtkaNi0|-Wfyf02d!UG@}2{Rcg!zXk( zJOIj&NbMV}R1|_BsLG^FI{{Hc8{*~b7jIBD29=*mGFXHof60N5p0qRwR-ALLfN060 zIp=+zu}_>ji3qvSdROq{CU;7oVY%hBPZ{^ZQ_e|t!`ye;T9-}QKXTc$C-n#~gSoe! z+v&^KzrCJ~I_;PFXP?Yk2@^@iqq;t{T%{Z^WA#<{R9uuviW1UgQl}hD86D1_wN4-D z2t%V}MM%2KV_IddSfsqgH&@1bm6EYwwZyopCc}6|#F?)p+(V0Yf}A zg!N_Pu|G9${pj<697$;|i&kh&_J^OD_d$R-3h6&6ns@ty^WP6W4=?}y*faAP^}&AT z^IQ7Ee2;PpHt}~|5P$ELmv89ZG=1Z=NxH0=ex*$n2T(VmEPkVS|0!8AC`{0? zKMk4p<00>TQ~Dv7L;J$mR1i!l|4jCS@z{@uei@hjkaO}0GO0!1qh{CL;ohZ2OI=e7 z5ZP&U59PbGXhptPa$GN|=lcgV)MTyg=P{6=Jku?Kqjsx)sI`b$ODkd8;R?IF&50_< zxdO1ZYl*#GK{pr8iWT9V5N%D1KzWgKotL3d4aYi4a9{thsWt)2nPu3Nlzb>}d$l~u z$%Gl_;-$B50Zm6u`;75?1?_DF^S8H+p4Ftr%H(QSJK*~|6bG0uMJ`ZBZ5}nv`LYFH z+WBS?m$$q|h)G;CXny_lfO?SI)gn!ORop2kuGu&&KF7QWt963bcEx$6^%5)8t58a0UrPWnKN2&DeyRQbiZF2thg-LpAr#s+h zd@6KZqZr|Djp6`~qU&mY#ke#x1fxPj$()5~uu^Z?-x}p^xE3I0wRaDm`G(kGQ{QrJ49a1x<~vNa8wYy>1ET)S`qU|1IV0MN-hxB)(q@dnErZGw0iD*4kG8N`ET^^r=tw;;)6zxk88hyR%j~Z)7PCr#`F7 zW1P5BH;_t$v&wx2LN+7kg{=CnI3A3JEUs2aufpPW+ONh_1F*zY{O1$xIA+>#-%WL0-}%SufwRs&7V+*FjxAY0`ADKk?l%EsIM>TVt5 z-K1Ttdk>ZAdi-*7M+>cPF{09@w^RAyR}Lc|keaq_i()dXy(mIz zf+-3KfBS;8fGdJ?uA@1u*;|>RZ4>WyB1Dptq&RwMmm&fHJpWjzC}_J7q?%a1_@Lz~ zkky8z6ex>5N{2`PJwTA`pPEQ-FyF3r9wS0YT8wNzquF6S-_}LVqIkbrSe7@Sw4(xd zSnpSlh`hsL_9Yg{5N=R#B+F1AP*SuKB&QN+nT4~yZZ_gLNrn6M;qj3+M(Giwdv5O1 zTlkgrlt(>pdftoaY{4>e=95yA?!~1D(pz!f;U+_Y5-$|NPOeEdic87p*;ujp^7Mm+41wL{d7HwG(i(21jEVP7&I zmLhpVAEoR)f7eeR2DWlV^M?zEA^%o~W+uyhUCPfph;iJu=GcH0Et`QIi=&@8Q<@)3l(DO%g$lj#zH^D*YO%c7=a0VCDXOu zCSRW{*9tX)QWFGkTUr+8deyqBk8N98esIk3s&ySj_FnYC)ytun$;olOg-_k0wz--X zBY4rWjHo=NDweEGh1xx`!z;?JaCuRp%ps?84r`fA!q28}9s6MV(y9;f`kr(Qy2?TG zu<(mA${3e0dGoV>D_+p#;)J#?a$;!D0%u-ZQcqeqI>j%nu?4-bjyCMb%dW7-))A~N z3m|W>FkapE2GYSM7T#~-ua81;i#CG&tT$gts9UO}O$j$Mov&7^4t$ueKVw{5d04J? z!UUyLskNjiyJwKyZJIL5i49Evn?ln-frhl zvrYWhY#nbt?mwB&z0_hcM{X3OU#u)`{AXFFS)cCGq19r~Htp_gqra8aJ@bI7XFqTO zBFmoI!QVO!jEQ7+H9lpsRi5Vc=(1PX(|n=V2~YDGtWpl~G&J8W{0%cb?|Ob8i&NCX zd1W??w~f5EnQEcGm-pnyeAbKqrnhZ64{LdCYw8@`^_RxmdYuH?K zM}r}Nqu5hZh->k4r_rg8hf}J@P0J~Nizco1w9~G=`(6LoYxbjhv(-cY)=>XE=(fh= zQPdzaf)uL)#9-7KjN6@Y?cGb=cGzwI}N|TJKi>I2?^Soo2mXd-wX?8~yXBh5yy5{`gn* z)SlG4sJDKt+qQbm zZoS{>*02lpukCTG*{o07HC&DKufwR>>`Z!t8tP%OUx(vHr`N8HkTN`*_3Ke{((D6? z8j51*Unh;ISs#wtHRMOvzfRlZX|FjP*I-a$zfRlrev_u%&>Zn=qd)C+n+RlwK9s1& zzc$CMZoS!_)I`KdhQ+VVNxRwW12Rrqw${J48^gwUP_I$dWDR6A?F%oz1Kfa z#`Rvi-ivCZR+9mF)98*Sz0ssb;WY+(ya9iXqG2?uk=5nh9}3i)E^;`Gu?#ib4Bq{r zneR=%*BlR`PKVZJtQqaiaN6uQr^9ZI0zl0{#?i3V9<^Hpi*@;}+iH%ZUVB(eFLW6( ze(Uyoqv2>Wu3g2CG2RH&hu)++8ns{tzM^~5PJbAJ@0yKKxAyMM9o#thmr=cgWoy^o zKQ76QMZp@4yMso*jX~rkRDBo|4>!PP;?&Vo|83eIOzO=+BtN`Tpx!n?^-g2dsU0?- zH_2a`x!$&#qh5r)T@yw^=&{)-Z(D=*ussCd3IfyROMPm0dr@mLg@bVe%h&8`D-pZ0kQL(oCZX$vW;u&90aM-LCYfQGGBPOk1PcF!}gO zm}}H<<8HlEZ$^-Uf^CiA{%G{^DMIdn7MjH&+-O&iTYyWOsBV1)%WK^ryTAMI|d zGa2;TH9X1Y_QN0DK@W2uOeGJSK)aLfq(Li`MW-1%|Bqgy9Zd$^F~k=v`NESTo5&xN zMyE0Efi1PCnEux9G={@|OQIvJJ?h(Z*d9labkt8i$*5^S*tQ4tc54dJk?KOx*T-bT znV#Csa>y~(gXz+H;M)*P({^>H5>L8}&xAh`b! zw$^ule0e$3XC+{b#+|{i*PVd>Vft;XHuLQhwvS$b1~{bO?qXwskLH_Y@-RL;+{If_ zoI)YhsI^<|c4yF;8jXb6nl*zw_Df<*_gvA&V)Yn0fKj*BzQuz!y9$5-Jy68|LxwrSs^fj z-VB&z#-QW=WYX?KH!+<|3}#2O>9`JsWt>TUptt%6lN2o#pG33P=tiA(3zkMf|4d?h zfIE(!0~CPCq*WhA!%Ti*n(F4PrrNBvr{iG{(xP^Kxcj(G4v(qTniHg1>$dtBwLev@ zCR=zG7`q4BLT}i|-s%XdJ;=v38`+w*L8CQl46yB&@qZ67bjQ&R{xh+1WfQtZ9XFru z6vtum7-QqX=K{+jZEtKU)6Qht7)*L5I|;LrYSpSWdJzsP923H`4|_qIk~R5SwN_)= z8F!&`!BaFLeI;I|CJsX=G+MQGuZ^b?=qbB+zZZM!bNuw~4fy`u8zz#`vNz~9CR1pP zDUD;{-1_d#j-P#Khf_9c4sm3P1(wFUX|lpQ6ywrXZQN{uoBM;>O8P25TUdczB;WJ7 zK$~vYyMQOg!;wnCJ85D+Mw!WE(3(czM7h=Mj1|?It=6#HY+-B1%N4S&({eQ8PxCJ; z&NDb%#=U+7WzD)NlY7q7QLWwSbRg_T@>*P9{PzIR$dM~NFBFbZt=sHCen+@)SaxO} zXcx@b8#Fp-@bbz_Rhz6lkRi9 zOt|QbhV@}*2swbYS3JL1J${0>3VG-#K55s+jrJt!x0_fhdWU~61oIX$iM(2P!%2J4 z=}$%^TtG}npie7M_)%Qv1va`d_-HcfL&vXYXDtNRU6QPwvJ09-x7F(PdeF<+IVeos zCUbRbQLhE%5tmHqt3`9%L&T*raVOk9)C9Y=PShKYXo5Ds2lHs@*81IPy)*3hq1Xs1 za+8SLfO;NNaC;Ds(`LKb=V&yqn&7!l@#1sgsKhO?Jsmdc;3BmknTGM0>{g=WDudqa zHJa1<07t)g9Vt3H^0w1{9or2n^ZUCOAj9@a2v<4{x8$uKe*x<=V+8imxILXTSDhni`>)~Q1~i~3m06!I$%RP} zVu-(1Pyw;~&0}r|Euf7X^r)Hk*(5l;=I`DJzq?crK4L`9!UQdKIFLfRKq8`*MS8 z8W@lp&Ke_lW7f;uCk14;I?5ag6hEK zmr@Z6yJP~^8Fw13UW2htrjQGDTg)e?aHH3B(j0Z<^;bwoMg>Irk-h@?Y*1lRi=c<# z;2xR5JO%#*#nLa-t zWH5NY-ni9<8I;cLg5rwR#e0xiYTm8i1D-HF@csI*!qG)UfN2rCB=dP?bHgDvXiUdV zlNtrT64qldnBuxIgz;DG*)>i_Vh!56QlP9hHi0s&MeQkUvjdodK@2>8O3YF=f?h(m zV+2&urHRYuX$_{4*03{4^@z}pFi$rIy?&$D)h?4XvJx=j-U3oeXDvla^lRd@>0=|; znz#_-qS5T(|M%s5#VW3}i`Tn1Pw}1^q0zku(K#C6ZcTM1>56L%dk>*;H>Xq4kZkBT zolZL=x_f07BI=iJ>J`W<^z>yKvZnFHwG_vCZ#<=gdi}IX9#-=;hJ8id3lf|6gUz=; zo_27H%VI|iHwAInlIY=mTF`mBLzo{4df~d36R5f)Zcz35xKl?~Ty~zMax^<7=nN2h zY4^Z;!p08M6X_w!^XJ{0RM{itOKz+$P7})IPHsV#yi4b z)gQNM17eD%&|8SWH;DEfwk}Q`vLhK?C#`<7K53+zBe&&o`Gv0}SY4>Am^JS@>UOaD z*uO@QVSXpJjo~JPW~%|+OJMq#)(9cHmZ}nh2?%Qd?!9_2+)2ix0nCxmc(LV#M*=-9 z@5F@Rnt+vE?ckZdfT+3W{l-JQg!J137mJc1gY;!_&(Ixl!5BilpW+=sxo7ALG#U43 zWGMi2uTBm3Fc<-c!Up!q^#7+0SdDkTlc|F)V7%XSRL6B4<_TdVfB$%sq$N$`$vt%> zbr#_P5U^i#H`tn^0dAkTR`3F-U*g_|ZbRrQ^tV?dt@OZf*=n>q?Exl+y_Uo~iBL*9 zArG~HGZwsyi+HC$ti$NbW3WiKr56eyN&iPG&>F{H4JJ{TMK^L~TYc!aa81M{>9bK7)_7-}*mc}|apy$X*bQ}qkCd=OgRYwChy`H<TiWLl%U9GF9QoWL^G>yC!FyUJOPVS2#51D##diyzi*dZ8!ROw+b3ouOsF;hL%2n=~eI>q7DgyljZoBxD8Bkqlay4sB+k3 zXHvSI$X-TTitg5|^&5j$tATfW8c0M1NR>`98Qx~&?OGZi=p*kr>f!mg4ug>JC#3EO z5!pUX<1LIy50sFgiML&$3G;4KJfBP(uy)#{1}p|B;0GM{Hz2E4gjzT}8!Z^CaMA?P z)aW{HOh%K@cm&x<7b5oEx>pCrdvu9#^Rx$!@KJd;c!uDf+oy-QWC1OSPJW0PZk(Op zi)ClWMXOW818^P7(6bz+1qSEi!GhoE;>zW)DiE5f2CsW{p(()J2I;HZO{pE-Rq$Up zxvoHcNEoqr?|HuoVn0T`j%2fOq5@@T^@O=Z9jJ7D(mi`P*Ki4~!|A39IiU&-rfppR z$I_<*NRmGICfTfEn<9M%N;(jg7iQ4;P7jG^oN;H`>BI7pJKof>n zQt%&)e#2(BH-rtGSbKyeL?l>UCqyMmWsd-QH0VM&n8qWRUHRFr>><>v2UGJFu}Hkv zq=hH-KCW6MjK=T<6vI#EX^G5`6u@%$@eQKZX&e$}$Y$ zGc;-7d1_!PvV>-KTUy2o%6tfHHJY&fHK*OdWP-K8v$43W%0IYe$#PYK$5^*Lf(sF( zlJg+U7?qC)m$B(!g7=mB8uFMP;xi#Hb~vgkf?Fh?|E2qlaCK>RqB_V@CR%VV@_zj$ z?mW=CNw2_N)4aZD%?+9i?=|X1@J7OWu5)f`H|cIrl}5wPs1BDZCtqf-RJ<3wNBZzd zgNut7#SgEWyw|AHh`P|1;hK{rwIrJ`7F^i_)KRbd0kx>#Z}xCo^^XSs0o4o6o#3th zbb{x8TQ3?^D<`}gR1hfVFjLvO*{L7F{8)#k)PfzhLNA#18{H{P$8PLz#ybL@PYpru%@u!Z#bif-e^ za5}A{8m*I^$z(tUy!Bv^2*VD1yx>SDx7^3={PELj0kvlRF%j{rJF;d%#4oi~Bf^tK zecJDlKN%OZ$}qg)N0J_GR2#Hl>ubPh;|hPJsflm87aR%OjcC+sbW6y{)oNG?y3--t zh#Gjkk&l(cDt5V|#=@}yU3^@J_YB+JLaO6-A+u@feW1JH*}IKvW*aUR703t+K|30^ zd-X}PrqWbqd?mMU`#PQuTcZ&kp{9p@ssgdElQBG{a3yBO zTJ;r=YOo~XC7iaJaGbp6J}jeJ2Y1y7N~ClZylOXp`{S*))!@9JG@CHDVQA@%LMkeQ z4kfD#Us^atY5kgi#@X72Z!lyLB#u;a*ykx;)O!6cZoJ~<7$%M_X$0&o0`GK_E*``% zyBj?C%TyNcUMm>TnWGk7P05o}zNih2_q1`XIcRnJ!wLLQMJi}4pl}g?_l81UGii%v z(>C@ICSodd)h2MZIcaOOf(oyq1OXRL2fdU5g#%LQLEML z4Dd3*)m!$xJ!y^Mv`Y_R%*g_qg0<=NTjMU=$ia+M1~|$+=HO7p{sY58OsAe|!Uv5( z7~;5xl{1yc(z%L#9u4~N*~g7kVwoz_ssWz0y6rK%M!_2rgS@jP-e_T!s*joj;mP_z zJZl@YhCK*AN2CL!zAsWgg*tqTYPgcd2w(F>rLo@8yI+Lopj1yKr~UHc#Vu_l@^qgGM|UX*DUVPp6Y0+n zZ?Wun&Hl4j6HD&`g)4E*QgW;^q&l)poeL|#f{?)eK>$jj(h9?j{TVjh6maGF>g$16 zgRCaWO#a?Y)-Y63CG2At>z3|;SP7C#B(scKIF_lMgira3KO;I}Y$Ff?OFRR8j^I5k zJnUWz_{PQX9#}1&GKPpA9`{d-NvR?H8T3RlMk3zH(*BqrsJ&cm^E-!{`AEo~Ci75@ z04EHv*#$Z6A5BR_W)|e{3A;8(aGh(HL|9D~Q%#;G7!|1l(~!ngkzq995!cr)jTLMJ<7FZt;ns;{}^g=+|Xt}rHN zf1beaIsN1kGq@o3h=-d^Ht~l!Ka5KV6MCSV66|}Fc(!H#iDqY&SU=JHtimUBe&3tA zsRhR=T=^Z(%Epbb7i9ML2eK5*GOO%u>Y~9!QC1d={bZq3Rftqp+R%c|0Ta0f&JB}_ zKA#&VWgQ5BnX~A~G*&RNBl3Gn&o1(XjV|Y!hoKo`CEBa6@seyGW;+R?xWYi@)?z_Q z8xkBU?8Zj<qkn$z_HCmPu5PDfi(8Ixb?~JKe^&ER+)rC>o^^^#F2#|a?>NrxOcMxAvn zLf%X1wiAYYv=o9}AKD!fVwTf7mE~&O^eq=x8CIq|9~07v((1LnIpc~ zA}A^SGp^%LHb?79@(>(oIK{`QOtqyoMq~YYCNi7-^5X3;F8~<-iSQr%13nBny`=c0 zMS#+G6F6AhS{`<2R7#8Ws^%J34oV{Y){TMm}MqdZ}>%K2bxf_3+G_uZD44ou5yNczG$qF}pOM*td#4 zu`LIt>O$9D-ID$3?F1oFxf5MjD|a$8p|k!L^iqw21+?M{+Jv8~bOykR;7R1^C*pg~UTzTdKzwL0SsC7aI8rq}v*2NP>oCQ!2F{Gqx!{6j^$kWi*cH z?ek*xgDY0LE)YlZ5?z?HSXvPT;p56evE2etiVG}fQhO`pN62v`wUdGr5l=zvpC#7t z&B7YycTxwWJjtV8I!L$hdRE${R~W@tn6$7qwtSktX{YK5k_{Yq-LL{&8OxC`lvrry zemnh8bivR`N2*9o-K&bow3opv;BPM~6WXk}+)B-?#^Kk_*goG{hV?3*3Ft?cWr{QN zf%la2DiFx^w*8@?e{{6dc63;vW_3K@w33H8%7WaI0YImbW4N(D-<#ruffLRMwf9jI z)#52}EbGMn4Cp^Sp}Xz9OJC2+20xJk($P0{r1!h`YMgGbpOCW(EU`#kmkk4y8{;eR zko9>_gD&fQ8h_Q3yQ*|d|YXrxg zeQzG&hJtemLi$C|nbtKQXjEZAzW=ZoCP>2S zkWTk)z2H^|j>w)P40GTW53p)hIuER>S8F#Y>9kYX09g+3TyvE!X%(;EKra{PRoU!U z1R*i`E<(kuT%4Qnj7OSX6nC%wpy+4@*HyQ9y8%^ZHAyKGp(C~wBG>9D0ufXB1a?An zZM=5b^GU_fxgWQxgzQ<_OO4@rI5~L)9bYHeRjqhd?MR00XklK)cp6~!P$Vl27(jZk zR!?W&I-{B$+2g~;{P501Ow&~ii>=66aCrOf!@8^l%llsabW=2gay+39u2758xEBju z%|R{pk@G|Xm5ltY0z5*|^3nwsHyuM^hC{exPw*_B25z~-r|j6JW`RqE0hJEwrG<+% z&oJHZi$~NdD73tEc}5<|IaN&VZ3>k4thYco?xDUrXtjm+bS@4=>l{UHQ(MW1Qwi$f z3}Et%atvn9@FmYU&gi9LpL{m{TJM%z=FBnmFpIv^$ z_$%vtlrAB-6)Mz^6HjKHk9igS{$qWtlgM8;f5d6X=$v~LK)5^HyW(GEm`{-gRf2?E zy~6^7oV|C)XP$S#lpsCifTnH>2hPJ&7E0yhxARC|OKah*$c2dikygN^dweSt}qwpqxJ1nmVpUkaB!8r~8)Qh+^Q zw$jq(;XSTVH!3y@X6L=R+-uvg#7z~jLPYv!I9QA5oe3%nI%?y2m`;^Z^t5S;vf^#3 z9p-Dbp6_;Pkt1I-l;&M+;-y*I+t*>cAd(jXkn+Uvg@;+%W~>69%|(Y58V{kYEwkD! z?iDMwom&9sACSzrv9J!_H~O6F%I%@)l|&E#Oe9Nn<;raoFyN*@|JKc_H+hz}wfcg{ zj>gk};%$OmC~B&PHg~GId6aDrt;IHl2dzRA@F1ib>V6qoXH zRiMa;zAoatw?%$jDVR|k>-urNh`aIn(FpdmHz)IzD^f7ugX$YkJ&P#5mo>OSf#ebx zH@@$O&EKdO?cS=^D8&3ssF9GYH%T%~5XRz%XT);N!6{2eVcRNjL$GL_6Aq?$E$Via zqLyFX42GyqxsSgFj7J&K+EfBNq;0%ieTkQN!5yM7_uhAKrkEVn6!whV6J9ylvg*@m z%iKS05fZ?#Skc`x5G=Z{W>hoIy<;$2I#j*NAKGB+T~j&ktXB7Yf7r(ItYc4*uP%KAmV3fwghT1fDo_m zZ{pp)4HX``hG*j_#ml1k+rO1*^GEgyNefY!rZu}mzSRwg5Tqf!-^5=Zh1L;m#99X2 zHbn7fiX9lGic2l{4DuwM$WP$|bQ57@3^*WMZkBnNfBy0EtzU}W&6hJ_A+{UN#b+|i z&NlI1v$eb-h}@6)p{V6zzT4a3#OlUx>)fsVyZ$HDDV+^oPJa^>OJCIfBWspky?9r5 z`Qg}H#Pp7;{Z8d>ef=GNJPr^jL<+y@`=pSKl5IUUrWrewse(}1P#n_Uqcmn+Pe?Sa zW>96QW!`vlI@amhj8P0i)GXMc_*Ye>6PD%8a=zs{9cw2~DyNNywd`$BU>ClW@-x{546x$DU+Egpx@Tge%6*4*udax*&Y2&Vd#Uk6RKFg-lw6?h*!Z<*CNA;4 zvU0TpyjA0?1R(QZ=ACS;ObDd+u$&V@*>u!)^MMGtgX#5Pki;$V7!=ZuM-MDTP}Q_L zO<(m*8>Nh4-1TSmlKE2^*oFwWS6fLh`&B34h4RpNNvr8&P9;l-lDTF5uwn9gg4i4< z@gM9#>-qzo@qqxXIkq) zV>Cj3>GgQBHS>l3^5O+MJAQc)frBirsm83cHm(L298kTy?No|Go}JY$N-UjtV%FeJfjL=& z;Z;k=8V=TCP}NHk4Cd4%tQ7|0FMQ?sSAzi?saMTjRkN-Zdt-mWdQBOoPjgmdhl6jB zQYW)OIEANVS3h>ekuiz5T!)U9AKZ}R?HW#IxKoS2<7J44r@0OcNH}}5PC377 zzG~b?eeU$S1TP@ZuQAtWw^?cyG4T+-tAxD}4%uNmlgjOd6a1bJlX6jHxdoh`Bw_N* zoBs7&Gyy7Ag(6)ce_)&YMV6Cjn8`*iPxN4?uVy}LZG~kpJsGmyOR7xvuxh;Z1y}0u zzI!3rj5)43R_?N=DHX)pd18d7@I485de=jZDEk^84P3iJo*D2(FfL2iYm#A|Z02`s zW&UR>N+mrrr;ECEpk~N`0SAH6%V>YiiZ)Y%6}N25vj zc+OlWlD8n>0^W<5=+S?os}uO~Pg$We%lV#?pw7DsJm0(IOJc?fn45W4zAf(Qn`#B@ zO_O^m_RsS0>OntL6ElzE?@|RYgk0#np8bY|`pf!e=v8Tq`5bopB^yu=1$)kWl&Mbf1A|x?&}H&TUZ#wm*6K{noN@kO{^bCJ*F)EkF|IEc(Zt-VA|q_ zphQdy>pHep&I;o2zf|tF+ZxK0NR(F&lzo`A?(v5MH zoUlT-tmd8kF{JVO9t5)o&rC{H)KjKezcY|M19dvp)%hn6Z@C-O1V%=tp8V-)oxPW1 zT|;Htp7B{aST@b$#tI4m%5$MSAjA^=NZJi!SN3Oax2g~hrE|+VgL2U;-50YpJE7~( zNMoLe5hrPMJ&Rh=E6&*BpmY}(u|@fNHkCP^QYiS>2hVk)$o=-2_<@b*rNCt-si^<0`9YCE zVdSO8^YBA1Ccm`6i?Q!4o$1APlRO|<1dMH5%rJ>#z>r2&3emepdI{7qdK=sl%pcx1 z^0$SxBu&7WR#JK`>d!h(E`c=fBI+)sRhYau@lJ?%{pE#sobsAC1}*I}%`penI2V0Z z+T4r>D{G#M&?;+gKH$1Yc}l`jgJRF~4(}fFau3kXF@=5B%hN}*+yXdIMmaaR^2TmQCs@&h>MB)T+35NS z_V))Vd_}s}MS3}8Fxa0QhX8Qu(i1QxfXjsGVsUst#%Lt@l!%4SFRn`I#t2nIP8cIt1vz1iVD-aZxA1PhTP6)AMa`xZaMaGpabD~c zjk1>?P$$KB@d@=1CZbFd;+;=VOQILyJ<_RTF92qUvTx$Aq2vjzX!_$%g*zExLDV7% z*47ljbHR7HTv%FrAslllx$MR~a+6le`QuC)Y^@H4DpQs3+tzt1>09vQ1I0p9<1mg% zcV1}OjLeG&vpLJ68c);=Ey2j&)m)EQOL_481NW<%_&;OMs_FhC_N|)jPq=q;5=Txo zRjTujR@m3_yIVK2E0Agsr-tr5D^&NKGg!79fyym!7IbYWMJnDhMJtD;sWv|AIi*h( zHs!pom=W(sox#~s`GG$<>-3Dh%x}9%V)P=hm2tOfu z4ed_l|M2IF66XUa905$cX~HSW>%TDTCA+&?R~Dr)rgkR`Aon5FMgTNjvWyFU~TdD#s#d&FmN+q50!Q*UD`uu0I^|aVMJv_u%?S(?n zf!1OF2{m%5GG@F?FVe8j6=ewq=a!bE<`r00Ex0>`1Y%p5UPD zuy8b4?Hh;1=a`oo=997JzRx$9Y*%2Cc&W1;yLneoQ90_!LyGtfZyZ+WWwPyIC;E4hMCy zQKOM`3#7k#UKMpC`?DnC|(%derH3>O9 z@zkxVZrO<>+9<}{*=Ny;u2OLYX24QA#1)!l;>zES@+mAMS(Dc>Vj)C6A0(w2-V#tn zfpymT+S|ekdp}2+jI4 zyM&*yohLeN8D=Z)i&P=@w&v6B9d5T z>Foe37*dTd>)Vfq2Pjqc6-XONeQO_o^*5tn3pt*x2rGlQeXS68z3FJYAbFu zlcqTD%yP_``{#68tFiSHhQs{|oXwvdtk@4)?N?M3-aa@crQ!%nq%)e*0Sn1wA18il z5jiDG7As^k>;VZI;rdgu-Pb~?G@Sqagu1IZRqVq{|GY9T9VUOZS6e7VtG%dR>;N{Z zH+@qb&3B)r>axdWTfN{}$ugQF4bxVdfHz14E@JlWE%9~!F=p2y?CmBLBm0EYW8b6O zL*I?QK2FViGWMa9C0qx$brf{|giG>j;TSU6>^~+C@%HH|e%!`8Y*x>0W(3`5^@!rZ zX!9i&iD_<-jXp~uSFIFg5HPnQV4Zb{`aDiHcXT1dI$ycuHj1`4lgB4vbF>eXh{P=L zj-V@}owjrx2tkM(AmqD(b*M>?7r1A8ZgNdRAXnR-e_t;plTMRlZAWqP7;k8U3B@Fr z$4^Uhqm^5Ip=Q(0RH`ln)q6xt4tvx|Mkc_o4kc~+^7U`8XQNKr@cGkNg}z@~iRw-V z#0UsMCOb>-U^@xX2s18v3v)!Xdqdi=#E>K)ihG8>Qu|a9(cY$;Tdxt$S?Ixz>SwrE znM6$C)wMsf6NzF|_njN_R@abfD64M1Lp%lVI-T%2dqHx{X1*jb<2brXjs|z;- z(tD&rtEmHBec5>kL|4@7c#SMl&eajeJH3)PCZWEokzEb3k-c21l1A7!WcImaoU7JV zee4j3@|&BQSFP(Pa`vTfp1#bl$2tLMZNenrr?(WytL*?CYyHJOU`?$zQGiZT{FS*!%<6F+_n0<@a_oR%`?FlNH zol(`^H!e%^zGeUBxkw$+A+0N`RCJl@!-cD*3azW@=Ck9AX9>jnVaNsb+S1au+tD8S zmB-c*^g7`2qhkDqR_WPQC}C%|qSY!?m@}JXBHb-iZ@?;Lcaj^(UB^8{eDXkdJC}1r zbFCUA8yq&-at~()`28mS`iSEqUPc?Shy6By+xhwsQ~9&eYKM#Y;!`a|-~BLO2@8&$ zT|dm%pFupbZ+k96;;N^Fj8k)UrDbGO{_~HQZ=GlK-F!I{55P-!n3GS-abZVNm`YhtTGmvK6NS* zU`7P#z~~?DY9fg!J63Yz;2lqLpOAn8!hTYYr}mk-yYx7u#zn3dDc|f|ZfRWd9z;Wg z8U(4W-()CS%s0#ApuVWCp&j+ zBK#OFw(1y~+1N6(Kh=c1m}-4ckM9R^2SsYW*ypm;g`F0hY%Vw%!n%YUVay8>4()-YWKWa5I?3l7mlV=gA z#>`acujfG5bXTT*Eut-(%`&KAe0-*1dHTPj6As>5^gM&;vJQdqQvgYx54W_&VxlbgbXvo$7;pz|@J_ct+w=@yau?d)RsgVMB z(o5D-JhMoL@`Opxjae38@ywXnyfDFF^s}{iiQb`Mtxj9fGVFZ0qBwrOb{EFblWEGp z(9`a+82a*5aSVO!E{kFAz1fg#97A8bQVg9@HW=XqW$#6<=(yfLOl!W)4UQQall*qb z!(qxAv!JJO7TmQJj8o+#!iQz)6xg%TkD@&5&**Y0_JA5fdNz1v<5_qfe8Ue=HO zX<2asK~vXi4=$=D$b6j1Y~YNIfg0^5Z=S zP}o@;3W^Rsai1(+Ks2emoMM@4YILj0a}1KOUn1MzsMVBrv_fr1jomHlS9T7vrg8}L zj(R4b*~BI4M*>A?WV~G?rluC)tf9xSEIfl$aYL}4`OFl)5p`(0I_@ArtTyqJp9Q?U z`RrD0FI7}zePt_lkQlOD4lagHxh#7=Y{CShZH=Iid4n!_>rF+E=$NvnzEhF z{yfvVMqlA`0&Pbg|D^B)FG&4cyaJ*=pgFE7UCnclk*jz-xa=)?iewp7bXXSy%lh~(}7E_+L^bEchrFM!)S8)n1QE+ z2v*3HLUR`#Mc`u&1CLIA7CI385}|4|sW@mB)u_{BrE%br=^$DIUeq*SvyG3gPT(24 zRe~+vohnT)7smyRlml6Yf$>z@!zCu#93E~G5rzOG1VTL~TQge_?wM?svW8pmBXd>s z&0w={JAw2iy6P0nw};XxJj-)+*&ISWO3YKe^#0`60`xBOx^O|x`Qe;va?gGrgXgxs zjQUh0i*P^e_Q`|Dl!mzd$N5K@D&n@%MOeU)cC@2`w7Ro2Y|`dFj-*~$z`ZR|S6=)y zlY96_CR?75BH767#fA(*4b75OhvSfveUz?icGYhF_Q%^lYz~e=E-_UB(nIr^aSU*c zsfr~%<(?VK01p`h%MJxG_+6}u{0|618G?AlpUk1x4~Q{QDNN;Lej3PV{c-*Jr^uL{i>iPl$dkQGXr?8 zxk@do;=2$SSa?tC*R*5UA_qcZQj(-d?j8pZIOl?6tB5kJ$@}=D4C!75h?E?9<8Po-a>M$ylGO{~S>x1OIoZn7lL4`07;1qAnoaece z8){r@o}dh-xXD5>$-wIqekLlT(~~Tnq|^Co``2n0(=$H;qvOruN#uab>jfet*hOT>6U1z4ffF z2!S5PH^~Fil)z-k1tgP|#VJY4C8hSgMs^dDkky)F_7yuo2>NCw5Q6PT=F0~{g1(MS zTFjnP=qJQ3$=@Ip`G~$GTx`THDi;W^>YRA<&CV{XgL>q`F2nkmfsjFca-oSqear`Y z@A{q+XHaC{=kdiT8TWGj2mXPD&e*fX-0Ma2uLXP}sfr-^q6lEK!I_|u{HH2CIfBZ3|(UyH>*O-G|5 zG9lp>mR_#HA16C}RTxX!11kEKmF68NaW^XqnKz0#lw9Ud94aUNFFcreZd`V-+<|l1 z!Ez^6*2AKVM)I`D@htDtyE=QF@@y;})tImvfEv_C!4qp^!^0 zUap(0J0s;dzNdcrX2A%(!bNNXV5<8kLyrAvg_+4^UC%|LSZTUx3ZYu%INVC^%tieF zbx8J9=vQXBgDdi3fl75TN-ic3^VNoKmLc~-FO9rOf-2!(dK`O)D$Pga3nw)M{e|(! zOffP%^f^b)_WGGeKBpSwS>m!`s;NMy3{*+|Ibon`s?P}nRa1MA&X?+)pb&*pc%TH_ ziQM_eWwQ6lb^B-m>F#|%kpV!z|u1{Va#7sd7H+d8Q8@ zHgBtTl9BO;p2lAZ@h_zoBiD{J>5ZlV9Fp8mfo1Dl2HRu)vJkusn#ZJ7g!X=Ozdr0f ziAwjk)pDUZYpT(Eb9XBLhd*EZ@}k@s#R*I}vt$l|<#6n^gj7wPJ7JNzU#;W2!+ouV zRb70VZ)f{0YLf11t+eWR*P z#~xBwlv$lqp>k1H&btH>*wHH}G4gZ|M8{W5OL;w+*(-7h7qooIlTU@Vd4#WOquunX zwH7C~2M4Nen@jFcz?0hinQY6Ng_P0LG}DQ4;$?cxhn2A)o(jnDeyMUD(ytL+VHCVv zQ$=AnJZ#(EAHFr!wJExqW)OP#o_gtG;;r*ovK zgVA1?h+6S|87@!%CYQa4wD4dQyDm=62YB)bUCt*z0@bGI>mnA@@r+xll*$Iv z!~XhlzKFZ=`q3-eWOMR+&XfkBMtCsjw2^|T?0Z>*n^&)2m%zC3eUCTf7#~s_S}{QB zDP!|)$+H|e;+HM~H4;?3Ns?iL>J4s5Vo5UTZ!C>p3!xLX=iujMjbIo*uhs|~C>gX` zhj@+yGU%udxK9MsYF3NJf>AKj(~4l^*Rovv!bFVn8_W9kgnEf3;UzR25q7KWtZiu!w*zCB$gH`z(zad)!nl zE>QUe9?g;YXe%9ZHVAJK8IRnAPE|){Z-7?Ngj(-eoV3rs4)MX;Y_-D`eDSFTrEh^- ze=Yj&0a9U45eJX+?P?cbDZ&LX`udnlX6TtsvOKKk+d3%!=^;jpmTwlxX8$pHh__Ey z@#8k$;WANXFyN_2zr-T<+6`oDW-OGh%0=nuL*lUBuO1PGfuWrco%*W>aPU=foTRe% z`tbNj+b2_Jf=wFZWOGN>9q{Ls_skwA`)2a^B;GLGYlv3#KqYQ>U>Z+DT)l&*NlshR zZ_*8L(rbB!n_QC|ocZO}WWAJIZ<-{$&Tf8}P9Eb8L4rzDrdS(IOO$JBJMB!RVomUi z%viwWuzx)4k>dBO?=~`h`TDolvr(tb!s{tV|!N}MPe@oCK zO`+f$I!i{Jwhl2!0}I@G=h(#BSXQd#icUBg9#$JzhgS>#HQqlnJ*?FR5Y*X-Qz@?L zEIT4}7>OTjv3-dljUU)YOheJHRBK8H^6L0#BUOBVtND^do?kJ7;W}+pA~n>z5M-y*6;3K4H>$c}QZSJ|69doXJgGVE3Bsy_A! zY}ufM^jEFxDDp$024zsL>jA16G;YYYpkxaCgETDc<7w$;}2=xHYT8vE;DpvlfClcFo|0FFDM6Yf?BB}l636zkC;alFo^}zhW;nx;lHWg7ug&nfWO1*B z14pnTYHMC9m(U55DaGXJ0r!dRYEf`F%JYH8S=Q1tJ-?G}iFhX`X{5DH)7QDT4%%g> zR~bYw9Br~v>)s6{mhY-AzLyOaE;#Zsra_`?=i$kGhjRJyeiMIv6j#z{BLq!=?d^8H zKEzZAXO!M*Yr$8K5Aazkx$}IOuRnvxRAHy=RxPXwN;>*&@~-^Sc}C1??YjBuZoZre z&mZY|l?Na`lZVM{6aO_^$D5D)PwtkB`EGCj8Y@G-)vsuk>}Gf5x?p~-*IpyBQTckv zc5WbTSWnYfKr{+;{{m3-la%w>-{2n?h9xx&gV+m&h=u_WF|hK#6K|{_G(4>EC%cjP zGiMgJsRwAL?3JVl^TQ0u^2Ko|w8zJaBOqr_Ko4lxD$$oeVHZcw?Ymmoo4lLTD>K-| zQ$x$#ha4J}ZkXz&A#X{#6JsUMjHZe=JdH|JziiAgHZ_h#aYEg?)l#;k$HvT79I<#% z9U0DQ9XEe0=H{nVM*D@^<|!RCjD1pNW(w*&jX$2&TAlo+|h z&$-ddQ1_ZVTdBYulNk`oblKZ;OM$KCtg8EkyJ5A{v1s=Mq_a6T)lBtaz)Ch}6vp1{ z&s0z8sFO|Z|I&MP)}g5_F>a{MT2?r;*ruEE;CXAxUfLya zU4zPZTc%x&dtTha=304Gv)Knu1uROuQ>D0dabi8iNqF|T9>2`#eYe)*%?GB`;+>5M zR>XL6D_Q_5HmYzc_f#h<+9{LuD@v)p62F1oyIBY49_cGQDK^`3%Ag23RvkL+bku<8gtU8U3cApAd)_Lj1^r=R$Z&98;zujpH>yL@>C=h{@xDunF)M5*-29wPB6P_Bvhh6KwJmpZv!zPFT z{mi>kl-$4x!&p;7PC2@ZY^ND^Gx@tWMdA@>>5oh{P|hHp-fwx%fU$(xY5gJ@6hZNw zEHj1Xy9#3&w%*H*#xoBeo$%O}gV~_0%F?09;U@O;p(G1pSdX$i2N*~lodP+CP%=Go z5LTW9Yo{e11{0G^fBE{wo6N+r`oGO`9&_)PP>%Lud9fsk)|`npv40wRrd`eC`j@_c zx;MaS2$}XX9|q^3kj+UP%tJq?xq0-KH~A&3)lpO`L&}$zk)!2ncNxSyc^nPIJnb%m zm@n@mN6gpmB8Zu<_ihgJwR0in46DS9PtdZ0j4!vj!Lg5xt^Djbmz#1TNOn-TB~RsKSQDL+F*1;CMq5)E|OHY$n=ONU<74%4VXW>Kr#TUA)M zRLXfzZW49!Hc;p>IPA}$`S@>5K_EW-S~LXKia(jD3##Jz;aC24L7pfU|Gug~XJc!R z!#=r=<7K?e97BSVzmv*LJ*oWm8a`FzJix-x#4n}61q>hdr(OngfGXfzFbW=GwsFO3 z%A;JChC#ZdTOpS+wVw52f2u*P0LqU_U;nUks{{faB2}J50>EYW3PuL@rwu@skSxUe z!N~h%7p{!f5^}aid6$M`U}dvA29`(`vPMuAvX_-54zZGq0SIGT)*%nZD?Jr3WKWt}gh66|9z}+;V;VIrNnEU0rpcSKmp`UjRMG=;x}w1(nj|5E1qgSe z$ulnn@q6dhn~w}w@)5KHbg}K zKh8hO>=(Bo_e9ZE8hWbsZFOg|f?w^ndiuP){AeZ!KtvEBPt1{QWHNRpAw^kbJC_0n zC9^1F-t4N~{Oymof7l$tl$6n8SW&Yo9C|T44@Pd^gsM2vo7{PDa(gBiICVg98==|K zaRSQ_juRu2V5I~O9F&SR@tcAjNJZ<9^N0C*xcZDl90-CU=o7ca>;Jq z+maGGaPhz>La9WIdBA^S8hC*DMhYKV)&(dcl&x>6lE{Hw@48Afb2B#WU8_g`~^65V9cCHqTJnTTx-}~22Ea|(tQVz0c9B|7jqPQE;PP#Cu6AKjj5qP0 za9J|VV-`r?0Ln4N=6@{xJ+U-fnE$agL_ZT7PPWz($aa`95M1HXo#d%x(TV8jVdLvR z?QlZ3XDOWTK=?Xv%p_42I%j=OBy$GlG%BkzO&-W{x7qT&<)5G$ zK$5y5%D^*6Y*tq!f(xM|r?0S4??;;dH5E8ML>Ju#O1%rC$|OqPRcTE;v~dkrjR0&c z@627J9X~lmanBq%y?KgT54De+zQV>!1&+_<)<0-VYu3{;*(MGg3uNh@3;UkjThGR@ zj`Xm(Ngh`7HEe3H_&%}pmlie3$$E`+mL#=U2Q|AwE6gmcoh308%*_HGuKX$;l%SNo zM5e8|H+z(=gD1xgns<@XUqoEx_{u^ryGZmk%mqSuo0?+H*EAO_WCE5e7?oyB9EKgVTVJjtiPEscSC9jgP0GH>`9hx;0c>l1-v9DK?D7|7gtVb>G(Sk+3TR&Pxla7k^uACG z5#pJx8^gnS{xL4rlsMVdrF;l^8Lj9{co!DD|`K|9P>@p$0m?^h*C=CqM4Hvb}HS9O48OsJ(& zCzWkwB@HP+@m*ioPX?v$ex;x?VWo>rNQ6S>l;)wZ8W?O;tK<}^NcXQpvZpe}G6@nK z8V?JUI*U=xFnO4-HguZ_xs=!t^5%1>gstmD^Nw(_3>%7erwyOo-(~2PA;2#)-)tkE zXTUS43m*EFK@UQ77IYub)^`Mj@CK3%ZZs%NV1n0P$k87@d@SPm=g}Z zoRp$M?ey9kXtQ|U}Z)>!Mxw!GGR%@elC?%9o2ar zsIEE3s%#mUmcuo|yzKb}LPt!H%8ROdPek5{mR~bl;!ADcI42Z{wqkz2M+^-M2PohfOZBS+%XMLE^ic7f0 zI$;P00e_7dbf5K--5nCRv0`ZW^-dTg?on6z?r`t2Mp*l-?qR}+=MU97g%wIuh#}0N z@)*f6h$Y7iByBkUo`wNNTXGaH$pw%wsxE;X-_y%KxTiwMD>KU4%;{8=Rw^LH^GSOT z1vL^UmzEbPy+j_rT*xv1^k=eleBEUwIeob5Yzy%+y`sA7dcR^X*6}h`9zD$)(G_6g z#gNJ|7G{R8vKGr)HnKOlj{kdzH;dTaX1){xm&S0`seIL#FI(7Jb3iI>NIn#C&6w+T zM$3X&PuD^$UM7w$bETq;nV_|NUhNx)#pif$`D8szvQg>dWJ|9t@lv8jZ>e@p5>!IT zZ8GplUByhe$YDY|kq#s>vaq;zG%(-@U!lon{ZuQ>*Oq}V%j=f4bC&viq zCM}XSml(J(N%~&a-%W0vE3QnIP)q#;Zo%{B%Kv@7*`TB~9nhA}Dw~p>E1K*1ZZ|%x z*S1paubhRuUg4$wZncS*B~?XVHMa}eaE>av`26&^Pn>l@)9*e>+EQW!YX#=Fh!Hf& z#E7Sj^zY86Ell|dK{5~_(Hdsdjb)dX#?WXm`AA|4Z7Z;z1s>YLh3fx%kHj#ngDU}NA zq2&}#FO-+qE{nWD%LLsWX&5X;$6u+h)|%tua~HDv0q^+YOt6P(2eEi7zN0&G49r}oT6K< zx#Xekl{zH``H8v+Mc>4vZ<1t~;FYyNVoQc7Ya4k3Ux;(RjS}ccia=eBpG7fF`w&6x z;yJ`LF^h`|ZYJt&R(tre!#lkg)|AqT`7ZrJJ~+WJx${6>Px)TUiO8>PhnMQ!R=I1qjXXz zw-a*zoK9;sMd~l{w(#gwz!pCGuVz-21rxBOizot!pXfjb6WTtth+J|H95#zR?l{(F z*lpLJlI^}0LW$x0?s>xY14ll;)Ct$Y6qrWe4;adfh$Zc z`tJezX;03jkMr$nmuy@T4+?Yi^)Z(VsEBE@Jgn#2x~NVUL!q!>m~8eRlZSZwbQM2t z;~n%n$EAlS(fSe#J?;kbB~$Oii~a=xa_T6>DU|8p<0O?o*N4YPV%O}PEW757lg(Xv z)4Q@AD!%H?ukew~xI$yb(iYZ+E*)iUQKhd{eNt69=E9u4er>U(&X>p0BVVrQht^ zOx@M7|KC$iEp>HMUv>^6IEtWT{3VX$80Wi%)asiW&DIE;&BwGaL7=yP3npWg6&5N3hvcrBeF3saE-u&liME8Yyt*iH_crCXHw zq^kS|b$#i1@Jtuj-4?oOyoCj|I3HXkl+d<|~=2KMgs~P>Ne>eSLv)|+O zJ?TnxV}b@%L{x26F(+N1?Ds8?pV|_x0QP`Vdnx>rtxe z*UD7B5AX^X@5}|_eweR6gE*8E+i{-|HzOqvtY$7(qP&y?vVu;9!SCkFnQ%}yo`%J* zRB3CriT|3d?alN=6zm(XhOEVrhiw5G7 z907&pc7WE|p;!<0r=*jsb9Pd)4(w0e*Hxgts4iFP9)4${38YAfi(Coy3Ye#zjv5f1 zE>ho~&B+)dB#P2oHN7zV;Hxe}N%pBmuv_H54%lDh+95O^d7>l^`EMn(> z_3cx^AU6@5r_=wJKND=60lCcd1Al5V663BMpn+o<%Eo0!EtWEhG;7Mc-OO9fx;uuWl%ODM?HV-RKmz)bD5DvoGV<`hila=hu_3ewNEe-Ol z_3f=FFkN1sPLc$nfis~5H&pox4W?gUvdf;OzC9;|r9-j4eMyH(_3cYw9aG=F3}m3q zDbuJeBsoug`w~2lt8ZTd)KcG`dK_2ZKI?h0`u4>EN*x)PFw_SjO;00PcxxgjyT;eL z(l^3E1x!@7iXN-4Ylc*ta(L!Rlw1e?MJO*Y8N{v@Di4h z=$FYnwrAO&r>$bXta}CWn<1N};vzIf>21>txH71UBgYTNY+Zq!^Ms(gTX=nYoDQya zb^+FsmMtdxvs4(_0Bher28sQ76wtF{8dl$)Xc|&-UN~lCItH67`?I{hedu5T!rf?M z@S~=F`Md%}xHDyu;=B9bN6!T|!fOMc9szrVO z$G8@op>z6v9Y6G3j;wD_QsCJ7_UQXP)wd^f&Qag~2srd&Xx}$gF>?DRRE0!ua_7Ox z?U`WU&4WaI$#h!B9lITUr<32*# zmIGNni{rse>921uIVU$iqt``Ib}YWcr%<0B@%zcjNWf98e<;(~hPRR2E~h9&sZwi8 z!19UxpQpaP z(z46thGBb=B$&&$)v00>7R7iI{|T2R(>y{;I|opX=}7-$>2F!zUJ5YH(rjV=$JScaiDB^)yJt&-(CtEIaje9Ka!TBS&~uDTw8k>vlOYpceregj_mfc(UoWLyJUTH z;!Sfb^>U(DURQc0&P8+WW{2S71m$NP<+B|-l@CZ#_uJLC&re@rAjeo{o z2`-M8>kI7k)1Uv0?pl(T*77BRw$C{m$CgH;ku)03m5io&_3g0`LZe3MYohh-L#;yf z?St(C_3c$VC`oea+lQJb>)VGqBgPyy+M&pWewB9)sV>7~ahg83S2Ng`c}uiazc1X>O$8BFBK{WM&Bg z%qg{LP|}A+C?n6xDP_sWMz!K38U?ikQTqBXWQ3}L?KmbH1TA>h$0lg!`6{*t4(Yv7 zl+0!$1zrXgKjl5NG57pGSPXP~4K;CU|=5IKNxLW$0Yg?=lu0I(*<7AzN zq^6hApKxoO!s0K+38EFcz-_d)xx1p6Y1$}DjKTKTsBbSem!{>fJq_d8(7nY%=*8i! zY{Vw0^PlB1!SjsIPNmdHbo+S|*30k4nYn2u@K z-@MOio(*Ksbz>@=nJZLGda7)_3gz4B?w~)PacL(cn_JI!;<%UH24EpwYMCVz64E zw8gS}DhfP!Wgf(`iSZM?(t{`J+jrb3Yd5D;m0RgJ{=`qldnl_B-)x3M%Ci@*Z{Ojc zV)gAiM;Z0)J64IpjQaL&b16JRu~SL4C2>#Ix9`-~x2GnmFg4!Kuo6~FzjRR2k?nM% znp~u6GPTO8Z%++d)VD`B6edyZxVqf@vtqP?pQH8dJC+SH(2rcTGV9w5NVWCtMKeez zsrvS!5tl+jk-jGN?K`#JL~8FutJrjsiGO5w)y8bnD)p$1RLfu!hkvi@AFXfSF}dRE zcnP&k)VJ?=>6R)i;v`YuzGIReh51XezI{if_X!XuufBaJUEdx*C+pkG-&35lzP^1Y zqrN@br0Uyu5F`W65UX!bKl>5FZVZjwmVtJm`t~7sS@rEh9i0H@%H{z^`h5_5{CF{p zY9h7+IkDa<;8cD4PPD!~ehJmGOx(9w_3b-OtEf|~oLwjiU;h-XZ{O*iRN|*quV8)q z4!BFb+k^sPr&Ov?+wiGqefv(b@R#{DSUrw^uBmU&ZK9>lI`R7UotOY2zOSioFME^s zqq2r)ZOZp zLiUa7+w&0O0Y4I@!NVmQJ7;zE?K|;JRA1j7ogtH47vyfWrTX>&8Ln@SAJX;hRf87w z?RD39eS6g;QQuxSsjF|V8X7zmroKJ3&!}(TiPpF8 z0KGuEh{|Npj4t%h&4r&b>f6&mP3qfs67}snwe{^g_4VyL@V1RjDYL$PC#$}FN6HD- z<58yStFlDdG+d9eql#WOuW#R}$q*xXCR)|hw+Eoi`u3fyvh-C}5g^KXx|+;UQoJg;!HDw9~e}Jvt`q+vE4uNjZNEmLsJfNsSw;Z{NwNZ{La6 zx9^1N+jl<3>)UtI_3b-O_4-h0RJTP~O3JQp-$~WC?ai zr0}^3HqdSikzenI*xTk&9TV&@RBnBH;ElGSH$m{Z62!|$$Bp|qo<@?Z03*c$jT>%o z;A*q*D;yBhudpC=-6eMUO0Xfd8Gcg6mH=#B!#?#}umXEWztx-8x9?zYJ`~Z~?DX>w zgp}dh4Irg|OFR^>7V-M_9i6Qq09>UgNWhNNx9=qC+vB%jeS7(Rn7X!mLq(>+k2N$D zcG0@}_8q%fZGC&$`l>9aRocZ3u}#`mjkfY6Uf0&Q?x0d|EyXCjnijZplhraNA&gdyF2aZ{G>ynN&`qJ_LFBK7SF1}$ZzzCHb{xN4Zu-=yo?cf$4U z#n%ytb@lB#Sb_PtEEjLrv(XBYdZfO6rCs#Y<=40GG_G&oiPpErFE#b;JN5PLJF!H0 zatFlf+jqW(>f4KN6ZP%6fnVRg6RdCF3DviMWn~Q47wb}2ayYY?=%_2Zyx7GcN^F{rOIqnnieaw`dY@vMgfqo zkGZGE`VYE#hqebCzNqRz<3(cX5f~Z3IX-Pr&Vkzor7$e(2Le!_zX&dZDHc zzn0|lEA2I4cCO#Aep=(SD|?*CcOz4`L^A+P;3m+m~U0R4|d z?50U>8XE{+|2?}Xq|i-*vy$Y`1mfpKr-kTcwk`bkBJ<+uNYedX_aC^LZ4qwe}W5owNrRMKuks-=4hw z`(OVasyw6W9ymfa%1YQEqSaX~na1hRX3Vhbqn?NTs%Sb^rNk~>xekzB%rG$OF6W4> zi%xQd{mijC>JH~vDNDSUIR-}E;T*~9ZvX2T7`5#jqesbjBe<+8Qr)&&SMN9*N+nj& z;dR*vs&~S$_ zVIg8?1Q?{7iov;9mm!ouO+)I@l;SgFNaCza0mhAEg zy>a6$IX@Fx=Bn<*8&bz31_PoMOdj2l_bdcl;raKPnH`TUgR5Qn?l+rmAbi@LuZn8? z9k=f9Hn-Z%``b-e-6UEo;aoL#s=D12@_v2%bR+9{S^L1cQx3QcZ>OGo-n@4>eC^~( z9(;=0_BoV!I^6QfmRvi?9F(t)rIf7}VQ)mer$RACMCqCax8YlrRMe81lwp~~zfhI< zP=$F%0!z?l=ObrKIk_6KNpn7TC#m~CE>J7J#k_YoeC_0)?mS0tAH5@<4!3-=CD-mL zcukdhPlaNLh`se_IvE$knaJt#@h+%e6p9n!xvwA1fv!2}=ByXr84@st_@GM2LwR2vXEFTi=|a2#}A{zcUao&0My9u{`GD+_1qV;%at z9J&3ph3c^3ti6KDt!KWS!8e^eu?w--=1AB#ki*D4F(tiYqf0I(zRAG5o^(aT-^NbQ zn|6BW+KE#d(TXnh*2=Q!Eup?Bp-NE;W->hrl;fIN>zY)Iqk9{W92$@>A5JYTwqKsz zny*aIwv+nLk%!N2hYSf`;Sqlz-#FfUJ+KK={-|fyGIG{CD6($_atLKR^&M|tyu|RG zU~U!D1AgiCyPuFw(n1;Y$~i`dT{|fm!(ih?USDfG>!Y>7e)Wlfp-7^0U29uU`O8l& zZA73=B_ce_#jm~vf9Z*&x8ScmwWJ{cJJ2=T$uGFhW{3&)D@^c{%Dzp`aMC&&;&-Z9 zT~=oU#bS5XN0;;cdf2B;QNQGZ7>AnR6^=Ri=CxmKoBfLT*KV|5a#Bfl_BFqdsl`S_ zue?&Gm2P>3MyuVH?aPK%fC*U5OMq%X`q-L;x*?7mXyzqgHV`QTu$LM;_*w}S^L%|= z71$${J>xK|RX~GajfN{(?K3=1cIUu+?7mXMKr)j`nr}nV><)UFj3{l@r76bA(W;n6 zN|tKGQbkLHWJ`AlA`mZm8XFX``yCremP;X?T{whJndZNmR}- zl3kh9AQPxL8b&7Au!>B$GN&FdQhU?&TflMWr5f_$Y+h1Y&l!2V_W>~vj)Ud0YhoWz-A1eWd<~Oh$+~Gw< z^pW~=U2xPZmgNA578P|`1u8wwSJ0KL-m_9 zs)t(X9IA-wHwxB7tu%^PMfIB^)It>L4DG{al~H}rTE_6MKJlmHx>Hvj72CCcdGPTo z6~8qPqWWGL7iB#VKYCU>BxiJ0nvNz&+qKXdjOCX@V(gZM897i}RxcU0L8Zp3{bOE5 zSluI76W07%%@eE^Lr_r8`uaNT{l;#;~SdY!HFkJ^>tx<#Kpm_*G=X;A3qA zU?Iq$!N;zn?T)NgZFSYE+0hI*hD#4uYHWsrE0cn5T19P{k`i8X#e6m z0h?c<#aT@gr2-1PCbfFV`K|g;lb-xeRN_Co;YN`5buU;yDe{^&@I5|7IyzG6jB$p1n z6orLbn2EcmaC97f8!iT`#c;A(c29*vrsJf^DXo^PakqQ?e{WFqrJSx;1+RHP$@X4@jYt7RMfc%BOO<;L~DO{<+2_fU$a(t=!Lx+P8L5W%L27~my_kHn2jE9 zish=>iyV7GvY+b!WvvR08%!~WGwdAW3tLV%cm_or`*sG4%UM=uga3vLtKK5HX#^9r zSDMzaGZwyIIq$MC&q$VShE3zwEKmT%P@|2~^ z%i8PGoCwdin2=&IgrO+vtyC&oR=5wFX!+1xy&nrvP&)E(kwY4Uh(Aos_ebL8-8j{~Ot<@%=+SXHtPyYzR5{yC<9y25Ug7@*?u?hsSKm#rFtuX*7J>~$jsek*XNe`;{Q z&GFTe6!P2F4i!im7qCEBN2KXo0t4)FKHE=((~hz*1YxT$j$qOK1`nCZsJh#7_k(R2 z{88|Mxv@^rHB9iqw_|+KI&^q$U(r9u^pCdzvj*H?5re~z$Cy)Kvt;bXV~3K*bfjML zlwvURaX$_nD1U@q?YWG>>$h2oI9UtbXaV$=(hHC^#s&*g84(Vd_r*=w|2~;_5$shg zDlRi*>-us&c>i*6DYnUv;cQfl;Y3Du|6__ZU3U2&&rIc>sKNWI-f{2cRqv=bcz+&; z1gl6lkSL7!N-hY2=^e$;~G|K}?DgsTa%-;N4@lY&=Q%l-su^_0M z+I2ZOA|>26)J|ogpow1uvB4HX4Rur3w;~J$OixC?4OK9`!Q}z(ZJObj9cX083{z~w z9d^!Igz0_B_awP+)6J&-79wf`jo|ZDhGBmR9T+&aNI`m2z|#Q2u+)v6mD6#tAQJ#{ z9?@9jDka~aTVerkUR<1t#Ox6hyCr1MfWKblg!ghQeSwSjzk)`)kQ^eY<5a%FS#-pc1HJS zIO&_8CF%K>-COJCvdPg|J2*Nkytn%#u}ACX=!V*OC(xQ@s@;M|tkIuv7g$(q zYZu6OrDEyU+FKv_AXtMx5eX7r1UL%#b))R&PjR#fXO%pgx1zJGzvzsD9t~oFa&4zi zv=+|u*-~xM$ZR+jzmqO0TLtv|ed#QYv@7Z3zn!k1-=24O^vKF3Er~lP zH~p~G_l&lH!qd7J4a<0Dc$y3r7Gl=Nr#?ecTldpGU0m zu4Y$XaBycMs}i>nOUlm2jfOSue&kpHye$|V+7AOu25e}Hu8kU3(vCpXsv zQih7&uBvjETjJyRNM{(A>T| zJyo07Ia?X|p8dR9o9=#vnL!iw-{k1|za=@gl%IRJWe`+o_`i4g`lj7o-$U(LTU*QZ z({8u_8R+uUb~+B*)=MRJ(f_y5_KD8qe+_we`_9hYy~@65RJzv7$olvclBd5F6s~)> z;kDojgzK+D(_ev}d$)^PYaaH;-OmlL$KIbEFEn${M|aP2-=94%H23}4^sLeC7#H^0 zI}e2&nRVC`s}7*0vcDP=9lU2xU?H$jvOezeBB@|Ec>g@92E3jT*)qa`%tqVY`t8M- zt&bQVs(?fC?&f!;%iQecI8-Xo>~3b)r(V&T-3{fHcG>Ab?v=aSp&VbCoet$*raK+V zy*alx6s33`A5D=!gOWTM-t@;2@<@CcyyrXuQ*L!y3`6a{P(#sd3U|9@mw4c;e3%TU zuml}iF#ED#hk`mSe_oa|s?+cTvBY1e#no`Jf+Dq=G?+QeE%KuaS9J>}jPPh~C2t4? zQ9EWnqTS$9s47}upj^(YIOue4TR{P_1ls9BWHn0?0nNqlqPX4UKgBp!U(+nIqG-J6 zHaR6Urd|T|F!eO@KFT(ckxl-jyO^ZK{&T$ryqz36%2JZ*& z5erKx&Sv9e`5H<|LQ%7_Y4r4%f;Uc&M=AXv{muIBu2}H8&z5)P;sI$*oCrK?=g%Im z$?vQ9LC0>Bo{01JtAR#`k(egh&*#&}x9i!65x4W`86r#8=O&I(DP3ay2j~5d)?TWG zVGfbTCb2aG;Erwu2vMs|7B4IpI7@a0n&lFV6%4Omj5rRv+asSM!DPz?CG9zx7Q@+k z-tBQQAwvagGMpNT68=cG%0S;P$_K$oz3L@TQvBt`t1I!pi!S_qkjaUN;1&OrC*T=k zPdOCxF|N6a%o6gtWfQ`HZJq?OJ^42owISJ(w`XgrDX4oTTKhq>X%@%Qq`SA2&?HBIZ|HZie< z4=!3*-Sj&d87T*wl9mO~H!t25D?VXo#dKaQ*n7WHTctS@Z~i(|Mb#jY^AnLzX+4hZ zS-wP30SKmrbzWeNF|1>}@r2clhYGW1FNaPAstQ7pc}MMVy+4SDR-aU>)o}DJ=h=cg z0sZy+iu>h0d5+X`&-4ledAO}Audj?p*%7H)2u0p-JXjkr#{k1G$pn}n{xo_7%_L3% zU;>9UFk{>(m|-p{Z9U& z!Ky4jj#kA=l&cS_TKQ#|SY&a>Xr6K808A)k8^T5Ot3=XVGkANxPfYcI)Bd;85OP<} zajqwZJJ7Z9>~8Fy!(w_Uc&LjjtF9p5uybm@@As$Eq@A&1$4s(S4h3iP3n`4jdQo+Td_kToc@5#3Yt`x z>*>@TCb{(-BG_ll#?*&S6f5h2ivQ1>48h^@@y@(Tk+vopn_d z-({9{pFGF0i`ZKp>k9U)n$2In_1F(CJ+@~JU-x8e16{vx#oW}Nx#c(wQ8yaAtq514 z)=lx}e!02JQ8yX>>u@<44VE|qC_{6KoX`0l{t5~Bxsrr`)W19sHG(a+!iuZ}W6{h{ z92famFzYMSu~FvC3{P*}jbH#tQ6z)je$&aU7$_CQ!E0+mN(q72AdI@qQT+C{n?pwP zSIwaRty%NqazCPrOfjI$odt zzt_V>5ub~*zeMBc90F~lxCh!saptxYC^^;;+LX{@PACaGTm}RZt!U$kXrZQ5qo)tQ z6qu!1`5?k7_+|qOLY0h2x^V-`NmlMXW;A`gPp&?}wXXbH^!q)R2MI^0 zlj|F++aLD(if-xS+rxwIOZ<=6$;og!;!2XIlY1JjX4zPqCkj~!{;B&bzpHu~HSplG z4Pz0noV>2e^Ya~!)c0ncXmeMdv`uDsvw*J^6>({_CPFXIauCp; zUKT&khO_b1sr4dXuqVUWIV8o!yrfz&z1eC}&Z%BJ^zhAdpvXNJ1o?3~78AcJOZ$mS zBue!QQ_CfBegEX3qE1ei0=TWrC}xNY8%4C3+&!Mp=Id3CdCQvIN0?1PV`xYr*cZcx zu9saZJm7K!V*u19<%~@kPMz1xDwW<26qOd$nXiW*<+K)OksIA>s(tB*(~z}p~9=<}O6 zf?78QW}}JL)z*DOrF*T?y6I_Fp|zQ12uk}&>OEo6-h2!&&%_i%u$=vuT)=Se=*$9k zvv+TOwQ0j+m(pDZNkJ7^6muU-i(Z%jhdO=5VyiuWQX`Lvae;2C}TRUTBXE)sI=-`u?oE z3(oG1o>j9}@!S+Ds*Nd9>zsl%!+NtzjqWwo zNZ40gM_qB>hO=2QJ;7~{r^tHMpASb+$yu%jV-q$XaMobI6TDZ5?QNhEBqbV$37ypA zW5VN~44;Ul#4HM_m&HSFw}kn)UO`a6^XgCA;b~{1zn!j^-@xrY&F<(EJ3-x6R>5Hc z!Z^Mm6$Y1Q;-V9~L!gnh2*N3MqrDj%JWlxSk0?W4`UPTbmOVrQy?MdH{dMuL0#Pnh z2ELXS+h3D2q4kyrwt{0VMzl${K&u)wdQg;3C#%O3NYul{WLeHC+jT#P>~zDpL;xE< z+{PY(Pr-)gR=BSr^VZLK8j}mU!Ew!JedS^JhOjC>L=#ktel$Sio!P zR$0|7F-2AFhFy;u8!t{SDE#8(UthdDKI-B>J^TlMT%3DR=6F*GZ(i|mCm+G!*vj(e zjVJzXgmT?lr9&hNzefgES-GHDPD8fjUib}A~MoQ z%`}mx4!b0!Z2Y|RRB;S*$mk&{&A&RrnG`-a#zatZm6$Y(!pR#0S)ZZZ$b)$0o)zi z%e|k`zhA7x(ZKB^D@j0Lekf-;DlxYng+RL0qRzt7gfh9fe zP>21!(CmvZ1mr$UA;p7o7*{z29ZySZVBQqS+Q6zpUfQMuNFg+90E+8}!tp2Ai8kpX zl~pACfAIbVv`|5MF^iU1HwSuTS8KNh@S(2fpAc4ji7kda6Sy_}91a{ULq4mNuwW5v z!XR}Mt^`E+D!L!apKm7%M21dQpBEEY%X~CMA6TeBtCK1GHzD$gMRhz$-cI1z34WfJ z8lG8?X4w^I5-5Of)mVrbXp92x$8Lb-T2s4qnrs?kX7&@i7U!Nczu9guHqAgUTz13zq6%D{l18vO zShD?Gy{ux)(e6te>~E42LjxvE;$w0F*`1@45<>luABs`TJlvRzD-J#FY=l_5*?inQ zVzu+xoi7+I4jr;(h{QiK?BE_$!}x;89wNq^%+i zrC=wf+F6cxms=Ky#ZDmKqYPRy_!YwJ{_*ufgWVl!Ep2OrrKtGJ5O~}8Zb)F*1MqO1 zt%`e3Ts%HHqh|}40gLhMi=+0s?WypCqmy-lJ$V{1OZZ>S?k|efw{ko&jT9@?mGB!@E4OwF}TosL{?_NsX7iHOGCVV4CbeT6aKwONI+rg(rw11ISM!v z$%8}EzrRo+haGW}82UM7tJ4s3oZZ}uI_x-;KR_!lnN0B7-Nm5nZH#*2;L>dvgUarb zE{4^c+h9aYCq~1wB!*PRGt@sJ`bng@emE&F}1`Z7vHV&r1|>Xmg*^* z{`?%q7fuBuoP~{gM|#x3dM3Yfj8}v_>5@|HG@9s|I>PCKSZ&3M$afw4EgQvxK}CMI zZ&Wz^<`inM;cQfZ958k*AlKYYhq(Bx{g3q$`B?-px!VUaTn)7cMSU-LrAU8mN`_iF zVaf#=JHyb*?enEvH0%~xMsuSZ=i~6W;SHX~m2@FNzfDqo@YWAZ5E3o4A#vYm2fa`8 zF&y9pHC^KZi?L0rJq4#y3twI%Rr`yzX{?VCD%T9tsQyx$d9*2{R69;U6PDU;>%{_* zMC|tw+H34i@}A!mvL&L9$Sk}Emn0hd&C%yqeI61Le?1xj<04r-Hup|yjLTCxDH)>e zaGmOxLz5u6DzI{BPc7H<2OB`lS1Z>ODnW@PQq9K|VaDRm_=swM<)lLyl5msBpdW_ZLCTsDGJpD#3ya}&t*{bTU}q@x(@c$qQoA5NMpWgWHkaI3r%i_6Kpx))65>}J$GUX5`EfaZj46vnsF9eKl3xP1gq$!bEo}up-4Tw<2M>K|FcpP4VuN!g zaWS?iVdlQEPM}InJ{+uNUOdiMUDRp?H2PTjZUO?+PdpgB=n&bop031BNmvQUX-?>Z zBZdMw95MslB8|e`qZ{q(dlH)U7Rdn!v{}#2K}Km(7B(IA=4VNJVTlwGl&VvNi`l|MDr>6aQ_cR6dqGJ>)QD85 zPlSY0rtJ<1(h>T_hiuiM7vyO#8a-QEY=^oL-2&^b!!kc-cQK|@X?;Iqx+T~5Go~9e zkv*n3uy{-sbc`c=U@`eYTnDns+56MC9QNetoz1zW+gtETnSvASjC1Rpf-mNS5!-?I zq68B)(Vikv>!N%N8n$)B-)YgV7@O=Dv<*_EY>h6fSRsMVm%qJ!i|kj(W{YTFzLT!5 zx?P!k^mH=jz(SZ!yJ8fw0VpG=$gycUnKYat8LA9Ewk1gFPUfG<2)S8BiS5?mOC0>J zLX@buvsd7m7D)({oGy3g*dP?%*rsG;yd81c4xiRy?~9i`fshCh;y>LG*f2sLaoJa5 z2XC(qIe_0i>NR>OX;m(>ute#-~HuDLl!9wrN%(+}l6 zGH`rhjCJW0u6Uinkoap#v5j!Q$tT1x3m08D{}Fb zSh#WB0?THw0*t;vO`QtIp^Ye1-<+YcrG(+{2euL=07lP+$72OtuQlWeo*-qO1-`rC z?)4-4&J84K)%U8q4ic2yPWE(n0Hi55w9Fd7TMWZubC%8?4v%EK;b-LoinD_%hgN^F zDQW*h=w|%3U;LyNY!o{SQCf364ZNmW44@epCK(tJ2Bt_o5w>brl4+FA)o5+#xV7Ob zC;D5UyCI%+BJs8>l{6=&UWo)LbsIsGC?Rz_3zlAWA2n7iTcEVdNroE2u_@Aal2W-{ z4M^SLTO2|#1?$l5pxg(MNnePE1In#2olsOykCVr_k9~1P3FQ=we@RW%TjT)kufN_e z%JrO6R37~pPNtkoU!M!T1~5Nyf|8IyR}MOvPK7?&&VnZ`>}LH*29=@}^w`rAx_W!4 zrS%v$^kY3)DE;)IEWfYkqBS@k%R&SMSN{#;&09!W%q;$c)S4vrQd>w4*=;{hpdS3$ zjYx>+!V=5t!|D2J<3m^+((RF+^TY5zkEGEL$A`$sEM!%iEWdHRKP;(D++d19eh~;; z0VxA4Dp2$sna33i(`D@r4ltElp*tw1FhxMKDTF9(bHJh5eWqNQR}`6ad9jd3k%&_n zIC9QTf17mZw!Mtj~n_RBL>0Vqs<;>hf0!)l>G&5dw3ol2`sUoKdv zZK}{l)erk;F&6f9CrK}ylLTuLsek!yqqnbl=o-$2RY7ynq`uas^@0X=(rkx)VC4%V z+oI#~!p}B&w=~07Z!nutTKEbL1yu|6F}FLIM}J$CFNS|!O<~vib%@*u;PQoR^+AqRi&TSMA#2#EaEgR-@X1s;l$~en8LkV_7E`b!xX%#IbL^Ub4 zmWxqwi3H(!&L7&`^X}wgVDnE_hb;#uA1*%G@ss2SEks$^Ooe`udP*(FW1#(;qnp9t z;o$IZlP+oBZlG!61*C4*Fhebt1#w>S8aTfbg_;9!v^-25`{x&@p6@e%%_-sOZYtNv z>`A%p!;p^Q8F|#>Hv#oSMuCIZU$c1WVdtHpzqarfI;60H@ zSSw9mQP&=24_2>idxETz%%${yn$UUihKl%bxA|^)H3E)an4hQC&4?6qaGIq zO5e2#YmB1920IipE(t6woKQ)dg4bpw-ucLx8Lw6?tfjIq)#tnzF28pzml^|1TZ9A8 zI-$uI$L3I^Pf{?!JGx<=yA2w4TY8Y{PUHkbi$5Mu$b2QFf!cJnxy2A}z4FP<#qKOJ zI1Zg6xx*#Rg&KW#*m-p#o*8z&g`*XEC)43_NzrTpPp25c;X-*hXwd${Nt4!>9qz(M=F9O`g~}aVM|X)We=$@zx=CuW0KWpRYh?Dle3pe$P43)H;U^IK58b zUMrmVmr5JPQn`~C7@j%6?wqtw=k7V}&A%1McQ~BF2bWB1ZfpU*Ji1>LXfay}2QO#Q zrQJ7-v*35)%9Kn2e7;ofr|xTq_}F??_KRX%jKBQ-;IFiYZv&4?XMF4*V%!msO3(bY zeVzxGRtfY|i~L-03@?*+h@S~P1+G_RIen%JuJ-5?l24sj9l5j3qiRLkvh5=_h)^F? z1vqEfGWY~(ZsRpFu9;8>>q@UCEOv^_HXk!I_MoATyyUUWad zIw|ki1=lvlma~r>D{XaSPju(X)^c6=3=yjnPl@O>J|G3R46yQ+X*(3G4lht85`GwH zFGq^R9$ddYdHwgl{yp?OP|9eF8qyA{mROtO za%jjZjMTV7!6i?+2;fq}gRScuZ&}=zRcBMO@wuy9kv+nv%4TWg!!Bn9OE{waiv^nk zL{J(VP`pjX;TLQqeph67v7dBdi#zL#DS+I74yM7TD!(qYWX@bs6xaZ*ZS25S`aqBC z30c5!$2QzuX!MxP`p~tHfLSPTP4U8ArBPBjQ1*(^R90mJS?WViDN>G@x|XD@scAs0 z^s0oZXLVI^aHftoOjh)^x3+N>AYb)l79*$o`Kj0>-~?hV;`zs7*DCH#%CHcUdBpc> zM<}vY#*Aep+vbS**C9DfLLQCcUVrgy)?a2MOra3Z98~Q!xu20X2g?k{&~UxnoQh`F zw(NmGQZv0enkx97`qWkxDqS}WEXVa(wa$&%;8 zd%^mpHi^F{|0hUw4C%V~7d(~t8#RKbhcb9tGqgU^Yv@evVA5FCkKJUX7T_yp%tqMO zB4=a7PgUmqn|juQm0AwCN>ir~Wu9xT+ydEH)%np1r0mc#@tzPDT?MBqIPg4HW32K} z3SF3H{}JKo#&I9s*3Ii8q}v$?#Dfh!S8jU?kapMfc#`84zqskgR!E`m5u>( z+kRY7trz!_Xr0<8T>jOXF^M)*3xKc`BWpc@`N~74btaunu~}Xf3vqYiMc$?2(B|P} z&52I9de+b+ylyww_1%WwGEdE$Rrhp5*l>)s9pnGS*xfBxRTsZ*XSx)kPiD7%+KLsY|N~Tt~1r zL~`NTiM4>+$FKA_CJ~s$Lm_%|c2be&Qg1E;&n5wHT5X}}BSh<=5T;cmaKw*6tBL{j z2^e6Fmu#AW4vE3(g&w>ki&F>#G(}H6t`s#~$8-e~wP!d1mI7~7q0hm*;K1JCLPILzJ>;{VT4O(h<{{$+78Wk`o~i{>H~w*0y)ZCV%3LdzCFtKlZzyppCQ7 z1!+*J1~&vKWnDkBf2Zd7Nj0n4$`%y*7*;-RG<9bmJ?qKaYR}Y^vkKbL-QgvI);EXr zK-on;1al30&fAnpE$Z!zrI&Y;@bw$ZIOW(i6S)pZXgF7{$g8)LVmf9|8L$}7xWk9e zYzE>^N(+j|Pca)JXmrOSh6*cf^Wu_LRD`H9=kq6LlV@KlAhqyHlGiKB$mP`47Sfw~ zrHO7KzVAX-l74lKgV(EB^O%Im0}H5Cn2vVM=6cvbj+2kv&fdz;XV*Cl; zNwG9ViSt_om$7%*`5grNArk9$wbw9=)+8!$SqAGOrL=Q&j!77(xK-K;6|KTr-pCk? zZkCB2Yz()svrD_T_)|xev$DWn5b<~Dh19FOknq&c$y$Bb4LzH3`({3tNXQ{l#@=HGHF{096=Q6RPhbRdIP(>)t` zoqUqS`v~GEPHOQ!~Rb@8qB~cMSDx9nyIKWj3TNghIXf-;L*!# zMhw1So35#Ia6_BK;7hrGEZuX3u{}$j_r~I_A-n>WruzrvjB9Br|1g2XGo)N?@Ks#E z>KROUK?ucEcPPDZ_?c6(vEC>Efw-J9-01*?Fw3x3Uh)_5jqaxRn*PRYPQxVIfKjAw z2jx$d)36&*VA$F(OR^-ogj6(0F!OmhSqXl~?nOBc_!f;(>27$B{Cy&IP?XL7PgPJ! za{Lr57CDr(+P0)>ymHbOSXA(O% zOuFCcp|=-;{YDQ%i(XscjN$#|@J35sU`>o3wIXl=*uG!V?&HvsAKH+q97A4uC=R65 zq@|Yd8{E)EnP;RZV_iuS;^8(Su91W7`4|$_D?K!KiRt#!_$z{Y7HT8^mSY~<-W@s1 zX*07I=ZWQIqh$FHPBfqeR z;gp>P`CXRuJhrhl?+70T-1wj_4`focc#{3rll_TC29Mn(Ec2A@jyl7_kPeo5jqVx4 zOn2)i#4y*RIs--Wv7SNO`2Lhh&}2DM0Hcp9OFfucg4|y9(}qX0K$- zJk?sy8r2{_&HKglj*2Q#stAZWhX4M-Zu?v_veN26IT37nNsHUQ{Uy)+MZE?ab682= z!62%2c zf~-e4ZaT49*K+|fw-brP$N_tNijvhwXY#SiMO*D;i0z7?5^Os7haDvX!?TAFb(OYFl6mmGd#a4bn z(^%yAM2{D-OyK|?J7ND_>_{4jjJV(vw4PwUBTEwZT(CIW23zYlw@*T=hpxDq5g6324G;e6Ts?usKYXuPshYC_F~=sdS3FcTm!0Bqc5!qfYFe5_hk1&= zu33`}_GI0lRO7&)gVSUEwaZ~q>fi~6rHThnFf0{5Xg91l$Yi}`lYs%^uT41_i}xh! zApBVM8m$9yo=eie(OY$ef+T|pF$zTC9(_@KFgbt|OTW{2af^;jf@Wx2W`#6KNUztB zBnEbKMeU1MSK@yc-J|Y)hi*eft-jtq5f$kD)3E)>%}A)#i&`~qo3S^B}sZ;_IJ?#=C7RvuPZ+2D#I7bF)hJ2mXz8N$s z>$s)$51UhS&@o{=nf`lR$qidT3|Yd4Zxg7!MuLe0L?~FL&-H;!~^JTIK88MKkMmmakN1HhhjAuIc-%?`l`6s)CN6>I@J3D z3vpi}CE=r}Cv5c<)r+|X@$umO!NGwU6UveivNpXvytKIm@iK&cd3HHn^-Byn8&8Xi z$?{>i8hty3d)R1&gl!(^MwycZP_+&TBDBd(9RyD13tG@@k7qS=B#G5@?ajuM zAxe@gkPHaR9a=iB(FLEe$q0K(l;UZfME1qY>a-oB&0+}$wMwE z_u?h~e1RHu=Cp4M!`7K^U%c!I6h%!q{xgiC*^F-|D5cSIyQmt_bPAP4 z)6uL>SNwFC)v1#=!tCVugv$YVdL(+ZZw5D3onUjwu>uAgL++g%4?fO{&qF(+s1;O> zB*e>nA`5NXDf5J?v*9x+U>@Vxyz|?fp>}$yZ4-}XchojVZg%BlkG$CpvbACAE`;q3 zRKwr5Hc%bA-r7KQ+}9o`X}%K;IUg}X7T>%GWLcN$VOy#&uMJ{ERp(NX;5Y`*)14V$ z)({G=*H-xFSm3uGx}P_4N*}2pD8hM2Zyr$K4l|sV7V~mJp@p**N|Ms1<07R+F)qem{(kV+>&tiDTgCaTEn$7+^Z-z5$|6kx zpsAwTq_d3oyc&*4LrPc}qSOy~eR_R#dD^f`zt?NnWjGs`50~qQuf@W6nK#0dAzYPZ zrOLcRl?AHP%tUoW1l~N763>g!H-nO%;|oQ|VjTkg-l1dn-N}XTc4Boyu|`(|ws%db zK!3-0WNAbjV6tn?r$*(tcP)0CPBmy&A9|*vFPz@vd^X{b=%VW>&-!F05Rt`B8&?2` zwsLOoSS$DH6|IEY))~^hIQ?c57-;@eU@yW-YFsIDE9w}Uu=R=*aKeMqKd-`CWUhyU z1J+i7d{2eI-p6ON39ZbQXMCJd%fXdbb~JT6&i5tk9?TwhFkQ2YB7-QGlGeL;OC;R_ z9`;;_K&;lf#?EGT$|CO&cCFV<(?;xeI|JKRC^TsxL(cItE)x%r>m;L{g_2YI42-r zc?2&BUyRJ@&Pjlw()m!9-`De_#R3W=(w|*YDFTnm;@&$WiBHzIGFwx6t4lKz31Vv7 zpU*Ho3pEztf~dKKkq}Y5;krO<>+G`lN&2B>*K#x{;3Yp=JR1a zSxWC)_V_|3Rb@&ajn)tFQzHBixqgrmL4kN+K*~pnh;Lbx(s041p!F^gqN@{Hv)xIU zk$}51PD|`jTy`aSjkQ+N!RE+ZdRVF@N#>g?sEA`p=P(t<6a>40hQx6PGlT3=SrwRM zGnG{cfRlZa-TQB_A}X~OC$*^GZ3I|JAszOMeAQu3Jw>P8tFH(JchC>((a`pQrbJ#E z%LB&p@SqDhUW%Q(8$nQH;SxTFX7@`6K}1{7F!)DYPBlH0%ZnrefsXFKnh_{tV*oEI z1CL3C@WKUkzI=-^1lDTu@^(MAnPG1A6O*eDbIJ^k{m}D z50e>k-@x6K?O>uosiyYW&NT-zVLfo)Wq?$6evMaQkT#8w8RA{YZBi|wlmP=lm zImofqqrKVCLjF5`Tor!KUi%Qe#St3Po9rtcTt2kc*d>W@pHHsYd2jM z;)y$s$I#*YC^A!{rjuz}gz$9h&JMNkwU61pQOrz#`;;i=rgF`}ksWizG7Fzycn06{ zF;eaT*1A|9Tf@ftw_9iR(wA*?g9gxskMr*E25>yxa550tT@4^MJA88r$&ofE5haB+ z%7#58qBT^YvTIUYimu=;(91m-x%kPfAdvQ+CHc0E-uB4H$MYjH!sFR6PC90&ZKAFE z0cEcn$0#^YNb)qwy|IuZBWW1f39Nz0zibLP^99fhZuWyf z8sM=f#1!Lz6kE>iNfmNQE^HX*q_` z=%QGCgUSi-4(I9766G+pG}2%t^Kn@&-mYgOGLBehenT7uIY?2nq?o#A^jg~!W-T6R zd%`SNhO)PuhnlJ8uve*bj~H!Cq~`LapfM%G>n6@+l?K5cN`-Hjj@^;UW^juYIL`Ar zp8Gy5kMM7)igE&D>Ho0wQdrigJ|ew>k!zJjRh>)tVHD%H zIXB1ou z*egV8TR8tZTuw%VCI8kvMFQB-x8Y*2S_~&ExO#P$t8teqk>Gk0>7no)7%+eB?ftEw z^Fvtcd(MzOIo`&jvd?8;vo%89@rg8w?BKdL0!#{nkS{20pca5wbKoQ%X%1)tXTH(* z!uBm`4rG0IS3s?s&`&mLe+)9Mi)cV_?#va$o%7?*9rl8ymB#z1P$=~Azohf*FwSY-I7ORm!y)7A7>t* zz_9Y_s!J4!VYo2~xGq=Vjc&FW_Hxwi#M>41s4 zO-OWX-)|@z*Ao z$>sy+AL-Coh68R|K4}wDZ-T{!^HUuF1m5Y7M#^`>i8wP0#K@m($o>AcG!d zcz9&h1b5DN>EV2v0SG~rh{1`RDP-6A$+sa?veUeJGEB2$h_#zoVws3ombX;vJ-jwJ zt0KvdC?yX&^N(=ArKeAdrAX7X{!?a;vCE(47EmRv@5QhRAALt~Qy1!)`0l^FYxjd&HgQ zd)@&$N&%8vk5%rM?a@Q&ICg_T$eLp-PSRxrn$o*&G&dC_>33b`xApOyq>{TI&rMIc z`|;d7ms#Vbee%?CznTt_4FoAhbTMjV72xNP_(CjOAI8AqLGT*9)&wtT>`F2T39b&9De{Xhqf~9NWsg-!94ry;=9VgEhC>9H;Q|wAt28 zkxJ|t;Y4I{P{;;)$C#iYSbUvWzG?(e+mJrPtTQQ`m`s?$dOH3j>{-|ESFpDLhqIOf z-me9}hUzP;iXAT{No313J%dh($R=SpbS4cn9+R2a#A6mXBN0WY`^>9nCdeJ}Xd~h3#xDTDhHqmLNv)CpAt#lUI2-Im2vUC<( z8!c03vAyx~bQW71FH>i+wed1_7WQ~KI*ZB7bycL|f+sh9rIc_JP>@(5p7615MyjyH z#B?`u(dK*|E;|a3lWhr@%wjh&Nk0ca4*p`^@$w>L&JN#7neM|yhf>gTI3W0V9CCY@ z>t!S;xssI@^dk41uTXysM=LL6IQYbOXJR|Di!{8*_bjHChU`V;8mQh<2jhn6OLrU( z^N)91z&!wSn^+@x`Qo}P?U1Z^E@Va0CY@MbFUQnHM5^bFrn{95Hqm+-Ypv2Pvni)c zCj$#?&sq6E-eOV0_hqJK`3Njc>Mf)nb8}o#Wh9)tm+*Z zeK2-N9bb9o?MedmMGz{h|M`aff$}XIQjv4PPlLQ6=vyR9M(Q;@dO4_4Pu>D+eI)MN zbn+oD5p&+#Ky2W?ZU)+L7N1|)fnzt1^HAc44adM!$l&V|rkW7m;@b`K!5d~T(vF7~ zN18Y@hKwFdZyv<3D8B=ZoC)}f%mIwKwbWfXHUqBjwP-b(mQ-|>V33gDM#_b{GhQK+K!!+C8we)JW z$*WMeQv_JT6#}B5Sp=}RJcfi8{ncUj+UlkBhuQx&b}=xM_(N0(QX52965)zfavwi- z!&}|n>)ht@=CIRgO_rwT!<|y(OxTCwvD<1#yW?!KiycVEk5}c-VsQwZERtb8Sl(u7 z8}jy{#RVRvrxy~Fd>F7CqQ%Z77f&?HN({mAz6$O4o6^p4phlL0zLfMYQT15V1)v2j5^=Sa1-0cs#C|bi zm&`6@dO1?bWhi*;WLgYo>v^|_bpF=9us$*<@eXSM?8tUl%7XSThT6LqFPlRfypMq! zyl*kpG`KwU5T`o?>pxnphNEv(O}bjR;PeA;UXUHI60~}Ib#e81}38&UCRKBUf3?};9d-u-(?MMsMK^aTMb(qK#`ADSB2vPF3frC z9Yq116@QzLTm}*G0r;_hbXb|PwZA^0H|!@%DhPyWQI8J;tuz?Cqpw595>4%KgZe=Q zldCy9CT<%6xr8w9N+9-hMcjq`Mm1H-0Z}YMgix@De*8)~$cRv^KE0JD(rUdt_D#@m zgn8MbBK7NcKOv^W#$2gMiEeU^j!K1^<0sXuPV;G?P_J+#i9Al^I>B%<|VAmUl@lHEd9m5MQ6 zXU%a37w?y%S-Dyh%S`q75cVvk{UW!pZX7_(QMMy{2O*CK-7f3t^!oCh#r6My+9)1$!bfHO@U>WcymOpC@?5vrq9>Ag`TZrd zYQ9HlZ}fUC+Yh+xHXbYFEEbvz3bWjNn=FMp%?21cVCt~_*dIutp%8+E5be$T08gvI zrQsPLXQ3BDpVftU@X-=e6Hl37z_~5w#q8?c6&%=M!ws6Aa-tMJ=0GtAUN#qgIKe^5 zC95_XI1h|PxH-}%tO^n*`J8sWs&s}#%qTy<(k(F(dXgobsve81V}gg05Qgm4CR7gZ zv8S)0$9sE^sAVRKB7tzM)mR}xs@eaSM>>os_||i z2{eHnB`G_aqBuNjPM#gt+!uN+Ip@C6Ys(gV{I<=myu_f+bFsmu+csL;B3FRrwdG0v zN(4Y}$d+nH*np$vz}_nQd~Ycy-|U^l;-9C3jq^-*Qb`w2`}%jgL3oB{x27ts&#he$ z?@lg4Q77>+lY1~dR>Rvty%xzrHJuhhzQ&u8@@Hnyc@cS3R9xLYEhZ4z2h0^T6XY#ZZgH+C?#z%>=1i{Y`}p7?UkhXj+T0ow5Lp#7E!yTPs3 z4C+QGBj}Kss27+g2r04}2vZb{HleHrU~sTAh$djf8L_b@o>wymU>IHu3nBt~Tuf zl7sM*5x5rT7#9pobV=!@?s;KgAoko~f~I7%oA{iPeidY!tRCYkR-Gm3swlqa>5*CA zDVSD+K1R7IMv6vJ<6^OZN1J)@YGa`tu(hpS=q%%;Ly_ST$>at_NKQL=T~A9QJ=5|X z{M9kfj|=1$QFoez1LsF&;)@EC8qRqf&g)kV;0zE`T15!;&+~&VUgCdzYEknoSHeYR zm&t1KqkvZ0Vslc|2>b1+E)Y=W;Zlo`8bmn_85yg3oKAjB93@<39F|8950Gn)j*-Mo zI|`bkR_REBir=rl{<@+Fs{DzO$6SDNZafP+)_s~&rOg|ps5zg(pm>j<_T@*m4&8i1 zDFBz4!ZVE=yoS>eLVs38|3+kWMp3HnyN`X_argbv7v9v$0j|Iu0ao-hDOZIct6kIb za7nw>vB8L5LYlv-nFBMNv&{8k}4+ zpgf@<9Fw0&WTeuB*Qr?9)ydGtIxrThA`$V{M@ZnU(i-gy?e+r%u@)56+0+d|oz|Qe zi!&N_ZJ!pqwdY#nGf;LFL%Iyq-6fx^i=rv@s!YgGA&Yob09mxF zbhD>oP{<%%CZz3BPGf6OwYE<^;X?iE=@#haCBUeoS3QI}Iw7TQzZfn?-)QSCejq^B zkl+u>-D@`G0sDS}FXOm;JU_J>l3Xbc*jKI{ibQ=>StwRKRNzD%IjO$P=a zQu1s#f}q0rTu;k~;bbNr>guQ%bS;Fm-WF2M2tp1{`j>LSN&=+99r@A=HHRnKaSx9E z@<|cy7g3_u_Qfj`%r8T+odwC0y|S<;44Pms-V)Kg!GgInZAt%*$vwG;2t+hmJ)s9= zNnEVqj`7Pjc0Lh)`R2PC1h;Kh%r0=gE&aSF zNzzb1qxN&SW3pew5hL1%W1i?KS&aFt1(LFIU*%vbc`~`@Jy2dX)h}R|po-_r5`|-$ z>?vHB1I=-zkXxa3_>HE#CW8!Fy@V=<7>Ibu3;t0B5hZFph+30j91kcKtn|0tFqJL7 z?6nV&i>Yh(z+&*lEt1z}4B>Ui7~>kN{sWGOsMaA>=dj4sMQPYag&zPxgA%zh(jGg2 z0f>bCtbj5%EK14Ue6jV5hshGoJe>A)>sVTw^b-;gIwv7eh}tX5B~L=7r&px8+G{?f zXgsS5e9+#>Z>)+5?Tm3&&(E!kYU_tN!u}4s{c^o<60Q(`MDiDLuGgzWNE;hh6lSv{ zn^(o87^<*(QYmMhuLb)^$h0^aWDz~ZgKzY0xEMf5H(4R7Yy4G!TXsK`Ki|S@Vue3G!zk$NPVVwvC{z(3 zHGKS9RGe8-=RkP32vG~?l7smv(#iuA-Yz8I(O#6EF}kykR?9Ggsbe5vNQPtPaF`LV zR1YJJe|^97#&>bfHy;w!JlmmWwFD*4ct}t@%b^1$&vZyoe7m6lbAA4g%hRJCLaWa& zP6ux&G^GmM>IWm>^6?`1H4KlGipQiR zue)lORCD&7tximM1<=bj=1#3y=IQYrH5Vu=_~ zNMhn)9go;11|VN0P!potYPjI?ACfl?&H(_eF!-HtWa)V&h znmg~PAk8JIE}9P?*z{Y z0!5SsTea-nY^eN%^NeFn{|NpR175Mu24Txq4L}D>nN`TT5d$V3Bw0}c=i8{*5rFTt zO%4;t>RgrQ0%NE~O@Vv3nH?S&!)u!yYFC-}AoQU2gYX2zQKS2U?(^WH;dja|eZ*;# zi`8Tlm{SJbWP0AB;O&UDChmr(TgLN3^SM<;EE&j1KTGn7536f)a zZR0~r)oaSn6qM$7mce&SDGQx!o8*;F)AGipWztzkuZuen5ULF%@>n6VLtK^my%kSZ zWo8PEDYAA64Mdy%*f(BwHQ{d{A8{GDhy)Vhso4Gn2Gr?UXrEvvz1jNVrsSl}pI@Dn zckt9K7xqplXCjA{wSgIX_j;?6P3zS+5Q`W7zla~HvG0IXQXz1F5Y^_J$5M& zv)Day&0O{NjGX5phKtF%B&?6ThiL}{N%yo)dV4}@JET$vRR;d1Z|M}(n|t~N>BKi= z?bVh-q(6}k(|E0sq_x27#Lgb&^_~1{HXasJ@+}-3jeiVhqhc)miWryW;HcL}RK8($ zuyv8G{#>{N9Fj8ofGxp_c;s)mHCS+N`c{m-!+Ww=;U#ii{0JaK+By+srE&23A&YSD zRk$ZvGpIj3k|~++fLOhJ%oUOb_}-%d4=KoCM?VVpcr-@|43o_n1f}pn+vA06b8X~S zM52uxXloe1x7Hap*K^ohF$Bu{?Po4DkcYzHy}%)44(>m#IT%|ih}F&Y$@$e;@7gn7 z_lHQ@i%YkEc_0pxjJhB78r24MRsjfW!WPi0HwdJ$ z3-!-ME?jZINL=~5U5C4iCCxVbo3X5O+~hLZeBjL{X*l4f5!bn_I5gu;u-I_^irGBr z^xGrRdiI_uWj1mqMC7#?D$@-WI#X7{d^P-#cHPz~JOk0m_Pg~fR`{OPvkkyOUTBC!19{1=~RMfXXlBVaO=M(NKFpBIF zp(eV$y&%*`No8S_5h3`+G`}f@A%O!!Z>|&O3e{)D)*y16hRv?za4_nOtwNS7{+_)g zHjA;cwk&I%SXl`@ju|95ctom;94~0i8^W&yLNvp-7CmRqe3n@r+f0hbG>KPOl3lJ8 zf9zaSd{GpuY_!sMQwCO50OGFHIg{iqnTu21HCBgGsK2;{yxSBAO(68buio*3VGFVbKg$25m~f zs7Q{+nd`kMQrVNX-dE1=(JB^F7>_ZEh`=j8ppw-zWNPN&6uI8Q7XEcO`raqIm6tNW zumiSs2{mr9a=RpLvbqZ*{btA*+uiNVCEEe(`}48Ff_U1{M&HU`^r3+6+bv_|T`hc& z4K1{mpE3qU65(PM2x=qYtpg}&M7X`=;1V$r>U~|VXGnV80D{_L zpacOZ*DGmGP1{{-h~k1uTV_+B;6{KqsP(OscAm8ErqFm2S%#?M(>4=4aoDA*tv3TfWHmL%%;+{<1xZ!KSmjq~y3?;=w z0q!rNzMOP4mHy-(?|8+ie6d(MTpd4(#cG0N2Tcid2`>`nd2|!_F}6%sEzlwC0;~(> zzGW9%`LtL}kW2|Oovv=`@rKl{Yn~=j=G(wQ+<4A{dK(Z804R@?J}SJEB%3e{Ys0l6IsU^ayXQ!=}45oa+(dQ&|`g!CPdTScU>UcL4j;wlvsF%YdTNj zB}#21BS`G?ctXfSH+_0N@FI;a=qA zv4y;Wt7b};c9Dxi2gHo4)flK8vWPS42RkLo7Fb=WW~lJs4i^#a3$vk4k2tu*Dw-6B z5ZpvE3;ypr_c$E9W1`~SD7LO~p^la@Hk6TyI_FJen3-m~rUT?vZ}N z%Gq+VTotp?Bjo@Xygk3_4-Q_vMAf>f?H$Z%z7bWUceF?XfWP%jq_2?LGoR*n@XUk` z!3t{>o7Gw-aAFbb@!`TOV{<$8Gsh;zwhafDEIj9^pied*{ zU9v*tXz3H6Dg+7`wK*ikUBZ0ot)S+{EP>67(d6!t5`hXCY?;(uT1QSQHAE0pfBx7F zYd(&Tuni%QL!KAoJt7Kexg6dHv?P984o_=->$y)3c_;ATVSpZeqC1=*d2L-O_IM4V8J{*MPY$%N56b zH$B36xEA)e|XI)T9#}b=#AMYVQHipaQEB~<0eKUbU|jGFTjWFzu>C-;^lF#dkd%d0~s~y zMWvGw3StqL8l^FJj?T#uql0(@MhJhpShqxI@V*U!&S`W|i3kK|e#VH2X46q(G!PFg zUKgz}qI9#wo0|sEa-E}%w2o^3Oh!I3#+dqc0*48e6?P!LKP#sc*?|`{$BKwAxgjmY zEpOG+UVqR#?HyX1$@+Nfg`_$!{AW8c1Pq003H;*o!q&}QF+@2n9_K7%{R%6FnE_** zt(pQ9_5!|n0d>b{0kaZ#JEEV}Uhh53Q6$iCMr?kv${UKPGeXBgX%}1&CPvZy-G=H} z`W-5RwcJKwprzCJnI0m!BmoaUhYD^6|GiD@^lTtXt#oh0S`)+!a=P9A@UCF1orSf3 zd9+TFvdg8zv^1}$>>GpYw)`8H#IbS#STNUmTr0+0510B<1dX z<~d1!3{tyfSoFfm&U3L#L|}L6^}Cbjxps85WmY*_WjIo~+_+8)J@zXVIampW1Y}-8kBUOG83cj(<@(`kvG7%+ z%^=Bw8ib*>@O3b#(8lF(u_%99oi>k}$BjDpERE<~%;Pfx^Jg_f3_e4iu?v0-J_jm( z;7bT+>>ok*wj4xN@->2RerOSvJ7ixG{$~lmbygGs*Egc1!Pc8ff|{rrpi!NXwIX#o zH-Ct&DM~W{?*jk*t4rO9wo+VrARNy~-tetba2oBkHu|&}XoE%ahn>&M#cCOf{q)?& zLT?CbPglZhrGwXcTLaLcsfW3VTckAw4wm2TXqoeAAA#CpI_(FmosEzub%qclUYeda zMRze?aWQuDbLWa&-2U&)&9?#$h?Uw&e{hA?h&l3rwfQIlU;aG5gDdNBI#I>oBZzRK z5nE6&{@cYV&p%ECp=9%p`UIercdRE{DE z%Y|U3kOLw(g`35Ch7`rfY(!Bl$^3FvGT7PDcnf5qLAnY#4@zEpFSHtqs!F&uwdqBIKIX$%Z9%reLLWcMjo!zo#OmdeQ)-uXFZdh#G;Dh2^WY|wmWMK^W; zC>HP~xG6Kr6p>|1xU9-KZ=_lf5~;9(Aw{Jym@nHPB5Fc!5gA6JcP;qGl*_kxUZ9E) z5#~i(f=RWZ^SMhSMk^3|A@(#m&+Z+axU0%jq2rbYdqUDgkKdE+oy+xf>OY>JkU;iT z{fy8G*35g7-5gd`JmHFc9!|f55r({=YO$iX%eGk}eAl|3_M2sdqjSg!>=S5QEYQx? z*QQ#MX5YvRq9tdT6dqn0>UD8X?$=1ASeuvmW-%E~*_F<%m|bZ#H(GHL4=M7ZSq6mvK0Dsw^pX7i363}vbTx(~UD7McI!S+!1D1Sp>2{}u zjAe6M(uw;*=grF(OFl^B@q`M<2#=mxkA_cf`-E46o1w+A=UcPjYzFjvJ*Rhz_d*jd zpZ(#SnONsp;p`O=RQpj~assIPSCoMVVOgQ-0@9mD~zXZs2)n9M#N@YjIQ)msyx} zVJ?;Bh1PO^*afB`q}*o9iJr7nieOZV6qrubVMexw`~4n~TNX1d|-Z87g_0ot8oImp6}L zcAA^GJ*78I>ZCgz!XmGl<1N`s#6GV2OExzLlK#Wi*Hla^n~W!{NDYVBuCZ{BgSVS) zd+T1+l-P8#?Z<99*SeH7P2q);%ru0e^59g@Q7kKq7=UFX6|N-WkU9B7Bmq?LPzs?% z9WLRk6Tk!R!j1$<*7odGjzX2V6Z=x8*Q={;HYmQhS#ft-#7;g50y?- zBy4qNQ4YCacr&#CiA%DFoj}26@I-$I8PVJ+285ryMdf4QJEPvqNi1{l)}be+#?%@H z-jdEBKHju%>H)&iw4|_JyJ{b)GD*OCDefsjqtnSfGE?NLT%4{_)}R~|3ggNy7XqEg zye9^fz3j9ED0KoDr<9QFVKRfpb~56$vMc1Kkj?Q9C`po(#lJ&D2^hr>yKu#uBN+$h ztUMR)cD(db60SiBRk_O_#e!_+dqv0(kWkUs;VWJw3sHyWKt$V%nQ5JKvt?Gf5-CL$ z2VVv>Y!s)-fs3XQNsYmb-li?8H5YJ)KswN3i0bC9cFU})d~hoL_Gh=7r(jBVyDFC} zG29KZorJQ7@?fMVU>=@!C(Gg zv8dI|a+@fQjuLlpynYTx!ZHV^(vk5Y^OX_MD;-!LfzB=0cF)v5WxKCp2Fp#a`-?v z(A5Xb?$MLQF0j6}DZ3e{(CjyZ*k(821u7{90 z%X&aHvkUHA2m4TqAa+*6fqpOlD7d>yG`AePDm+p%Ml(ZNR9zL|WSp%=8N3KXqOns&$Y z8QdpVgFnrclT5;i+XA;ZU=MD;4&a1|Y;+(s(*NMD0(l3Y7sL60Z&C`wj$EmDvq+kK zfEl9MIBx~YAK2z4&I^|>1w`O5JnLHi_s4h z8bAFsxIhXz=+0JM89*c8Af@B+E!8hwb;-&L7tKRdmW#q87uBw_lcE6NKU=H@lvBRh zlzF*$%6+6SLB{_#2XEd$DM6o_ZgG;rJ`E-%ormt{R}AHD+C3zTQ}>lk6F77a*l!mY zkA+w=m=!+<(_(hN`le{kd8e#)qaj{_ywzk1z`@OAO!7?LQQ}!TJ@#{os^iulAiIy0 z*1}?ueGY;x1i{3A&06|t~AI23?OC*RZ=R(p+YyFJ&1$RRw0v~gZEX8 zK+b3tN;rtsk;-YjMYs*-5V+r5tg4TGEE@hVu_BjK3{{TtHHolJ}2Y(4LOs_)7P z5=3`+)f3gRbnFJjfr)^80$;o2?e`32jWgtlpXQ`@E$mcyxtA z+tn671HWg{(9afXodySd^fC*Mg1|Je&q1HL>j1Hz{Dc%yg#&t6E!~%u=E)fyRkj2% zu%}s2+jA z?g6A`Z4n1&OW#T&tHMA|kK>20=C) z4&9DPvDa%;z;D@QUCJ55?fe||9DP< z0qJx`>&1`a@GpNk`1{}iIitF#Oo}av0Frg_H8Ue^vUYHjtOC5MK$!N^_Nq)+I;%_iYP(F{5 zLO$|fRF$Sho)rFb8dy2gSo#O4#?m{{p@3;Dy_{5IyzglDMjCHJQ>aGT3|0#?D|#dQ zeltrdR0U})GeI>)QX^!r;Z#HB&syZ_L8Ot2Ywk2fLQU#`RtV-zB%t<7gZv!Up?P2< zt&*Sv6m+2m8l(Z%sKXRtJra=qvL#5@NYHU{dhpsV#L*5XL_uvnF#sW1)H+k~aW?)E~ zGbmUe8-f{Z3!lN(Fmh9?w4T~Fz}z4-!FHvtB2$coG&tuFsPDyNO7x;jveKbW$g?}K zMkgTKk)}$iyCBfAXM057rPvY#RPYdv+EpmUphJxaae!pn!%&yl1h$7%Y=k<*O6UPY z>(LG~e<21j@D^IZKC$U+5v|w|K57d%XX9eXv1-$e!^Hx~eXo_{9=7O)u77Mjxmy(f zWgyR&;(6I@EM!RG<^6iVE}!>?u z)-`?j3J-2|t!8u@e19k6K@!Nr-w}RiY9DwDfHM-grujS+T99*;>M*3Nt z1EcOioC72A6wd4(zZ!A@L@$a=0P$-h7eM04n+;+MSi~>0Oe{77kb2q@0uKRyC;EOy z6;G|?>J;~jR|VIVBPoRfOl0ntLIjKB;&T!_G&k8(z6Z->Z;D*t670UByMJpVSFW9X zj_qG5dmOuRUF>n}%2kjtHofc{iDvYCg=L3S_$=WdMZ?_`rJowX zB55(wU&x4w$is-+k^woVV6i*OH_#HNDu68@^?kG);C+*{vCiiR8K2bM+w%qV(GT-A z3Q};ciW|SO$Ul$CJ#)TZep7LCDpu(^#-!8s{PN-j{@KjLMemL5IadrU+DhTP44l0d zMlTbRP(CUZWO~NAAhRc|CuiR8o}sL6qV*86Czt^W6Z?1M5?%zpr`^6lSZ$XR0|jz@ z9{lr|E^sJ^TRIX8XW|1N#-qHU@z;!N|kQ)F%z&^yuCvw3AZRmhOUb6U) zg%E<8kq$_4&DO7V=|h10EC>gF^WveP%7gNy!$dm8 zM|t-ap|BRh)q|G}a^p%xfHnih{g{UJOGBo^BS0bWzS$_vJ&ec(k)RnGg^;C6TeaUIi#fAM^N{gh*DhpppLuJ+oWH(P+^=_rt zJ`bQM5>-O8ira+=)xA~ z%A9SkU>n|B(X21rF~1C`gT4Z^fWJeE&*lS4pUl|b^`1wMPAtkQ6ME9sH+~O^A9qa# z+}&)Epw`_&X9ymSZF2|Ea-edkmI>l{59I93`R--aO{YWI{fUnS@Tf;iO4(-{;?*S= zcZHVZE#SH0?-(Ep#>yq$KWAOybGzH!9Rax;bClck-tdV5cST3Az23_%SuD&e^WqI7 zcxOtL;+v)3j_OW!k58oaU>QSm6!C!|t+oCqdc?5$e^ICXDZO|;8E$OzeT!{osdyyq zd;V|+n!je!fz><1I<>E{jq?|uq|O4?U)v^m4rIHv=oCxW97m^ z_C5LVx7=eG+0elI9^W_@@yasDWv6I%sfYM~s3}Jyi5F6}dt6v0q-oZ^c1e6FKs~M_ zwuSzSO`W2`|Nq^9c%x~!i{v$2r{w=9AQKR%mKYTqBiv-Ojda?M- z&h1|6ZJ}8gpY+FlOB1{8v!&DPFHyeb5B77Mz^`BVHIjeJm7=&3BV7($Ht5k+c0G{t zp%i^k@}WpAKv($oIUmXeV7`ECa-k5V1isvH0$myMFT=Y@4L{*T_aD;>io#&@$;=ih zw3vAH=!ro$ZkLNx>nOIT!?o{uwb4_Tfw-;+2KVy{ETs_az?*FkX#C$&by%jCwK@YO z72Phkc4kjk$HRAAFvu-KYz0CY-tF~K-H4P5Uag7hP(k;Bi&v?eA$;|%+mEk$?c?Qk zx)AL+AyV_Y{kT-SpE62C?d9)X|DW7na^RBQj~h%5VB-6Jhsl9Ud_Qh6IdF;Z`#mPK zrrL(*1RVHKswDrY3pPn*H4XOif;@>jTIDy!*!x5Lj+}Yy8Em8Af;1pygeLeV0 zh99?hOI6moDhI!N-Vwfmib)KI(7p4TkQyg$$8xgd95qO=>vFByvvDaBXEC& z*X8#6g?e;9y~H0xbI@JlVja<~3U;>nojF;K>P~t;bL4XwQk~cD#tY)wD@KhcoIx-hjK zEd5$HtrKH_gzsLHKKwVmoN+;HtuzWM1pH=!F*L^w{+?#~K0}9_J%|ve3GtzaTuSSl$ABji}^gRTW)O>TG7Uo}}SjjkrpKC-^nB zE(W6zPouaf`Q>;tkQ#&-NyNZnr9w}!;L(c6*D9kvNv@NveTrnNK^aaIZ(vRv?)%cF zqaUP@7G<6_{0VnDq`%I5d zrz)C+n~L>x;bRY_JtymbLWiB$<>rh+ypA1|agCpKr;|yQj3H{88rcPn6Q23&SgI{X zgRuDI;Urbgd6-#bfttXW5;ga6XetMZH6&unHfmBxs!o`>JbAvMRZ%BEAt|cvvWL{D zE3Wr?E4}E5HS$ctV~J%SAM?1_4L);l7cBZKlBV+ZwBb%8y);!+oRJj@Mb~!zaW1m8 zep6x+ZYo!F@>buHAYDq<=EXQzAvLO0!XpPyXDdGM;qEpPTc!uZA(&dEIbI(I69)R~ z0`UmO+nl=G%~-Xs z`M7CClFLQ<4b=6eJ7_RcnTYY7@Xjfo9I%|uq$(M^L6 zof6XxF%^a9Hb{<9XN(D_QMf{Ebg`)7Y5HAO`er~($u)CpB18S?RZ%&C7@TQ3;<7#s1r5~mhqfj#1sPsWqGOGTt$}rSaWkBWDlxW^1p=rJMf!Cy4l%-gfTfn|DE7wJx zIguHlk*r>2Xrk|Z(Ot>>q9!ww#!nF+l`coQUbujv^cB;n&xJ)K=?2FV8u_-EEGXh- z7Fly`g~itR=|#8Z;4-G(#TzOH7O1g`%0HqS^UlReYPg2%%j#P=GOaD`(*lbeQGdlm z4pz;~qx(gD&Ts}V;|4WT6>c~amZ_-eUYrv-S%4TD>rAe+i0*_%3t{{zrX{9hRXG~^ z8U2BrOz4ijBB2;c#Tbyttl{uNL5L@F;vW;padmrnMJT(lL4_V^?joV__0lqL+}TAC zycQqt;_O53t(l%{ ze$s4RmI`s`Ds;|75*PRUSr%t97nT{l>8%{7nzX5hDf*0NSS>?lLu(l_94*R3JOe%% z-iN`O9LH?jB{}Nt#-j=z7B#4dcq_*g_4fTAQn0xDF{0q{j0O}uH0F3h2QwK?aN2M* z5eYUKOmJxb#}Yig*-%177>p!TOys1GF_7S~OvVu$Fc?ONz<5Rx95oq4gn|7SL-42u zLx^yo?g&Bz#yf!ExY_tY5C>rRz$KZD9_sD;J$T?z5A4_>EOUQ`4m|Guj2u`@`Gzv@LB2_?GxvdTLsiv;>0~3-5c~$u1eHU#dxh<~j=IlIoZj-Ay zH{V$l@o&yoZV`XC(mOxm-;$-=!v1+mPq-ESxymi#pRI}_`)9jb_~vF3;osff4#TRq zYypK223R;aeALHs;*+M%IP}q#mYo%swCt?huu|fvmXc2-VSZdP7aepW$NVOCLAah5ZyDa)1BoaN4HiC~3_$YfsC?+B)( zs9LCg%a}?rSC+aQTr#GzI}D=!9mcYSDGUw~4CQV7FO22F93-(2=E#RxnqZD%n56~g zXwH&#)7S|SRCWwY6K0gn8aA`Q!a+6te_~zUC`2kpkkNHnb(r%ZZ2{<^PIWG*{&>CQ#cES1uexzMa|B9 z7fK0v$a6x;Jf}0K*xHT{$jTw6LJSndNM1D#*`r7Ut$tyG^<|o3dT`?&kdBoLt0q=H(Z+WM^l$Wak#= z7r1irn*`R>l3!fd;wo%HwaqDX6*-G?vt0!R&BaBz?)>ch9D%|1O)c4luz9l!#ajp? zx|_0F+=V$!?)>J$aH1~sAj-|Hsq|rK1%=s#MJY1@5NeEcmpvIKvo9 zFhARw>&nS%Dq`i6?JOwBYjWl^wYZC%;i7jJH{~}sIrE$HQAwIyErr>+g?V|XN;yT& z99UjRQ=Z~_ZYkyX<1T?mJajjKNqDO>*EBSi z{8p!Nbf4cWuw#iyOwZ{Z%}#e)jMRMsGZEArpb?DUjPPNOX%ddmPOrDkn7}s+f+i-$ zw?&q^dyJ!Z`tUVrXlX)t+j=_iRJ%Emotu?!Lg3wvolcW{cDhMvB(3Vctx|k6;9WhRnB`rA}rUD$fIi}(H1t!6+_E^cg+Kr>Pcsl)PPR#(i z)6?V>rYB)dg5B+S8pc?>+u3a#*i2uDbol)y=Ql?R@?r@wvv6~pN&6yZU&iuXrj-v* z3*%j@%_cc;vb+6F>aWvpQhUPhqcqmf*|r3am^e-900=i8r!p4d!S`YCF(+fd)fqGi z6y38ifiAk;={M03fN3E$`kL|haq|>##;E|J&c+-J5mBdun!Hr=&Jl61%$lJxM~Jmz6Il%yeDjlAjbf9V}bN`9Af zi8$!V8=W9Y$AX#lKIhVK(33X`{_lhNPH>bjJ$YLYuoukc?EtV1!LBE7DEv>^AxWoW zr_D%SCISLruKj>>$vEiA8vy@L1;a^w{m2|&f!p*Ur~2byByYe+VM+X`mtR7L;LkUL zHInB6H+5%hd5tKjYryUKl(Qpo(9`cH}k_JlBmtem6j&pMiHoGSts z$!|ABWm_u#x`$e%GqBS}f0;a1?;{-Pb0(Nu1P3(~T;zP)2?39Qxgnj)gBrT}eG0`> zhFPR<4&&S`a7Ox_cBDl*9XoCG*GRtrm>UFVq~C?82ls&~JetchD&GLg*8}Fg$((CK zx)J>%`K9yb{w$01D0bRp{WR?woo`Qp`6Qcj6i-jyt?)0*u}JS=r_D&-VaVW4FqVAI z8MO!ZKt>;!X$6sV_3BF+3~@1--%sb<2*iu%7pVtSUz%oEqz>$~(cegUMC>vO0o`CO zo5?vkfA!Km3=PaCFrSojt^iyl-H5zG1Sif#K5U$$c1cg(6G*5R%#3QzD%qj>m!rzd1*LBju*%8o{*ca*^^Fhxk4)R|w81 zzm$*L!TjZPo~}`Tha-3|m|<<4qx!6u-)oWIo4^$KIcJvN2Lcx9Z`f(0zef3e9?WaH zoI1bngV`%Mqx@2HHauvNj_=~>8s(Ro(R0CEx{Py1?c`+S_h&HU&*9ue%SG}_{pyckoV{G0Q9JoHg0BFxY9;5??U1@&4P9lC4#iFz{f+1s zNw*&YjsY|AJkA;QZ+AeUOTiRe%sDf=ydAPgA7hVBSFPXIV1Cx+BKnbC`d?y^yx3_o zvdeY^-wbBOrJOUf%izl_(irTt(O*5gIN*OYn3aOVaDj80_T?i8xC_jsYhtH6_Hv7K zEOy$A(rrON7MQEA;G9u@A3{Zc9?V%ca4rinjp}LRO=w@RN2ePp4;nA~z^shH4F`7# zm_Nk9-3jK2IJjrQ{4);jLonaR!AXCxNW-y5=T}{?4hM6A;Ee1{9m_f}>u%=q%<5J7 zA1zW1cC&O#5qL6~8w6)GpP})_V_@F6HFmm9w_$vM-7H-?kGjF^5S&qde}tIff3iq} z?uec4HDGQL9MO8`5#{$DFkcDID8D0+-@$iUq;Yr0PWK)#j|$Ex-Em0wDKH-i4&rss z-&6?r5lqrOJYA#yV<3X-!JK+8=ZwY&Ytesf19R@foHOe$fBLIM8t@3`=x@Y+k@J$q zf9YTj*X1Jhc?P)Sz_*SuK;uZI-V}I_mOr(E$@&=Ez*hDX)}^niC{07#~(A7 zHx4q6eB2_HV5iNfJZP9(59W7Ia1Q3w)sM!RFM|11aAxv`J!z5V|BcHdd+O!)5coeU z7&zI+%0tuMkB69dz$LCX*KZmm%odCgr(6HlLGd1N*-x44mj@wtf_YDHMCfbH|^ReKJQSS)=x#2=Pb1j`kiqZARzE zVF>O3bMYITGpf%{$aogaac^>t{_5#>D-4kh=JkJa&Zs`S5Wnhe*abUnM)DqlyvM+F zyk{+-8x6V5iMUzo!v48qB+bqj8wt`AhPW zwp*lu*l9D8_dLRegLy}AX7UnuSfpg^X7XqqZWx#^1!p9W>^JfQE{h4oA3gge0T~1C z@DDj_WIvL(NHAvd-a=p_xI7xDVl$FQ_Ui-_6dcid`u!RH=YpBElgl&8@7dt$z-$qm z(RgDtGLrDIMH;({%QHHEseS%lFmSR>Pd^D_27QL{%jaC4(fOMJ38#QLQ*cJ@%hTX4 z15@_}muF_b%fMVIIHL9RdkFqFfvNo$muF)WF^uxD7|e*>T&7VzNZt%ER>2v`dlB3`Fr&UPmq+z} zwqW37o1T7D?@Pgr-NWS>l^e}x7J%^x&dAOmfjb+F^ILQMNZx8NHwey1-ga>Jf%)Bc z=K5h-RC*E2>w+UXBP}cHdP*<+w}Ekd&*f3NdhH~QBm7`)S8#gv`xM;cU~c)rTtAYx z4a{(wIAAl%FUdO&%+Ps2_cP>O0p_y*#Fn=S%wEA6$=eQj!+)|!d$7}H zR9`5+$K#}P(TRu6NFMbI%fQtA5?kJ7V4f13kvuv--UM^YujcYbA$S{@@Aq=fXrA&r zB-9Pmo20 zrNox^G?@N_%;lv)UM85l)Y$Sm!8{;1BmL-n+XCjr!RGSDflD5eAWgtd8~xSGFSQ3V z!5lL*wmc`8m4Y*pN9A!facSoAD1Uzw44iD!)9*EeYyfvvdTe=H1tY{6=Jz#lPYg4c zR|z3Mf+-&!;q>%-5#`$prt%QZr6OLWy^r+!x#@@NuIOq@%}j&S?E$JrcSQ%v@T?!e+GI-i-oz7|fImb9t1`8o@Au_@k%aVMzCS zaF2}R@+cn>yF})z*CTkqQJgW8SBZrGn3*7bIhC`G2J%AizaS?;O3&q-Y-i2-K`(+2 z1#^8q=SCaIyBG~hs31W)WG3e_!Rh5!!VL&#&q|QauHsyWN}jqNY&31oGSvWmu@o#>Zdj)NE>{d`xCf`oz>~i>`9R9*lAOztLEy!IAUy+5JUTzhE`Xgc_Nmoxlvcs=}A$hdv)tBw?Pr4#O`UpF1M)qU%@=DGy z5P$UKeGUJk!41F4T;6k-m{o%rNev;k%fxy9#SIBk+Jl_?J-A4I)#vYsM-!wB z?6k@DW9N~Yn+T>L4z2`DWgOfBFimlAZD6|N;8udUG!E`sFt^6R-3#WiIJl?5Y|-T+ z=lSEX?b~3kdW_rIsNTPe;GJMLJjprrx{A6yZv0z?RVf@jne|eC%2HZ3M;PNQHk@}~WcgRzmF_TC0_|f2g z7OdI%R`hgy@}`43@)^#W$vZ_bX8O_jdm6a;&zj4lcI;xon8~9P@k(%4KF8%5*{>5q zJ`#+Xyf(&+7|c=cb8e!6JUTy~-NqR>*`_Ct>hnf$_iX2^S^e837$HtqKa%$axGg)(Z#?q*2$*f3aE{g?Blc6bLxXlf9(LN~^3~}-#(|ll%SGA)(x*@` zOd$T~=|{`mbHPpeJd%%yei3=dhO|jAX7Z@L+6*r7UtFHi`9|eiCm1t%R2~b!P5Y9| zGb`UN!I;UTd2$ap_gCifGQiyoW`p32+WV)$Z3A=5*XHuli39Vs;E2{MkB8u&v^zms zhn+T~{F1zH!Swrvb4KzqQ66K!%-j=OUJsay1!p9WuK(Ty=Gkw}<>f)YgzqrU!A={Z z>E<^J!6jfif8ZR|TfO?15C60u6Qm04v>C}OLU1*h3;$y-uL&}a`zb+Mjh!~5@?DIC zZU-~q7tX2I86xKg-3NcJV3ishCI^mlQ`vl z1@5O9@<_ii7ScYl8RhpFaM^-2$}j0x9jCm7;9N1}k$x-Ul-CFDx)}0EzenPf_jhoc z;*hs1PI9=dIf!i)vBfC)l^DCGkN!-?Eb~y^n zRKXd^BfC_BX;8_F&M(=;1Ey1OW_DRF7(`*4o?WPX&jzF47MFna`NmXBWqBeJ1e52$>le!MIqoPPPHf*UPZqkK^L7J!)}I5WGP45lT9JSyMw z!1Sr)>D%RIFn0*f%q|ZICX(N1c~rg+gWD)rvwXY_Yh%&_7X1!%iEQ7o9HE z(@Zdv1ZS3ye8Dh*_@h@(seFr~IQ{Z12UjClqkNEEI>4+HoS9v&2J^=l^2jdh!E98? z)3?ieU_KI@kzMG1kS_%TC)@PwLjA{{C{EulKY<%CfR~$*T}a+Bg5jwexA#-P6~~ZA zc3uc(so>1)d@h(!40&YdJHb4lk{4}fx}N_mm{((PR8Kz<44iB;vh$ZwoW7mE2bYj+ zZfB~`8G;eX8uqJ`!4<`jN9DF4PI;$+J3WRxYX2?*bFJXa%I(i!*2R!V=r zxslZ@1G(+sWSdcWB!Np6tkHQyb{+}lD8U)ESCnFbV0fzf?GV|e7@S=tPrn|V3dSQi zlCL*EqIungVAiPQMcak+zD+Q2vQ5t}WQW`JxGry7ps7v7JW+ac=$thrR1ZPwaDE__>X z9mVOF?>uk|1#6@q$qU9QZw0u%81kq+y&KHm1!rczSHWzHA&=VAU%>Pq#O-W!e$e?l z7R+%mIBHL)3kFWM>Dig`Q3`H>N}j%*PY2T_I3qh#KCT3Fqe@=%c|`i%4`!X<%<9WO z1j90cKYIC~@_ipV9N8VmAgNB;tm&Pv>1Oq4AjPjceZe|R5l;2ap zc(t64etlrB({eibeFV&NT24paPB6Q*oJJn$H#80BIdRH4iQ@FztLwnsCRn3)egVA7)5S&>(7%v!zW}8txm=wk7*MnSevjuBb4^E9!o*Ud5G31e*F9UOn;LPm& z2$-j0$Rj)N0P~qjUbLNQyzwiTe#3crnAv%#V3?8dN6*eQ-WV3e>D&1Ta1#YxoSs^sb0`LAG}ioubc z-xN$FztQr@&hJNY`gZ;p+&6+XvJ2Tc?U4BFd>FX#f;EyycAf*~WWkx)xdY7d81l%@ z*MhlOB`?}8RG%LP^N$!D+4&8@z{xhF`utuLr*G$-;C2hv$S!2(p(Eq7^P%956ReRu zx(-$W#wj>6I|sq6h#`;c{0A_1sN_Z4`516dfY~89vZs;#jvJ-TZ?rtB&&Nk``gSe^ zS0-39yEws|EjTl~tO0Xl40&Xi$H6?Uk{6v1s(){R*%=4-Z^0l6+w|;5*G>E5q0=Mi z!BcEz`N#n?OK?VZp?oxgajWD-=Yz_#2TZTvjQUGj_qkXwaI#G=A5`xzi{kXl_j+)* z3)UzfWS3{+l=mLET`}a1hr9t}5~bs@(`IJpGBDMGGt!UhK|7e`DlXd2W5Hbu<^jRc zeOr3=qx0i!Fdqocs66Pol`p{jAUK{6{d5P7<#|OEwi%^+OcbYIZd1S&3s$y^&U)uU zjXb^e&dJc|Byi^m)~r0P1#_$5tv|yBf?NwVXyCjW^bVc~@{|_WKyj zH*v^IJ0ekBwsZ6VP%x_Pbm#EMfdHvfuB){V9e# z((maw<-G=OdklGGzhA+O%;0u0>lY@1DG;2I{it842Xm@QUUa`e>vd;0Wi+zo;?%g23So)DZ_KHdiNp-Nt~el)K80nD$0Gs*{z>ypQD8?#K{ zk6u3L{1^;woM6rJkq^cyIJ0~>z_hC5MdyRc<18>M1!t5GO6L;6z{xhfd{Db_SrnJ0 zd%x{9;BFDDQ9j5n8^FA-<#f)=Jz(}~In8-V=h5LuB}!AU(P3M=*%OHly>cIEpi{Gq@_j%68V7S1i@Y)0oL zD^z8hQF)95H$|{=JFz*OXPFEw3xUawrpUCwylXo~6tKiJ!HGt`fL*6Pdw`=8T>H*dJ z#{~l?+l&OpBap=!A=~BIV6x>$9%J$Q6 zh2Xx5k{52TA}2bXm&Z=UdIWab)bb)6wY#lg&JvukpU^MD(R%C!U@nirQMxyPSuZ%X zog?yydkxHwf-}=^^ds&iFgpZimhN|8 z#^lAWr&GY3C^$3yykJ%d&PYEx&-=jK8ABe~?>R7^3(hPbd%+x?&+}oXpA}4l;LP-M zfH^aUJkswvFi#53OuwyQzSGL%^%PS0X2W540q*y~P8-*+M)!PkgXvLm`u*D~Ft-aX z2{Mh&x6NSo2u__3rV9H*8-pYJodV`u!O8k*AUJhBK%m&@{T7E5@jQh6B6bP;;9W*=9t&=kV2$Jv*9ayM2X{G`yW-%U z2eUl}N1vJa70h3!@x0KuM=u{4@PBtkqVzL%+GIOx>^B8rnKNVCh05c^IJgXOK|M}W zzSJIE1@3;qn$@dk!0Zs5TppV9h`wL37fkjno)>YR>(1Y%gK-E>PFG_Wdfv(}7&zIc zXJ^XC*>P|*ue~k~j_T>Xad5Q0_V*|b<7XW^KMU>y!OHp7a8$nEgBd$pQ(rW8&I4Bp zrb}>UcJ2jptKj5xHS#7y-a0TJ#UbxYFvCi?ezH7GxzW1vv4Vkw zJPk*7ae!GRIQcx%y9tMUT_ikL-Lx8J>H`PMchA8jkF|9L!CEGqN+ach7?PMQ~I5gt)6^@rPAC{A5P$UA1A6aeyCJ6@@7@9KMZuDmOdi)y zo~O|J%svA%qJrl`tzSeQ<>Lr2IciRK9xwxpEe1#BQ46L^a2or``W*}IVlelq<>`)J z9s~2Tnv2qp+LyP$q|V{_rR%5>J4fL&2HZ z`Cnixb5-RLl@FRP3<5JM21ofA2c|-BX8BkI=4`>q^+l6kst4DD`HSF0KBDxa^YT$J zug8!_`t1QT%Et3+rr#tm)q<1t)7Y8jW$j?D5}cWx{{ZGeH5ZkSa>#oUjK$9NOUCa= zd!?=iCxQtI&MY6R!Q7+eH2Ek+Ivck)B`HFufPnS$MrMfsJ>)_sSuo5eW?bsG=@A%cQu%M1ZQUF4PbW0kVpC@ zR-*o4r_D$|N_QNX3c)4ew~_tY!K@LSnSQr{*(f+O`+WlDC&8KN*RKlKL$T9lrr(KR zf`T*CZ#9^E1ZSq-CNSFsXQtmSFoWmE)-NB-BEhNkV_9Q=sK0C%OxQPaUWR@6cQVe7 zlk1C z_1X12&9EQ6Og$qbC&mA$UYT3=?Hc9gTD!y9l0+zx-h=jm87GwUc5rpxUL zczwEzqpGgVv7n-MW_EFwo(zY*zM|GzUtQ}cuPAMp>!_?)P*JHXsW#XV@U*)tJxxBR zuV-dexud+N!`bd})wm7CV<@Rca zy{_7^&|Y5QsH>?cv(K?t)YehjQ|$B0DjUixra2rXC5{?bYh6#fqa-V z3%yBMtJDhE8UKi&!A?#>rK>Ag9 zC9y>+V;a`fOq*6}pX;cYUv9U~cU0GwSJYyOZ9w_}8h=XjtLq*1s+!7*s*3sb73IoYjK82BSdI_sk+`)QR}Fvt*x$=Sl;JC$#ew&CyUgrsjjov z+ZR;GUib`Z#ayfG^)sUy=GWQh&PS@Li1;h>vd+ir-pQ70u-C#n6WwF7#O%l{=)@^I zgPXO?+YxYjI@~@-r_bBnGYgik@^pCGgY6Ed-`T+}?hJUm7_g) z%hkyod{dT2(x!G|Z7zMHK3t7!tmWnQ`E#X_2zePH7RhFQ z(@^iIt*Ao>B*Oz`F>@-dbL&_$WI>0VCe_<&s~0*dPAaRYskc|pXEAt4IAI>+P$atq zG4K^SoZ;5`hS~~s+7uX-HhF5(rq=9sCaK0+SLa~jD(j@N!aG4?-V3evdPjBX2^D4a zTwRKSN2VwWy5`zN^)|AGAFJ&cKXdhaYW(yE((v>hw)E`IT|( zvFhNAW2t7>IomPpK$UhlJDMFXbPQ;En%dk_=Rr)g)Dv)dJA05^2Sz+W7f-SMzmTHS zPv&w`22Vh8y3Mr8h|06yxOslnMD<7`V?*EH?(8UcyS&ZRxK?_-OM{&i9RXj@hY6HSDGT2XdsS!O!hicFIus>>Vv$lRB~wh;z%#XAoUwn?U0=i)E z;wY^yUnJ8Q+f>)ldH|C#OwdV^bq*FLXcCFR8U{{~fR~`N#fnN6mwYTzWySot^){YA znzWHGQnJ_8Tj!Tmu*As=Q$^v$QOd{H$8kH+i8ra=I6D$wP>;7~AYRZOLGc~4C+fLWk)3<4iE2(0opds;kfK$QuMX2_8& z*gFF5B{b5hV`J0~=qpVGMU!S73bV{+Z~OdUdz0H&k2w=&y~*h>=(FV*0yn!$dro%y zyr?wE=|`g|*f^GEThdhcyssZqnaX@`V2(G~(af~ktkVh0iA)0ok-( zppyg2r!*en_hc)>G3ECMs64GcpR=dN>BFF#47&*AD=M}c7S|E%)WBJoMoPz#k}Af$JySy<>xPG4Zv#&raIPEWwk7lQUpBF@_xka@#wtxUx! zVpvzOcqW~S*tKDeuqf5y47LTrD~ev<{;LMzP;LywH>XJw8{j#*yq;!9r`Ll<-Y3-~ zs6L#soa^73;ABWWD!O#^7gD7Kpv%Jafm@Qpz#=()IJy_~bm(>69WK74CuP9@8Jzcy zh7MP&+qKk93n*ym9az)%Q5%h+S91E(YC;Z67uq`NT)4zSYlqShcs)*dm9rBKqjU>? z&zCbqtM)#0p-83^P51s(FunkK;7l_)n-4E4aQa4088!gvbiz^r(Mlgq8BsCSoldNn zieTz7+f>0kfcm&_%Wd!I36;<5xSH1YuywenXP#A0$eM#GIisxT&_#@XDA zt0r|Q<90XBDb{Atx@9ECx|~o!6nP1uD-WzVQ!o73Ma0;z|8 zJ1TI2+lTQOMhIx!1W02cS~QKQOH!i2Y18JkIhXjQ+2H>b7at|ZiK|M@Z1DAyN`N&O zXhm%xz1+tI?RqY7@o zRkk3m)nTvmq>EQwmSfGRdA;|v6S?&y+{ zazWEFb0o(mbU43uL~_L+Nnau_QL2c~t3=hhc^`^Kj?OMxxQ-|n3B)pD-z(pgd=Vy@ANIfqKeEFultzE(x74hGPSAWnA= z8`MeoOk_lF<}c0~nl%klh1RjFIZEbeFe6nAN?TNKZ@69&G)@bNIxR!v0OhG5Qtsp3ork(-tNRzW~ky?m~<8d{~g*X zPo~J}Y?O%NdWP;INgNW`%E{$O{qp}+>X;Uz4EY)l-2u|+ZS%N#q?OPq8>WuWA_`mX zzfqJzm|d=g4oUx89Sp2951KuUMeIlk?|%i5ToCpYs;auZ4o_qcL=tHBYLLiAXsl{W zBX^Ie8sbQjMm3+hk5)*04-42TiTl(#$CVCJ>Oe{_X;a#dCOh8r?nQb}%C^$B;}I$Q zU*>T&_mPB5ih=ro`OtUeZ>f#yGf!%PybTAwLaI|ixl;drwQOhezR%bg3b9lzAA-<} zWuXVG@D!;`&YJZb%TFN;DpL{CI@h07JsU2Vvxys9{IAjt;(aE~@0|wW4IS?8PK+99 z3fxQ`EG;+$4d7B|Gh0<4j(XaQjJa};Kj6fw6rou_uTr6yOMCeoOMl2sv*~(Oebt@E zs%t$T5dQ_uK%^>AZ(oV^srpuDhjb&Po`1D6IDBb?7Ikb`G>nXo@ndp!fugIL=Vuz{})7M8w zaapeJl{Tt-`=|?b(U+-o*@yDom$amtkW#BErEspJPd;|vVBWqLMpQg=doetG_FW16 z7V7F3DMJ=vpNr+UXmtj(I#;DtoaM9MiL!aohqIOEjY*A`DxhGGs->1~P8VnuOBd?K zT6L%4Ea_~Bc~UhQlf@{jdc^i7($Jbto91)l!g6!G$(JJeKkrvA!qdrF(lW?+{I_Hw zEGj z7@850POk85h1_Cv{tR za-DCk8_x#OMIySO?}fk-zYmvaLkAud3gFg%42_!|O-|QRZ;&qUE1KTlYOXdUIPoAR zsJ0i?G;26Dc2PTGIc={Kj+rr0F<3E%W=Y>lc*7$e(6iu}kvMYwz)wCH9rBEvxqQ*} zP46DzdaSEv?Bb1E-u!TK;|892@|~%V z{B`e~-u7X4oiyw%)VAD{Zd&#jvt9wSK}#_e7^)1CIW)LWOHxA=0`oiD6e^3$$yd2cEe0?OUtx zmB~a(cU=3`sYjnvFktgFdH0zuojm)ycP~O`7(*q1`7>_V>T| z!}*q$M{6Iu`}$Mx6${4Acx2~izwbBVjWbU@zwCm*Iq6%rFFo>yx3~UsLDOCN|JajK zFG(LU&U&-^)ra=Jd|~jE@$0&`pP%^p84Z{0-Fe}e=SZ8*JE~(3%3~TnJ&}<(?DK?I zp8R*+-hU2G?R)nxy@NN+8vVOmH>SP*5-QbqjI+%B;fSZtI&a~S)2g?vJ>t^icYpcAk-f?9 zJ=rntyXu7*3+g0kVSh^Z>{Z{j{?Yz%VA=8SeR<2w%0qv6DDjToyPiMl+RwlB{bAAB zXX9;wjQeKP%%{G3;H~Z6pMU)&aqzPzTsVHw!X8_ z-u}gw(hoatpV>F?HN545UeST=_c&%G{(A3KU*Biz|E~$&wRcx9J!G5num|=`_q|Zx zwPpM6ipvvjkfd)IS3B>n&p!U{mFYJO*f3*y-tOnGJL9#)g+(Wq{57xjf*&6md>+2~ zjaNTqBz9*NZEj9~;=PwHU;n7I>8FP_CieaP)A9FS_I7#M@Ntdb-YH3I8MpkXnJ3;J z`mFfl+n?Mrapxs>|MK>NBUXImY#5xGI`_vX6Pi&jj7xgZx@FL3y&vTKsVw=-g$q{h z?Rnzzi7g51l7hcn@mA8t#y z!i_dkDjXq6SvY5(fV)(<_rSeIxUWOK_zLdPXiv64kMV~{((?#U#vNNzg}W55t;rVd z-N=8faPJ%@Nv8?-V~Fb%?iG*~6z+1^VVQ701!lQ$<5pN{1>C*RZ64g`!@U;A7jT|G zAebWL<3ZuBfqSc9zQwumig14g_iKWwL|U&a+&cyH6Xfm@{=LxoN8!E|`lO8H`Srtp zkZ^wi|Ea<~0W$4ylWteTzgoDrK+ihiMsZ6Eg!>}6$B%(bgdYp{AIIX$V#wnXv?F&4 z_mK#@OStzUEC=TuF-fpnu5gpgJmKC9cM$I1A-n?aOW~&Sx*Tz?7w+3ojyDVbYB0Ad z{0AM*`7$trh1&`D5aI5Gdo0|okV$X;n+Z47nU`?x4muiNw1fLH*gsXcFNQmiiTmS` zk6qwh$8w&^y#?+tf9`mmFRIh0=Amwb$0;P;2sgd4a53cmLE*kzxPL;re^$8H!AxPbeopN#VvEKzbJL48(;x z(sRO%WToeY8$~E>6mEL^`U}Ec0QV;0o(cC$!hIv$n}z#TxVH-TH*miq+`q#8u5h0Q zTf8saez>;@_nB~S7w*+??|_@?zz;Z&J`!#!mz~1B1OA@~H@(#GQw6gNZYt|FNcT&) zsm@TozJfa$GVjLkuLaYDy0=@n>)`%Ixbskd_9&R|g?lKNAA~yv?jIHWPjHjYRA+t` zZmKiCDExm_`0s_A^z4IfxJRA2C&JkeZjwWFtiN#E;7(Tf4^;T4z)f<_MBG%kDZg{z z9t<~aR~?CSA8x9LA+!@|3imMKrusP?ZmMJJz>R>LWDbTMMk(A!!cAKrWF7@K$y|$b z@Mz)wE8G*{UJGUy>@!K>K3=$gh0Gj{{TaZ8FkbBHZ^!hS+dY2Q!8LZkm+is{geO+CXI;kl?xKPTjSH~^?_K84n1@Q;n4Q&V z7pGEo*3_)2IXMM6*;BI`gDzj7(S`fSaCD&jTzCnCpDTXgEbMQ0`T}@-;h-9%i`{)0 zWsC#Y1hI#$4s0#quY)$%wTq)8oLosIoI7qT!HEjxJrGun?aFJh%G(h;JNQ2=jWL&z;9U}Zvq){?= zI9w%+8z*ze2)`8RIGLLQ*G$G`%Ur(jOOXm?ZYErLjI+Wundw&{{8FU3!ViOX+v>K= z(YDor%na)S+o~@z?4ey%p|5SBZ>pwm2#&CY{$UHXWtP}NflQli)zcZ))1K-*E3*dC z8Z)zOtIx_T3RK$8|5q?6_nprN*+MUU3ad%B&|CKDUsi>ltsGkVjP3mI1NFA^-wC8u zoxeT+<_%kD6T@=X+d{wELoe^S%NBZ>`FuW!=wZbLH0#he)&1Z^b%}MPk?LrD2ja{RB*%`E~=YeV5=F zAo9aIH<;%N-00sA_mCV-S8P$G%hR*qKNNB@Fb%gz-nQl%JViPLk><&Q#xTK^_>HL? zwsrVD0GXY|-k`uD(VcfJR*f8MB#X5Gzp*%qZ3EsIVNt}wDa&G!((^%K+KTN_98;O3 z6J<%m@p8pkOi_zOkF&acU2X`kNUsJmo<*ZS7M33>)o^|=nRPFt{7@Qp*$AC@uxt{O zNiXxFXOla7R2evxd~x3Vphe*RX{jl=P!Lg#R(<=Yz>`FV_pu5zSfNJml~H<(P*7n#daqRa zh85|(GOPt150i$aWsp(DmK=7VX-LO&m96QtT0rTNo{iYa)|3LtOT|u0*|daB_8TUp zv+6wVO_NVtu9B;#smIQCd@iH9m#_>uV|BU0GaKv(OFSR)&cQTG8XqyHxrOA~d z-68uS1`ADLmxDOBUiPDIj{AKl`=RO!zkb4njz;#IB>NT0e$!>YQ)NG=?01Ij7nJ?3 zmHlpz{Wi#c&&YnC%6?zSem}~7Kg)h;Xry^QMhI7mgkEdBtK0tKYw4u5gEN z9g<(F=@6!aqHsFW^&!6X@~16C3-5N|<$hT8YQw|)Y<9}u-|B7_w^C{D#|aPTXR#KJ z8ZV3F;P3uaH~rJl&K`p+0<+lb3UN(=-51VZ-$|qm`X)1la`1>&2Huq-lV~pKl?42K zv#cSe9tG=p*bW0cD}6E2g~)I}L9&h^AB>8WEf8IkMB_MUaJb!iX%uh$!oSx5pmtz9 ziyZX_?LZ3J0Z3<;H-}37M7x`oSvemMWzz|sg+MYxwMCd=h*X?TpE;$?f&e;O;iMC` zmHfm;WwI7KH8PFZX}bs~5S7=(IFfBbI1a`UCtWXP|93c|t)c4(y_Da}ah!nTwK!6e z6rPXcB{9K3{Y&;sh7~xMDqJa&7p}Y5$?g}f z6zM9NqZ-N6y-)UgNcOW$+G-E2w@vy-C5_&;;#8niVN$eT5SfI3e54aXluI-f8^y@B zVfagnzkCxFyNq7aNw*m-!%&CTi`uUzwxr)TG{Vb*{`xM z=_&}4a$jMUZV;U3L!n5e`xrizno37qD{XYf(v@hwiAsk{32lz$c&!&zIKNx{oCw_$ zM|C0yTcEj=%RDkr9x9hH!qsKWlSzrQj9)*Bk431ADLIreOODE&idZyNJPF=3QGt%< zsj$D4PbyISN1}Yg7583pg>a;Tq)%+|mW5m?l27*Q60Q{K3fb=(+3#oB4~Ae;QlwSI z($Fi{KNUXT3ASoXk84zHqq;;F`1vMGk2f-*`@&n90)AEkGuREU)J^<6irISsdr6IQ zUNRttHPgjeLIPkx5};f6NiS{P$BhcTq~FyzlD^jplUZexkt+pH$RVH1?{wixp%Inv zyHEDhm}e~lPB1agprZk>&B#3REKau5$U}dlok)PfPTD47U(7@wP~$a=TCqINchG& zG%dLzWJ`u4T?&;ZTUVD5mr}m^gk&abB$uU?A=lHdaekbkDF_eLp{*7BGHt(9N7lM*M99%D@OC}MhK3Ej9JROnNY7OwA9 zG?l`0z>&QD8;B#de!>;-n!s5}Sr&Esp6plIcd^NL>qkd5bpyCYGzJM*igdQ@w?g(?Bm2>img|Dm5fOKwaHU9N zWWU2@za(hR(?}LB%m7zcW+pGh=Rg|R8s_-Q&_@8J#lOK(7$eihpjKQ*4{Vc5-d;J zC%tIp zLX+(F(2JFQdFRv5d3}?QwS``N$9(r$ATIbJqyGZ`r=;AKyZJ zu#VKLoc<=u<^WPL#Y+7jdbWhnT*zfT;Lz1j8DS;g+E;z5Ou!ma>#%FxuY31GffOzS zeI?{rNsUsLHpxw~LXlmU0kp54We+`DwR#T1o*r*K&3dY}(ec!yREJRYlh{2=+(iY= zU38BRca0IJR%GPeiowDKnr`)9II*bJ+JWOKXxjKD#y5CtYXFaz;I$)7Js5m9d+;@y zB|$vVeUSRv$V6^9>m2Kmh2c!2w-WRwev!^~3ga8VPhtEMjMsLybQ9%aEPSX%-T59S zcmA~Y(H5RrQUb?f$HKpbx-4qj0famMDg-SiAL$jWCtK62(0S)D{4p#~43I9x(n%Uz zQ!LeNX&v6TI8vn1fXH@9G2It@urg>+iy=h7c%(vN`5 zlVBf8Wg7+y36>*RN~{x*M&3|I|b)4OP+x&BikL$Uze^0vHAt zMgfTE~=$6^(|A1p~@JMFG5ds^h83l>&p`yJBNSn>}~?5RD#hu`sgR(dz< z+Z}ZQcc*M^T5Y8jFY5i3E7@XDHE>1FFhwTVs0x1J!GunXekm`F)M-Ls3>LW!!S}JzfR_Nwq-0Ti4zs%X6#R+qFOA& zrDH5(qzY6N12gnn@nDpS@H12K8K^jLl+M5|tm0Ot&Ir8jIHKZ%%x@ZM?g;5L>?@$& z-=OXXxEPfn)Kd;+=~l+n#FcNRCiN#>bWF9fUo1Uv!35g~Hoy#<>KNuXl$ir>&KGNu ze6-g;DK%;3F@uUAH)Q~o!w{29<}pD>sLCOH9%Uk9OOf#1*k49Q2caB}M>$lBjOyj4 znG!TBc)D?zT1gtphjT+WBGYHg$V7)n=cfP4^9D^DbR5}fkV#gqVp7KJS5~4@O-NjM zFA_{60}dQvlIp`O)uZ++Rqc9n2AP3vG@74?(fmOCQjX?ZQJ<)xIvqQmYgE6wvC{~j zM&n{IA6d&=9PyNg^R4jH8_r+EDmMbLQ9nx?ttFo&{KsQhPQ&+!I3i7H5{?*MvEL_( z-wopTV)6TM#GL|e5{_9o&c-ntM>~#rI4;C7AIHTw7U4)Ob1{xo2WQ|&ZNf|(yKtP1 zV>gag9BG(disOwq5_cDlb{y#hormLNI9B2K1di1>(xsak9CzYK+&4JZ!yEwbNV zWIrk`E^m|Uw^{c4N%q?-`;CWvxPFs`D@7`j{btC1O|oB$?DtRE?>*U%>N%IUTlO0a zYjeMJ;YyJ{lKnoF{eG1F=oSo$ks@7~6pkAbt`zBd+3yds-%yMlcpAfnD@8h5_B&4Y zYm@ytWxrn8kDeyr>AolX?U4O;%YO6(C+7+=59jGl7p@d(p6pjG``sh^-7ouXko}&K z{m#M|oy+SLE}GspW+v18GL0s)xLF5NJ$qmG-pbG`wypU4Pu#6z3%zZd{^r^9h8|gh z3FnAIZGEK)n0S`h`%+g~L*=W!Ew;?-ORBXU`VQte3AV(y?R_IwRfb;06!#RGx+I18 zRHQt_<|5O#o%N_~`nKQ%>-Xy|!J{cEMVQx@T0(Sr=-aBk8q8#9_EH}D8Pga0^l#3d z-NL4a_P)}+wyi%xbO~m*A!}$LCY1i8C?aORskJoANeV$8f^5l^p)EA?n*Q}!&k@1Z z#8fqzRHqqj8r^&}n(p?&Tr=Im=7rW|d9m<0)RP-Dvzn2p-!#~#MV0W=5|R|2)!=>q zt!^j&c=0Vp%xrL@w7WaLMZ?GqKSnEy`@XI?j*U(0pz=7Vi^ove*p=ozxL{#}jx0Pf zH=?C68lZsv6X`}D zkyfcUfY&dx)FLyh`&epppUizsatq{5WGkU(^6PZrO8_TAA-;{Y(BNA+`7*klXFMVt z85yWoIlCQx`fw(_QNIJzPJGU!h3P}{qR~wHH!N*2vak2@fjvzIGFk8r7R)D&4tsMq zi%p&5aV&Ts%MINu#BK2$hG7$MyHI4rM-RF5PfqREd)uJt7$YSmreTUQ3KN-ugHn@l zyU%dSo3e1ig@JW?Y%gQ#alfg-Y3!rXk1kL?!lLIe{cN(eOHq#bsLB!j#5^UX_wlF! zI{d-|bUK=>ZQ{!1Sd50yim66JUgVwfue-h(zLH70W8sojOuDy*ibeQ|3PdZR8SteF zA}(D}WGZasFew%9dZ37oa(qSs;|5&Ir}LE-CBqw?$F!wkzl6EiQ%}8gZWoM^dZ|zg zaiqd5!Z8oWVjN3woPpya9B1OV495~2SK?^Jk*-jd;&>a56*yA5b8!4Y{H7&M`kjLG zDf|!|={Joc>}YTJD1uxm(o?eEbHbG(y(;_Bbd+;@WIsxU`z1mymq$yd+;5cZcc|=_ zEBn#SIGl6Jes0;1#tB?rQ1-i0_M@9|c-(ceAC2d@-)`COJJ~M{eK?mlLby_-<7K~G z*>AS&S0?+>Jv2Nn?hO-Z+$#Ig4OKkd&9dLCvfnn@??c(|U09pT+b&$ZXXH1piq&81 zLfeWj?t^`8A*$SxE%#~L>hm(!!dV%@+U;&yD$cU63xD{`K7Gs33(rA*Z6SNIZPF0? zlaa;YXRzRlm1O(YpY5TiY0bAXal0)vKaH>u1*%trLoe92?qc^{Y_Lt=($&u%dJA{N z_8pdPpT5mLv~(Nw;u-eoZwPj@Y(gN5ZG1b|vn>U0t3z zK6j(NuRPOY?@KDTV*z&3Yk_faUx04*Ji;W~b0t60adon-uLP^CpIL%m*h1$d+vz6T zA-3t81LJ8xAoEyy#1d=xx|^-97I8MDf(!1f4E3+V4O3GnhxSR&>*bJE!$UvjuHSPv zmZiC#s|zqRI2S$j1-8}mp+wRt!i`S*5@vQ=E?@AADJ zhF*!vk|b?}E0MXj!qvcHyaN}_ag(Ia;kt>rXc}{5GWpRxXXmgO7-O>gf@$FPjAo#L zMLLNZ1v*Yd%gHxB(BSuc#WAjkb#HJSgARI!C3_{5AGhk_GxF>%NqT!dzab5MG+x+E z?+S7RoJ(f0KGMOu??9`^&n_}j6H04nv?9qj-WO5Vn!`LcTUKKwk}gPY$8Wl6m+pAL z7-hbD870f2M}{fKv#yNhqsO!8uUOVt_)W=FmedP=SO5R9_a$&r6xaW~JA2VHFuQ<) zs4&1PD4>fRawzU{$gD1h0v_=Igyo1_!g6>-XIT)}aTOC2O`;JKqee|)qCt&`f*{~6 z9#InyJfa}}yrXzT{@-uCs+yYKnPovt%;)oO=`@KE*W5-Bt;=}Oa1))emD;khlD2@DS-cwQcf~1y;nv<=Ov|2S{?Yoi;r$E!Q zxfVH}3eO49L5vF=5HqQBuU(vHImx@AOC(g=9yys`plr*bNQ>4K*;v*{urk`Po-2tG zrA;YX?sL3^x*zEpx+jR~$Fz)&D#SqDQp^)!RpGcw7RJ?w$|_v=sA0;>9^AxZPtNr{ z1QYA5yeyvf@rU!{k$irjn~9t`&P*)BcjdKmGm&$+k%_Hp%iK)l3~pj>Mv-<+o1Af9 z&^AO%@K3LuO~>%CslIejk03)sV2AM7*YgS3c8t$qm@N={&$PWR+(HpNo?v$8z$$K_#n@?lH)*bT`<6 z15vL^6t^X_9+RV(H9gnKLAAS?VZIDWj!CBK_zMA{aJv$xIoMZG0HiaTh!I$hA>T_J ziTk&3Jq}kawURgo*AH;L9oLU=eI3_NaeW)tk8$0O>zBAvuqBS#pzbN&?8H60f))i{ z;^(;fxNgGrZQxJf%J^tFW5amXJGKO*JtCSavWhE0+TAjS{XN0A}CVr1B})`#4iI8okk%rT|dJ|iF# zl~178p(78Kqh^(tmmgCq5?lEM1ohdIr>6p??wW>LfmX=kNm-i``msX6Z zz%I?lSBx0iC{ex3%fE+u)Few7-Iyhe&av{C%Mt)n&N7}xWj5!e4v`-~*wsc9&}gqM zai5PX=eHE#O6EEOfkgQwldlrL-oqm=xQ6#c@OO>?r(vgcPeD4G_6Tv2E%J;ZD+GrK-7ESryB4|Z|ou?^y&4T(&g}XyjzPA*NN78b!rhM-O zQ1a|cnu2oPaOnV4ifuU6aP-wEfjk(q$CnmQ;7rqa@|~*W2wWy$*3PK1tqj-a={^rD zVr2*1<>1YEURO|}iBW~#BX!^GWviDj4;~Estug+Px z*H!!*RIU$KD*hLk%4Qs*cd6p%K@A;J(mBEBCsxeErtMR)Msmt;iH43hROIcfI!Et0 z>c$)t(NAVH4!n+zv{)sjJHorl^6{uAFb;H2{0^#oUcflO#l~nH_?$r&RGe*9CUay%G8uA0Kq0MSRM6fNU*l8r3&K5NY-rJzx;u-))!nICe63;~u43i5 z*HmEOva0CTi(SXj-IIyR>F#vFBPNfA({%SE zkbEYdpXF-NTn&!8JI0aV2j}J;*J6Y2UR+!3>h4^LjhM-8b9HrhuA)cXy_eG656_^x zb6rj9?qjLDM~o1iU3V{2U)fh>4s~~voo;%$-XN8zaoqNem7FduV0UoDSj5`OE_6m%W(F_$+BV|vWX19$tup4%PKeu=V+X4tZaR! z<763fB|omzHybBQj^)&Z?tY}z-N}XbNOz~=p1^4i_CplZDVW!2Fq7gwAHPv?{~fMW zwEu=H6?SqvD(qC;sj#ylQc>@PIH{;#gew*G+i|6${zqJmqTU(w-vdhMH&fKzzRf6B zg9c^Ns+usNyOHc(2l=h2>oQQlX>0!ob8ptu-%NQ==L!FD<$XA0WKrHp`5uQ31^Y@Bo>v^Cb(Vo`jJq`8fzd~b@yrdw=* z#kezpyyISr{ncU*TkLU*ZMWF_7W>j-J1y1)s=cJ;U`_d6e~S&WSP@iv2^Z0n@3pts z0Tvq#z2sxW9`;Vu6qI*R^6V{|^1Ujk`zNY!V>Jc;H;5{Nb<>pZEdj;#ufyI2n)1D| zQ0)a9uPNWV7}O^!+@+fGy|ci;BrVf4<$L#ll4t*-slB22=i$v66#rSJv6DE^e-eiI z>)tJgF0N*H^;lcU6|3HfCqIuLeHkiJ^s+lpp)3Dl#`0HURjKIZlo-_%D~uaxp@bN`ISS!8io&e z0>H?C8CX9k#)y49`Q%o-6@%ViZ*PT3Ur^!o{rhnwpvOj?-iFgK=O{k--_d0W)at5+ z#gWS7D^-L46(c89)D`7of)nlW1 z2_70=IuD@=>lYVo>!5Gtqt-aAB;-=t#b1hqn1A%y`1tu zWy7MKRd6|6QkDD~wuuuf;b_>iM&{1y`TmWZ(G9p=BRJrpJN!F<3gQJp4uzzF(jy*lictGf-mBSUh#@sp^8 zv!a^Mmv`d8zALJbf(4z8vtc(ztEk6-2}K+4GKG;1(^V%m^=uQEO>jo{ z3WV4fPtUb9oxm@+-w>fJOF6dENf$2+hB;XMVz2Kdw;!4dYKTzGbMMTVCuHVDa7H+Nt zMOS7g4=bU229NKnzvn9@mp%|EF7GUb)xlGc;Ur+W!pcL3V%4-EIh`?YXIRNe_>JM^ zx1pgfUY++xY*w;wPW#-B-cYrSkNh?=^ptm`H$7*EcYW>vZ(HsNEM1=(`RCH=w2u4} zigIxaP_1zmhbM%O4Ie`L1>pRa_~X~UjoWqwq0l}BMWOtH{UR+3`DrXSn0n;X#6RR; zM7(ozPxM}gPpYgEXL7?7H6BsEj4WEpGKK0(r{{L{cIF5MKw&F#3%%*NeAST&m5Urv z;dJ>K>SuVXsOzb@7`)3R-VQHk&d`kzMuXg=kqim1A5fPSx%+sh>hO}2sluO%xFiQn z5=N>xMwIklh{1P8tK%T}(QT42mG{k%_ddgn&H3Ay>Otffjq z`G->@pE&NKjtgA(2qeMhOzwJjbi+Uc;67VYTp=Uau-qDAIa*cjsHVfIjNk(mU|y zfN{?aESp%#%)Vfa+MxpOOH z2%#&wo6JE@I!@)I1)X9~H7o_0?JYv#tAlhHeU+QD!6ZT3y)$^?~AW)70vd&vsH46cKN+5%Ro}e-$ts( zk5G@(aB7m;*DJ>t?t>Lz`gw=s{3(;udEwIIT}!3n2Eg1ZZRpk*wkOx&oN{*VJZT3g zXV&VYyCFPI&l>{&omM~?E4ukAt!{b$Hlxa=0QknN66>tu-R2H*gb znzFYf1uE|^2222B-XNg#&va0~1c2+H&hhgyVC*vykR6K|KfeaBIVi{QAXB?cQAi-B zoKd!!k83%ui*c>Q^+H_Fz;!9Ef5Np6*EP5d};kp9XXK-aa|HO3x zu2j93;L2)wF0O~*{lwX^U5YD*tSFI*s!vK*`Vj0|{j01UDcJ26+hm_LavjEYE%uTP z_pZf0uviJwCGoKzl=mKDF|v2T23qWBi%qszwZ+iE>G;mI*m8^2TkIB#-EJ|uwM$yo zSnMf_(EuT7dDmheSgZ*7D$hnV<$D)dtj=OTvKU9UCB8c?cDKbgTI^Aay=SqHELMP$ zlK1+W^1Y50>teC~78_)-<19AXVrN-wn#C@**rgWxiN$_qu^uo~NLmipls z28Id=w?tFEca_DivDl3kyTxLUTI@-Sy=t*HEC$oHe#d7Pqw}G>w@_2QH`QV@ELLN& zB^LXW#qPBjC*VnZ4_j=j#oo2p4vT$dvGFjt$g`(t3Td$z7v12mShUSzS6l2?7Q5ME zFQI3Z__k=u_eS(tvkeUm8WonPM2$&lR&N0bE~kgb)PdKkjm6|HF%g?XW7S4XvZ|g{ zJ-d2NU?n}ZIde>w!TPcTg+$Fnjq|HSQ=|k79l*NNvS%^B8*%3s;N;}_=9j=Vex>5s zOe|wdh8qCM`>)wf4oQz40~J5_E_8JVa&h8#KwjD#OtxuXU@5|57D9AEx)%`mJOlsErqJ%6*}tBNG%Hsq}wHF(qF{K~;=7Ici)z5Z1k z4j`~&HMIRP5&%DyN8)R@<$in{4J4caiRfzD8MVG5=~dL{RMxG{1HAAliSwGA-Xp<449Q#yc{dpVS`<@o*hN^k;i1M7*SO*bbt&M zgNt{H1ln4??uSa4auyP#wl&t)qZ_>#{ER8)aey zvoMk$rX=G2#&snjTt(VN@{9Q!Yo=S7RCMZ3%$XkdTo=3vPx5Ilk9a0BivmO$Lh@77 zYVCj&sJ@>9L^-hFT89``14_BX94rskC25=+5QchAVw_dC#2VJvGbQaYd@U z)wp)k_pI@M#Qhjt@5J>qeZNxQv%DFe;f@ZOmO;u_HUPoq=wE#)j9?530}&Wb=R#-e{R>o%Z8}!3I+`t_Z>=&VlAV8LSCiZpISi~ zjUoHGsw}(|N~{=&I;#6CuwO!s;!bq>kfWn=@3{jv)T8)Zj;AIP89R{#tHmVin0l1D z)b|v~6}MA7iMxwN26v5=oD4S~*I2;qMWN~rgnf%@ZtMI=$q@+B$$6H$i^47uheuIM zXLDAITce=jzaE&iQL;XlGoL!Ze)zB{47T~nls~p9n)a& zLJ`?W$y(@wEkFqhMqd@d>MZsni(PFou3IDF?zb47#|5MFxWv~2Z+cg~m#dYK!Z;@W zO1LUb`QA!UlW>N;t2E_%Z$Xk0>>W+1F;Gg<3+Cq4_owi z6j_n zoOtc$G;PdpZT46=e*1lT6NUKlhime;GU}>^WAOn$sli@Cb?ajj*Qp=%HVo`6m#D7v5m2%X!*dpUA5;pm_BITYndBMynP>ANwoHPBXDKjR|mxVh>>21{%Iz-^f zv#@F0WX$Xlkdtk{VFaqVTn~9p_fV!s>Z;QC2`rc4K#$Z_jVj%w9+`OJ%;_^~Ap5#I z`4s2W!K!zY$L({7=U^a)$0aa=&cJ|7s!!rh>hK>N0JD6X@L>fVLV55Nq@@{)r(q^( zDAW;s$iC4?LHlrFLHm$j&<1B~genPzVBpWsD>ylle_+87xM>^+W7bzj|`LZXLnEhg&dIlWX4I9PF!3Y(|CjotBG>i#SgWFZzY9H8(~ zz=taQN$+SFUFTy1BzfL^bCJpe`fExaO!q?GI2DGAG=8j}ZHHalQ+dK&;bFV)n5Zjg z5$c7Gv~^yjpe>esi{uaGgj(*T4zu{Nljlr1ccPj0$kCJ+Rb(CT!eJ#PiZ+`fbwqIx zLuzsKRexXdjz@wUkd%#RR<2Vgx1vW!j|4E%P(jd$v^sVCp@<6;^sXao)hA9sNmVu~kF2|pu#&K#sbP3tIn=9e>R}e16P-)zqNq$ZQ zb;^{zDGGN`%Is8V@8Z~*r+0|SkT0VZB`jX-J_>T7DrRIi^=c!s+%eUo4qKO;a z^tkTY=P^VqQg{XfxO+nBA3}*O7@3OX7n%s%t*y>f9~0`PJc>hwOmDelJEqYsoK>UJ z%Xy54s`UOJ*1Ktgf2s6whApelp(b`$6yA&=dYR@amsxg%m`BP+R4k^rmtP0DL+F|BKRNi0X9E(?RN-)24 z5>6(VIm3))`p6o$;AF9Wf|E&OQS#-zaFR_Nj+3pG?U5~R0#3H1^tpORiX2;p1dz{b zIhMu)vP1H57!QPxb7PxLI_WvcZ!vc%D}k_1`HlS;gR#$}pu}Ts3(@``#FcDq9j;-7 z<2}P%g6mxdiCc(BK7YL#2VKUtCm!;;iZa0i>mXH z0ue^910_Q1%b-MPWk|vDP@yGUPf#MX9sw#{Xr)XM6k3l&C^9WxdxQDN@!b?!+3%)I zCcRbfK-sLfN_0WaHfZuRp9}*}gHUL??$ltxp@9yiWzN4~1D)w~4bLJAAgWeURK?k< zAPNz*RVWYQN?Qn|DUlU(oUF*&I@D4`RfKJcGlGy|Tzy=X95gPH-?fqWx+}@_$Lgz6 zlIccuKUYhpBa~!HX?L8$Ux9?$3G*~$pAQO(KUH{2GL`#jRx+(Zn3i}R3QH!*bpOOp zA(ps;*wfR^LAGN+bG z@$yLP!zh)i*SaCJR2m48K`P}3ghGd*1YD`KNJ*u~Ws*vN8t$G|Dm}@_XuFn5+0oIR zt9U|n z=`!Xfz6t3PLqy+)bh#fgh(&3nOG=hZBNv%5Qsv{InKp8=pk(=hGbc$ETjR+ zk`_`*i)6NtEQQ$)Ecu5jL-1d~#$xIUmF#CWAq*r9D^z|6;gLN2BV5UmKE|~NuDqvE z$&n2aDoKe@DHz+DU|VdsH!a5X4kaADEG1kUi&4B4Y_-K`zY}bO#U8QPD;9g*VxL;< z3yT#XmGWL+Q@%%sc)>baY`VqHwix!<)#2y_B5Aq8V(i%kqx+4-H(yg&D#2nGTkJNA z{oY~^SZtleC{#*(6e{H%?^*04i`{~PlW@0d%J-G75`k9!884C?;_L{DRVXA~`+~MUi8Ou6R`PHC)e zuH~*qigd^TQxAp~66lRTarUpnKshDe`L$&LDn3rbIkBP>30?1sD^N>(hV zj2NdOQ>|fmx)u@7!*_}J_h(Qd5`931aD4?1&bbg)h4(FP>*vEyIt;3J!gjk+2MCp0rPUcgeaG7spClq!$`C!tn_~M zcJlzaxg4_9`3&3`Ya3)|dBDE*WV}{vF#m>`Am6?=#n~m6d5C3KaxHZl@_*S(9-W!G zU#jKWe6JVslXfaf_Wjgvb76JuWTk;c3QNhgaz7WDaf%8t_BJrR$!fYJJEzlS!Z z;VPatu$fL+iB{xE+Th2eRU*i7D#*)tJ(w%HvlY6ixuUbY;%IzE${aLSbz{pE-1=kb;7;{DXWt!b!fpQKk-has0Agd`>7$(G-JHm z-2_^>=UECpMan4WCQ@6a_g|DI`nQIBbe0kQkwxi7X=c=8>V3KD{mdL`2jwWWROT4b zevy{!Rjh6RBiW|~a0PX3Zbs??ay`U$NO2f9h~$rRH34mJUettOKhuc0yB6&KpgwXT znmspHq{y1%naa3J!Tv(^aJpbGxs*|`XQn3ABO=(lnd%xqjbOjXe8w*2`t_MYy4B59 zwzO4w94yOiP*ugQoI!$TgP{a}s!H+_Fx^h7HO>RCFj-~3Hlq{|FGH#DK_R%kijjY4 zVm%8&FrATHA=sE$X{{B{a{)AF+I4%z{q1Y9q$m}2+*fm~TXkYeHO@dFvHe!^kZH0<7kUw9Y+T)e-w zC`|saU*80h+Jta1WD*whVxPYQSN1O-<9d+3@1^g{aQz&3KYc$CS3bv%i{Z<0<@4-& zzr>Z?b0@CKKoQ0!Fu2db^-5g9a}%rdJu5~C_e@I>uFvCIfGbrA-oJutA+E3M`*(0{ zf%`9UZHa4Vd=KNLszCdzs0yS+RS=A^3%13Ed(&c65F{L}*%FSbieQ|GE*LvP!A`Rn zT>=DKVKF)f2zIr_=p`=L8jI04Trf^fC*^ybUMpA&P5E9Qiydh(%!JV4##oH%gFH+1 zLE=kVjEaO{H(TsBi(xr`{pi2TI^Mey%4w-`OgB|dtNOZx7z z*gY0I8Nz~uJ55vY^|jbyi*jM?jBr>*mGA4cTdnis1}6_G;DC4O6lT#bt^D!<39_0J@7=4iM)7ZdhrY0JVY%x}{U=^#3WRVfHQ<=_ZNcrAki=A(= z6&7PxE8*_2*j*M=1u@C>7ad+Y);NnQ6%>o--^+JNNzoq#NPHtETXzLYqWo|W(PCAG z*rz&L+_IQJNxV3EcYX}ywEBuzbaj3gke5_+*-!!h3l576!!q}#;5QCy&*F_Y93SIS z_11~h{7!8W{w`lc7xjzpd@!D@LK>25X#C_3n6;$^v!uIEMkv>n5bYzqyo z>v<+0=%(e0(@U5}%!ED9jn|z4%ptN+3^AXW?>g72VWaV(gTlSSBQSm354Av$yhGin zwQAM!psb1%`Q{Po8z-kFN-Iu$GNnyvWhot03eo|QbWp1ZEe|pu?Wzdwce>GQMe$H< zlqZ?(dPXSIcYe%;sNF`=A>}`jA2Sh{D;fPH^_B7m?Oz}C_q_=Mes|onAeeAg8v6bk zi#N-UEsN#gF1JoAI9rIj?7Fdtvw^r)aW2PB#enU@^}A@Ub)0pJ{={REPWlrU+a;xn zORGlrF6*nhEAoS>3EN#!G=B*Yk95&IrZD+K9<~IW4i_{*IlhlB`a_U^!8tjw&R0Z- zfz03>iAgDc;$3&?X@0e`lK9jFlb||y<5wHA@fRxV4=pJCL^+z{Yx^JjhJHaIW$%3h zC5wGfKB8if!emX0)oIH2uCUmTEH(u>CeKdS6huagEw&id2?mn;^8xG_#WTdFDF zyU=1wE%rl;{lsE#f~rx^Zq=0U4TVT5*s+@Oy^}2VJ&R$1XL1HL-Hl8`FYuhaH0GkU zN_N;y(fKXJml7_%LVTw*Av*tKm%_#HnG0&*xLIwaXXjqk&BY1ZzKm$m90B?Q_1HHO zp!w#2YZzlq6QEhi4^)LzrYYa!R3pJ^E!JSMD=o&(U&3)rf|T#6!hpPt5{K~0EwYBw z?M3EVS@AiBAGfLyuK3)Ek5GIjkrJP=!ccxO5UeLuUYyLQTn0yWNYV#@f+T$aB$O=V>xXwsvVNGKkrNvfRj0S8z;d`HeTBx4gp()=x1=6%&r)x^Qas=ZDIH|1j3HMyqz6seOX6nI8 z#K9LTGj%btb5;|w_6Z!MQio%v9=dSawCefQQ^(JrJZFLO=%|@FcMe(|X3d?A33iop z<}IulGiTPh86YKpw}3Rc2L|j`>alMmfAh@&`J1selD}6YzeLF-ML$^>))dC-F4zqg z`?bX$vDgz9gZy3lZUVRIBKSNlfH>Z?JCOnp75VioQsP$E;m4oYNd%Gpw> zzXByPwU25oUihY>9||B^WtS z60pCrXRpMK4->JtL#52S5~fwo_pzFbD;HX+{H82Y`AtnqD>wkv=iP~r)*&I4ToIStqNs=+ZR z<-A}f8kVYWcn7mkf0ib8cW2DGk(PrqOa~mCbvhvHDP8A=s95`_jRerHoKU#@L3`B) zMc-+#E3>KblZ{Q83JdeC8`8q`um-y}WzN~lWLKs=nK?t7vTIAGqY3T8WG0Q*nb3|T zY*tPu&a*8mcakp*ap14~33Ll0G~r{)DES@MfAa4TG_mH6KUBFX*@*!jCH$$pa_ zHG_2P^sh#`CF_wRWj|(K7>vbd?gH1PdUr}CF#MOluWwL(*qh%+i5JrubjMH1SCeG~ zyH5Y=s}*_#`-8`xY3Yq5tcMh|y+_AQI`K#BxATvNU` z*kZ?6Y^TNO79#JRpsBETs>QgE!A&^BUI@J-DLA@-l6SDjlxM3fHr8TSfnuCt?;1_{ z7=SVu$JzO-@6lQ<;b^TEtOnFP_3RQ&`QE!0!(KM(S9n)I9+q%kx=eq{T2 z!?+mS&0|~njPonjZR0G$0dxeJxQ?9dRg3}Ud53|z5ZRySQBV^>rV7+m3L6jVd89gJ z>mG!{jR)lKnFtldc_z-sG8z5S_bDATNSV3uN41T%kf0pdnuD5h?4!gCdi8=&;uxpI zj51Jk4%tsV=E&BRQCh2jC#VNgv-n!WS!7g+`U!u|2S>-!+!(a=v3f*aq(#VdcXb%# zX3v)0wWJKLC9TjiAahhaC!jYlt|t7BfTYeerb+6e!~6nIpS;^FH(MsAu~S**#>rB{ zZkTOyG|w4 z1Go+!V(o9fYT>FCe?$iW52zRxqO)qn`k-22CZj;Da6FvT^@=UfD^~6$y@I|^yRTOm zhxDLcu_rnOvt>7RivFs*T8VOVx-0fzDV;*KC8`xqsnSiU732*ujq$=ZAGD7{oKW_0 z*4b~VixZEN3|$-rDmlKH#_%nsy-!f$G2QdtNISdi&uo`X%J&vp>|9OxUcJRQATQzW zu-IJ|OQ3uuzGa%ik{%Yj%3`Z5Mz0fzj~aqJOASFV&TSQpJEsZ8S+0U{maAY7S?pnp z(c&%PI%&%H)`GedXV`m4Q`j?3{~Gq#TSei(fDb*-BgZ{q zx3z%AnU_KSce2tjm@>Rgj^@b!WF?#^Aksf6AH$snJ6luYBroCUBroAs*>E>njO<0i zk-bQ`8K^sFsdvoMl<#q3yE1o0{pK88K6{RqYm>M z0?mNwOKS$gM1F=R$L)4QusH^Eg2~6UrXX^Hla+hc6lB$jpMg(HV<6>YLZ{~mHd|8| zFSZz+-z3~GEk>nSFv=J5ER|xx*ceW>je!*QuCy2@f(h1SW2h-@uNLoD79?3Lt0MU# z_MqGmPkvOD{7`SpS5bdvnKmj_))!a`8~QbzIiSzeW~qUdeIBl;zdV5?R$OxbGF+zN zb~$f1T)YC8ozp5dUVI6Oot5>MUj_n~tK@PmE(lEq0Pq&MkO|=K9=WWM%O<%zC6^cE zvPCXiwaydmVlW>V+ zcS*hXpUiZ@)H$if?BRZ7nH@1~*}l0%)k3^WH^zU;`y zCfC$Vo-%`bYXnSWrRtswA(X0z`{&Tc#)osf`PK8Ppr6VI8wjj?NfZ z7*bM$8|?cwf9|}=(VXp3TI-Qrhm`>*(Tui4k4b$oTgNc_{_ZgkeYh6sIGY!+}RAvu1 zE?234pZOW?W(=saQOXQzRP&j*pNBKMLA4kL)#K26&^o&chFMmD-WX}_i}Q4x{Aeba zAIe1XB*v(ui<(GFy5bp>+87A!SxMX$wJ@6^>Y1t z1o7~`1Fj6;N8eZA`WEhK2Y(yay&*aphLWMbblA(D^_SVwSB&rE5tfVon|bC*#`KA4 zyUFy0RZUBKLFz`23T8`R8y&J$>IqQ0k-j5>?74CN$*k417o={!?evN5p~?LFucl8% zO25156W_(}ZutwN)kV*-+MN__aK^|r&sP9N<%J&|z*b^4xUiMQ| zIF9_1!d62Tn`5!RfI3@+Tcau8^9u~tN>jc^KS{2&7WO7-%J*)y*zYXH4cg98;jli8 zqI~Z-O@+PD7P}VIA{B0xrhM-mi@j&DqacNzr^1zM3fm)D>~f0*H3%QiC<_$3!Fb); z0m=%+-t2jiW<~vu*RH(=nEH`QEmv(wJyyH+g{FR_cy6EUA9ym>)Q`BamQLf&b26Ilm)d9bg(WSO;!GK26+h>p&py8f9jhef`%&M(lE?{QHW!CtUfu$>#5 zGMr1yG9k*Bq$0ImL=N_B!Smz-LI07|8Y1wK&~75shs8~VGH!Yc=#O}UEnq00#Ca6X zL3^tO(Cb4D)?@#Qbg$Hw);8vPr7}#)40ae4hLrxPhA2B08*PU3kurHd78`9SyISM= ziEyNkF&ovysrq#08-Uy}&U~U`d;}zh(;UpVp!XhnP^Ag{ueA>DG$*Ztl(Y`P*g6Db z>kzEoV!yH2Z!Jb^g@mIGMV{rTRJCdy*J#T3KCsv)7R%N;zJvZ(;z$m8MUA+W;}b?V z(Y2hCsbP(tTT?lEo@}aGJ$2Ba^n2B@Oi?|AU81MCURX2KW8a~Uh2IhASeVANj)f}V zjX2NP?QSJK=7#%g>b>@Y`7H`yWL`USnMwrTVt^r z)TwEz(XewN<$F(9jGK@NmaWn3qD#Sh_N+@uulaqEj$q9nil|MOLeFeD9HFY|0?SnM zzoQ)rMp=yGVX#ASs(hvnr8(Wn$GSWDUuqRM+EzhIT7_V26@sx<2*y?+*v%HZ&0;j! zOE`8a5^g1^>8e$*Qy~S#%VO_YEOV>a%>^a4r0EYHB0oLA88vK@;XwFPT?8rKWo7h&fZ$7<&*=6@P3ZO_yNBZ=oV>dR4Xw>M@7qr^Kn|uFA$Y z2beTtO=Hqzd|Yx_7#}I$tF;(q1i`Mf*pDstXNysSmT=8mRDw$IR-70Sa@J&HTAE&y zjq6Lq5Q^(d#FF{lLDpAv-%!!>e`hI)_f-|7nOdl`EX5&C!Ipv&AMu}o65;=spu{VL zZlvN``cF{eTKX<1soXn3iEF8mWgY_&tmZ9H3n6!VyxzaJt9j-{Bt8fz4!c-H;x}2m zM}O0#_vmk^G-UK1#jLc<%d_2`#e4LD-SQrN0Ga7}k5T}D1HAfXE=c^Qx^KdJ^llX( zyZ7j(=6a7lqasRqk3OaDvwM$bTAuCvj1$(*-<8USRZdfbb{SWY7?;26<=J|;+TiZ2 zAaPcj9{FEfo~_6KUqJ%h%)an9!D+U|;{qj|h8IVDY2C<5G<@I-`j4n_bv7-^sgJ$cigNg-`fOAo@MV#%J;Tdj0;H!#)Tv}@h

KYA{5wsgPnx`Cg5t!rl^#?a`uboX;auc3{%P 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≻tkkhNF2`j?f)h6e3z0)J2=~$@PwxdKK|>&m zTim)ZFM~CFvV+qJ?lP=HC9J%poee9f8*byWoLo6w_nq>`96kElqDe8Zm4J=dLWC|- zsQF0}nS+NRF0*gIVt`sN_tfC%!Xs=zK725ema;d!%o9HAQmp?JDZZUQ<(-*cuf^GcV=i zVw_AiNXbvESz}HDCz@;6+n$XSJqectjgcb_#f>(_^fZ)3NE)XP)}P_&ndsP7&>9@u zR!kJ`W>8;Gc+4l2|KmTRG!HIBh|w0e%Am5P&`W^O77~eIgKbdkGHVNSzOe4TR1C#n zF;oPdLjQ$S2BS}|j6VaZOsR}~`oP21%iDR(v){^q?j*M=)@G~LF6-~zk$H!qWA6*t)bJWy0 zKSzTV@q&sbXDUBbG?l@1ht5-*D&eYhYH$r)WTk}DuA*rw(z&&=|Bmu_83HR0t~t0O z?o`B~b|1X*ZDe6;0EE zCu|!%UP>3W3YBTczzf0|4}&2{jk0v5LPxe92PzW zb~xGq^L&hN=CQqf%G#PWYcT9CUS7R&{@Rs`menl63DhGKi^ZgyO+9SY$+b17R>JS> zWz{PUIk6W55r$_`I4TRa#Q1FX%Z@<@Fm%AeEFM|09;%iv7Uzl4x}&_4HQ7-TTa(4% z-#V|X#_&%Xgd}BK`F?U%ZkA8{B;@DX;(cskE~ZMPX=W`>)pAB4$!VUBA}_+xf;`#{ z9NgUlSUglU3l2F6K(AVsA9LIx&IdjQFbiB(79>Y_MqoY8s;e>D&gjq34;y@5y|29F z1;#q(+a4;yxe{lE+9H8d0s*aFQ)!ZdYk0IS6$vs7qo*J{aIG8eK{ZMfqLa`;b z{dheWQFKttj9UD^f`a6wVb;RlB)@v0MgQ6Zr&Dbh%F71bGKcX zQZu=Bv2;29u=O0jw!a+j%9!Io{b&5QS8ro=b(tNF_zhI6VBTes_ zO4Gdk^`oi$18w_ow{2&qZQE5SumMtN>tsccG7_*U50cM+k*3dGZMPs>)NXFQXedqB zuE)1lyYA@3=EhW={EBEyin3 zF9h%{}xufJTA ztMiZ6-GLlUl1zx1m=`&}N)s6?5D5&tAl<$5{pmR`w=x^>&4aPn$06wd1KFd@_OBCWLb)1)8_Vd4(rWGgt%aLq8^ z_LpI|AX&Js+e`(Sra8sVLFr^mBTZ8}fz`O@0Zm`1xiqDdTj!Qe%a$L*oi1sI_!tNB z+=6t8xlyYs-BuQb~(4DB5kdY%ne|UXBdZq4I?wlwkc)0II*SvKU04^2ic2n>;a3*U5hn;OnOGiAT)t!p*1h)Pi)Db^hdc&8 zUVeDz?s7e<(-mem&V;-azyD4le1|tOp=W~V0J(_hr&cZa(cmJ9rK<1@St+) zXbTBr)L>WJuOa6ab;lTtyGIoJy<#sZ_6NoGD)yyf0yA{I-WwEfe;Yh1uOBGwM7><9~@ZySHsMt>w zyGgN=u+w1Tt+uw1bE;x%6+2t8CdIB&>}tjCLQR?Qer0VT=NZLbQ0y(m{;XJOw(EDC zwS}A+ip^4Nkzz{~YgFtU#dyTsq=iS^X$v{WD|V7%rzm!+Voi!QD|Rb(K1_JGTU*Ep zpr;xvXl)^oA~9OJU2R&B%lHB-d!0H_Mi-Sc8q+74sKjuU0n35<6mxmQ~k|6{g9{ zhY4@lJa_ABkKRsbE!Y**42f|gF~2?|zcZ6TZ;bg|zm)|gyW++itirKpx5(dNliRC>jS zxqw6RM+WIPFCcTEIZ;3qh4{9`0}XAqcxW?oMb9}_Kfit&1epEt$<{L|IzaJ#K(%tM^AjLZ?x-{sQ;PD z=DAr_{+BA^kKM}3__muJJ)}Ewv!e%+2Gvt|A1eeD zb|Ruk50;_cz3FSgMC<7^0OhU*7o^vUzfzpm?IZ%>B);Hx{HnUTRc14Q4AidT%Is@! z#ciIh5<7*#uM}X8j1?E+1tGX&1-Dkr^OYpdyG@emXl-A3=$_c|sH)yDe@zXpD_yy$ zX8y`mE9bAMsa_&+b6>_t`aLLd+bxpWtIQ4wd8>US@@?{&nFDQEv3P^{=C(&afpVlg zxb0#3+!F}3SGt8bIjSM3L>XK7zHC9&E=%0$Gh2c(>LmMm*brBMPKGpGcI?V5roS)P{AT+QFf6~#4qN?thP+$vuBNnW^qyH?&$0@Gq(%Wawf zZX(Q<1H0)KYO&}2)COu8Mrj-bV)uq~Sr)SFPFl&#WEK=jNO*7~}G1Ms={ zxevzxKA4NaYBJA&gRqQ%bp%W{q>(V$fJVU_26HsbF))vWxg6$EFi(Y929sfw!$dQ3 z#=~S6ngo+$%w(86pv3nt?fU?jxjL}Z7IJP^>@I5yIS(kdO|dr=`=er?D)xn9hoBLe zIC@xH$Qh{EV8xD7tX#1Z6gcD)ypcMJR0(-oe%ua>`~MhdXO{2W;QU_^Aca z-?*2?;66d#B7%ES;vYmyAIxvy2*_D=W<~RWPMlQdVos|Buprv_Sbk-Ec~K?rlf|66 zeoRID3EoGz^IcpNTUq+f`opI-2M*`a;nJt0`Qu-THc#+HkK&=c+R@SGC@z6{B!4q& za(CP4eK7dMqK#Yoyh9sA2J<(aPfPO#hzlkAH&tt^<{ zeB?+@k*lFCBib|%ljKu!A<67$yjwK>tOQvZf4Cz4T!p=Lgg2FxZx0N@y&~pX82Fh6 z!9?6w(*I?oRj!3ukGNiTk0k~}BW^A^ zao!2r#Iw2FVK zV+W9gFUFk$YamWFKoxt;2aQrUVwj=rf7Fgel;(CiBSp?R^iavr65m{3mWp3uis$)e zgtVx(hBuZNib7oC&nDkET;0Km^2pvo4@_Q(IkmiSE`l@9dA^?@upLe|#DjkU_eQE> zF3cyzL4in3EP$QrhRe|Aea?~d%WIdenO{O7J?|mu?h-q7oOTz#D|{#U%zXg8@UH#_ zj}>>6t>-Wc_4&?8Si)o?Lsr9uN7eBR@7=gOkZok!PWPScqYCEq_anIX4{Vh93ZYZC z9|RV&onxI}32jCS<{xms1d-=dxP(B?4k+GdY6#XNkCS($x zk4eBr6EX=+(=>hviXjoG)r8z}qYcpe&1yl`Zxj(|AuveViN|U8T| zIa?Bw4bI3vT2%Uebs7IeJa^VsWQuGf^w*5XLfKq2w7|3)R|5}A`fl-N^cj0g+Phn5 z#iZNEE^_nY%1M&~Oye>fdmx=lm*Y*-tIg)4jv`>=$C1lmq<0(drl3)E9Fb4qHn=(( z;yGwVZ3{^Y+Zsiylom)1X{BUmobMoCv8-$81pUNnL}srfksTFR<9#Qf=beRqwi&(B zT^X5jtHU~AI_S(qbEE2Ch*yP9_U6Ld=BxsK?3+do&x_>r_wMIe9sGyax4{RmDrc*M zzrGEnS|Y(B=$6mXGcaki@H3UEJ&ldqjCU$wZn8;{Y|4t6wT0WGbC9(}w&Y%#kiWiD zP8WaBT+JQgg_vzxZE$R@T_p4lQg9reOy@5ECnq;atiO8E$@AANTW+s(=djU3e72Ev zF*EK+<1Ja*y_Xdn&*IPZ$KFRrYm2RnNOn7K!?Swa+r~bj$24DpvG?8Jy_IHztsfWe z%P`xf@!7V1N~SRDWs{j--R91V08$SO6iaL4A8xJ8!=k4X>|V9iR7cH}unBFz&#P*B z7v9-Q*h#2Lnmxi*7oAQ;bn+pD(SwB-Hxm(Z!ngN|x)+ABcVKmtJfRn0owNY%If3IN zCh$%`mI2{pJj0imjES!X&c>%WCR@=ZEp?1Z7=Apgzo+5UeMmPwf|t(tJ!HWjw{v2o zscwYHdG;olN5H%lCRT;c&tbCn{tPBJ=%eW)Y#b7HGTdmlYiczzXad)#~KU3^! z#hz2_9mW2t7}|zP!D7O= zJJs4kPQ7AhD@H}l#vK(k(+0gHicwLs!QNEtPl|n@*gq7z1H2Iv-rd#~a$ZpE6~#VO z>=VVV1mE2F{h_smoZl(7Rk0@&+o@Pr@Z^o(?$#D^`YSd_v11iGUa=a*mMeBo5F{yb z6?T4YZ6Rkg)>9@9uB>PaIkOd;s~DHtydF0Fa{DvSa(f-xu`IWvSXs+*yRvCgUMFd!H--}+%2kUJd%JW{r zdL7WDC3m6sE>Kx-SM~q2vS|qptIsQ%-rRc}?g7PWyQ+DmuM+I(4bz$r9v0YRL8b9#|XCF73cp0S;# zwi{qG>-1Y;OJ1jcf|m1g$~yfHxZ<2ba}_5MdHxsH=}U%Ij~G$Ca0FNAB_l_TS~7I- z@RFg67mgY_Y8000qsO*bn*U1|?s4B42flE>#TRu>l!f~&uq3g{Z?SN{-FFkF>PJ8> zKjl1+a|4Nm`%_Y&?UEMmy@2TgJj24BD^{~`zt|VUV!FkGUl#7^)o_yTp!=kFhM0vu z7wMdUxw={GS?HGt#y>`t=LXpJztF$Vx6OG*XjR@_V)iw7$5Hx)KQ~?yi~Eax3m~7o z*~#`9HK~rdPTU#cD*|(V2Fmg{up~&IbKy^h7B+g7qBif7Kv56OwCHD4q%feD1$S%B zlb}ePlcme+N*OfyBd_xnV=UjfPLiPmKKM=&oHPwLU_Hf=#3W!Cljy`b*>@H03Nqm) zilY@K!RO+wOmfAjrbtvLA~8o~ViI%$lK|Hx)gRO|#i+&cLomMkaxo^Abz~x1_zRCCen}6ua2X z%YK*y!PvHRF5OicO|Nc2mq{=w(l_Y6Nz&yIOu{Z3uG-4X9!T)HHiAuPwms9c2e`1n zoj|_hFy5_4Cpr^-)MXEtte=mzd&2(N16~$@We*Ij?-|J%f{Z4E{phr0&laljDbkK$jzqtQc$18@X~w<#y)prO%q%FT!}3|U2NfctcTKuSx}EP zQ`#@VdWgXo8CbVl?4OzNKVT++C(weKz{d8^FcDayDU5{S-b&(!SEqm-i)97kluR)FW`Gnx0gJb_zUDGaDMah6WG|EZ}3x?F5e(W z)~v79STSDQWZab~HcYWH#U?7YSg~b_ZBXoV#eSgJj}*IAvD+1+IvA5? zs)I3Up*WJkDEDWulN75~>^;TaSL|!WvcL~8e*0Kk*y*p>NW~}zYuwFKY@uQ+6{}UO z54Z&;ef_O1 z6NAV;L1?P^Ze9Xt0%Eh0ACf zcR>gEdzBChI0}qVC;x(e{M&sZR_^hyD*At2b@sme3n)e%-MTNkvU$=Ts%qekH5Go| zOc9O0XqWlx3o1)LUDG~3WpC+}U~PDPUbOM=glhj5E&T`Z8Nt!hExx?~Q0*S56R(WF zSXuh;nxpc&mqCsW+6~~f&-x=OO83-J9YZwUDH@*+?FKnU$-!hu#fg%GXyf*RipDJn z|KZvlRi!Vin^@I6bq^)+71PbZ7mat0BKl|(G%G+kmvO@^|__8Et%XPqcLF8Hn#i)TmTvW&9KHk|5(~-=p!rLxnrpS!^$+rCj*x zSNrx=mi{Au(_l1@s^;majVJOq^>*7&6%=VyHA9dwzOyQR(4^Aiphn^mjMP=7PuBH- z++;=k>59g8kb|Ipn&#KOTH2(rl zLeb{+`wRmOQXD(KHd-xSXER!o-+dDtAfEVXd#ajG*i#js6|C6zD71YbC6%R5o-r9t z*uE)$`Ir$CeUf6LPf|>@3YzU3w`4{APn(Yw@xYVQngZJ)1NvleTGPbs!AjitQu@N_ zTPjPpuRTn}M2o>CLpbnCS9@INdyVtvDf_BQA30+%GD#WHCyF z&H8x3jQ~P6kDmS%KFnx3a{G*?+1rE6_=Ww@lq%!G?9#eu+*_P~{v9ll9Xs~od$jT4 zz38_02LV;||76J$Estn?(%#DEz@TW;#NH*9xPGbx2-N2AeH1Fb0ip4hwCcJEX6fC+hoR6n9Ta z2W$US+0>;Hid!lgw@Mp1`%SbQ%DyfW!5+%KZh#O?85wr-w=GA?IjaPmQD{m&vGGKd zwc(vYPYGp913^H2CxxeWFI*HMoFBnFK82??f7Ytnx__Uhk3q6FAdhDd5`c3_fz$({ zTsx4hXda&8G*S-SsKFIefhYY&jFeIi%m4{5E|e%%2+mi<;u?>@dta0cOM`*V)Ig1p z3>jF5^0VX5>gv3TMWqqBC=;wM@SN{x=b@|@;kTup5DE|)=GWQCfLCuwcN}X^Y|z$n zaTD-2)PQ+_Yn223cHvRsUf~Jct_+2-6YB3qt4L+m{{XKA;jvf-x5+su(k7R?qX=%&B7N_PU5FSRuNQk80li4Iedjy6b1uf zs`I?hb7+)uz|`46rY;}evWcs`vW`TQ#3{VYF0@JTu33{UPGMX=F~LXSbVXs7ac@rl zyLiCqif@`boFZE%RYd03VyV+oFoGyokx1qs)bdos^R}-PEBizd+XJ(~hFHW82}9mv zmiQ?8Jpv6#fAWz$E9}~EKT5x)Qjv36Yv4FFT!~epKazb=x>I>K!7Ic{?5eMYMwP&( z#gRad4DoJ?YrJWK-n1HD69@jj>&eer)1GF8d!sFN!3Fe#!pr5?i#OW)!-t0}!sEfp zY6HzNUHonE#`nW>^6}mY%_`(?i?2Z(Qyq#Rvd|odg{Qz5{_*fCkRJFBN$2n|2AJzE zW~mp5oy@kanJcJdhYi0HHFm1h`NzT~rE>E!d0!bA?0oFIF6(pWLH|6FdZhr% zLUGywdIk9IdR-szqfJf(^Jc5l!zsls^jzN*+=P8OY>6~1Sze1ou$eHVO%l=xU_@_# z2-WdUF52^fhU&@L6wMjixZ$(pNhG{R{U(Xz2H#m=zP^K7nJ+_ho+M2%Npc69>&11w zuf+-OoONm2X--VqX^Zxo8@q$<(;OR)Z8?xbwA&>eM)3oC7<;af(Q4-mk)y-_@o=7m zcpZ9pCnzoKgaZPda3ZId^AXG<2*C~ab%)4b8*tAOhir|XIjH+~&I0^?h~IB9G=2)R zgRiSI8oxA6JodbHfHZ>Ye&nn5BgZjpJ7+j@oE!TvLuu9L97t(Jq%e|8t3a@Jl5_Ig z_>f_Nt8tL?PS^+N}tPp+Yb9Y88hY>x+x8#-6kX$M{Tw- zgSAbYvwxYE8!tE69JGcqsCnU$C^H$|DNDugllt6M1xJj_&Iw#wS(}FpiZ|dA&;k0#rXX`n;dVj6? zTDLWOMayiR2kP$wWz`2Uw5p`+AxUyqNirJ&n<-aalw)#-HNG84<+%-nVH{`!N!Q7r zZLL_Cul&|4e5+e5UeQFWbD;i>@KE^Pe@`I0kgeX-r70LP4tb2s%_!dvG^1`|CJN`9 z_k_Kz6^tKQ+t29tmRm41y=|sWsHjMX##ce=3QN)o8L0UKE-c(ycH?XN7k{yf$LXqqwZ9F4AIatF)^N;Z+*G}w{bG6Khwd-2@;Mu_}J4^ zSmxlPzcG$xpE&gx3A*)-CAQW#%jdTe4#huOmJ93Lwk-GfCTWN(#7jTP5@`ju?hbRt zI4hw^^HOJ^Q{r2NAQN>c3%TsZtJyKq45Ez>A*)86P|JQ52{c~6|AUW>bu2BVn9?jU z1C6*7S-Ylt2@e@4{84bYjE&GfWU!crg2TsPua8B+PVAnTJQ2RgAYgChki^B^di{5YOpfS-H9lEVy7SuQ}BTvu_6PS!&_D7h>FiqaN3Tn&r~fJ4I~p+j!Z zc~4Y&WPPv2C-))0h)*GYmx>LtSkSt{EY`v-gSj5&447xa44|3EVCKSXfJqK$Bg`XV zZh{HHYv*j3^jA6P;9GW4=c7)vF8>0lVa~GmV-8H;tg3_$mygQMe9wxTs|6i{S@OC zxxvONwotJpiq$Gc*+>)KD~i3Y*!zlos90N+n~9^Hwc$*UVuvYKrP$GmvFwfC<%*r5 zSiNH0@iXqOQtUp(ey13B{EWLN6gwF;Ww2G&7IIEg>@3A@RE*NO^bvCIQH;{L2HT_9 z$BIR=-8c%Y4cAR5R-xFjiXE>QwZoY7Q9F!@Ba9s|gXLQr?rKu3mtsQ|8>!e*#ZFdi zbgmoTQPze%IK_@utXi=e#V%ItGR3A~7BuObW^Ezo1jXhnwo0)ziZv>Bj$(&m_soQM zxV0I%UxQKZmo}tX-5sr1y<%r8R*IcB<9D33L0gYvvlLsT*iyyTD|VV_o*j zD0aGH=PGu-Vz(-GyJ8P0woS2T6?;*!zbp2UV$pmzeU;W0auz7ISh33#yGpSe6uU*S zM-=EPFf^m0+ zVqdB|6oiCgF3PElKZ;HEivC-NK3W-nrhIg8ZAWaJeL3`*$~bliALV&*si|o5On-Fi zds$Vbk45vR?2MlMOx=WN!P7>iG*g2 z=XU62~hG+O(12! zQZ+3Z_AAL(_hEgoC1U`VEBJ{20IH{$$y;G!0Frl>9N&3v?PoBND(4=Uee641{GE88 z0rM`HC)oFk?E8;k(mmZ#_Q&)L+Ctc8b+MJ!7UFF`*4+h)eP6L_6r&~x6W;F>dqc55 zDn>ap76-mvtW<%YWF{f0YT$9-JonKvB zTMeB^bv3osb*pLPtKUFmKC{dDMZ^+u}I#6r*(jOy+qYOja3%v`m%J77~GM zgR!CvwnyE4tXPVgEuLvA9=aue&X)W_?CY09I^<;-P^Ix+wDG$|`Rn}Ac)w`8wjlZd zqz?F;6)pWV|C}udFuJ3>h^;Z&_;vnzoF+Q8AirRegK*wu5+G9&ZG03bot|1ZAj5Gb zbFbKN@4aHXNBx?|Qll96I9iVXJlZ@%PeHYFuO^$e`#0_hqO%{Z%YFwwoXY0O$N-Z2 ze6(o|vhhf?>9ivGLg|B1JZWVvc-Fg}<)hW&aSlQ-Cx#w_&7A+?+R0#lhs~V-;iif? z_0tZv4}^k&c7aGvhe!x>*m(C03fPX5t5+`Cs2VUBAqPrcoK0pV2Npi;MrgnIM+~XO zGfe*e0V*1M%9Y$ZFgAJjovbnoBp}jmutx25VNa{1xH!U-3DH|oAer#{2V@hZv9}&R>|VA zs41he#9JR352mn@u%bD$IZhd-^**-cyJcG_on--saon;~S8MCqJ(Xh)rFg5tE6ML( z@E2=z^Rb^pDcP~-(z$e*=`_9cj6IanWqBljlvm-2Ih5jG4prVzSC9pAD1QK%FFOk0W5A5LDb|eA zG4Wn(Z6W76#cojSF~y!#>~+Q7QtT_m$aOIJZDVa=r%3!&b@JUH(P^TY6o2R#= zPUr5v-$R`SCDzI~$O zpO>U?t`;dU#OT$q83Oe+*bLFi*bEjxgEsC4z-EZnA+RMAt*cQTsYL5YxZZpA?I5Hmq$=FD!7l=r*s2B{6d-Mroii(v z-Kz!pxN4GL8{H62xYRk&|Ps`NOQ zM%zDC%88D=j9f_AnN>!jE?T8Zxg5DpJSV79R-`G{gVIr@lu5r$ycnv~TMb@1&Qhhp z*i~*m_Cu8hV}D8K(n}1bqe{<;QkI_q zbE(U3Kv|Zgqb$kgB(=!F7L=tKY)2PT1r{HduKW;oFHy;P<`H0^Bb2E80K_B5a2$gZ z)mR_F><@Q*Cs8>T#Es#9(PoHBgR!p}Y?r!wTQNVvFz#}#E#$OUjO4BHdyitjR&2Xs zk156tY!lvFihZKk=ZZnZ$+`N@h(;DWW{(c&%|+-V!YnOV3#Pi5+z}< zT5AhA4T^16jK@EXJ0Aa}4Vs%3+oss-ijk-^?%r4IL&a`J#hLJaW^Ey7i((HcHXO9Z zTD*mw(bg7nR={Tbk`gg-Y*Or8#nKXsP=PF3nTn~nXaP4~PVc?iP>v7eqspUAM;AaH zGK`{W%>$s=_XDywOaGp~xt?F4VJN)A%h=q}DkT_go(o0Bf82#znD_23vy|XoLkVJ= zCJmqR0H-)=Jr5;p%u$WBSx{$Q_SO3=ZH&jf(`88~YBz#!0Kf`87LY^Wwww`FB z$t2{!sfX+inGL_w!4UXMd9{UiwvNpxv8Yn;(hn(O1QT+^`8y84N(m-hxs*JeYGZl+|Fl>Kn|whCO=?n(`;6D&d3n)g*G zjJe{599Khw@f@CVz><^;aS1R{!ucc4GK7V+;+SL^eoPv<<5R`SYlt3$D|T|uu~ki_ zLMDo%kc|X8iX5FtR>9|ex+>>ac`McI>@K zFprcJ^(3RdWRrBTRJ!Lm5LF=Ne;Y(x@9*bbt!Z`$aYY1q6cY~ zcO_u?&Ffkr?3cS_?*0k;Uq~j`qT4TT(HQqj*qoMN@)pu7HV9)7{cCLs9pxB zOW3b-v$0>g{-Ja(z0J+L*s@&ZSzyw(M^iO?|1VY(iB3?GIR0G(#tv>bOycvI2rW_Dly#i14m`+Au)s( z;R6R+>%)AIp_+`{d+~*jOMsiL=UsxCKb+Seft9NXGm4>*LQafx{$7}zUp|6)sC^%3 z-%DVA27I`E9}ScKIC0T^8BF@;-1`Mgj-LBq3WFl-#5hnxiCFAnm>6?o*V=bB3_sqP zmLSX*VdlW(QiAWV!_0;GmVJK@W**+ZfY}CS59Ej8a;Y#5v$|O-&}Nnj24m<3+okT_ zR*VY-;%Oc6+1_*`$xl2jiE^2ZO~G<3hq?y_GQ0$M2;kbp3 zH`m%i&S8r6Q*69qlNEbIu|Fy{BjAQN%i2QDe8ou3ntTiccbc}aGs@Z^S)y2_Vy7y$ zRa$&s)Z*NOwc(yW*ouO|l*d14c4H?FQ*HFM^eG36_kuBu&Lx9pUe)wR{9)Icg{&3Ihik@16&U>$~# zn9&RUxjH{We3U zzI~ZU zE>m|`DR!S?zf`7v@6z?D!G<-$Pl4j?Gbv7-T44cO*-sQ83!A;8CoQ`X?I zcujQY0wiQbN_Xx7S8Oh5htARIy7Tz8OP18s)-0Y~TfK6PETZd{uUa`~%y?WFbTV!n zs#v*tZQYEOD>kNqq+av7x9Hk=h>V>xxohWX*QR_=Tk$r3e%-R_RB64o(in;*5c4O| z$+#Wwb|}VdJCwT{&QM9VNvP~aY%;60$<_>UZ|g1Cy31E~2h*s(gl!>u zOTY=CS(}YdyoyNaNLW%EdOlpSP-reQn^So6%v=A;hR&n5Q3Ow^8_s3yT_BmEDcWeV zPRwUrrO{u6ubj^e2WpM@OU!3&ecwT`c$oo5U}b}eY7FF8vP->32#?{19DnRa9O@ku zj%1g3*IZU+CNFkl>f~n?#tw@80$#ikS%t9!Vs}Tf2YUBWcufc-^qb`^v%Y z@-od;GG--+V$=b8f>yrFxUAa}7u1ODRhMC`nd?u^@cvSUxW$2Q50rR1Z_9t1BYv0ij# zyLw9=-h<%Z_miUT%aF4oZA#NfV3lT+z+y>}TRB!j9g$QrBywVcn?FIdmy{QRG+ZXv zWHQUFm}~H3>9E}TAT3M}Tkw(iaU+Y3mSR%e&|*tmhacN2*Ys?FEE#TY{Q*C&>)H0? zdKzbpEQe=+@06@T)~?;ztvr(esj4dhnMFEpRUKXUicPsLnm+_kY(W|vFG?^o!w|Zc z*jG7*R(b*U(^6<9j(B`P%zGX$t@O_fG->E2&;07rO&og6V{V=!Eyc2MF;<`ZmSQR` zMOyIxIDf-Z>4$%1{y6b-E6vb~w1q@I!C+V0uOa8>>h2ec?Nsb}#jZmc8^4rPGvWP0 zv0o~-Rk4Q^FZ6T*vvEGW+!B!!DH&|Q9`Kw}k z6eAUC+y$%+ba3-|Gf}`o19ONeLmmR8j@iH!?Q2l8W?o^}%*R1Rsv(uJZ2kc1Dc^w? zXZz$59IgALvT5Bg{BYmOx{X%#Hre(stdWO(zE{aYzA2`Jk84-S%smP!w&xhAbcBycI`#55!Rss((Kr z?buufM@&{_(>+-CIxuF^o14_LqD{9gF!(YUCc(`Y@O+Y#TC{2NYPxT_EoNMu>v4to zOkHsW6K&pnC5`)RIgE=oof|{_qj1lK(G8i}9@_{T3-=;^Xx?0c!II8U_H+h=9Leov z8^sOLrVE~i8zlTC7;XX|f!$5uE(W0rPG5Ab7vY*$3f+mY-Avg?oi~5pwjK!cm(pzJ z!!|+))a9^^7Tb?u+bLgnsO_(6D?|>=SF!{z5qDI5ZEUQx_XNWhi}RY;c&z%lxt5Q<)3 zdGvKy{X#d_-SM89YjIOjKcqD`KSjAm4yqR^bZ_{-WJV6Em#RM}x$3#n_(E!edoSZ< z(*f0mXCSnAB{FscS{H+GqrVgHZg#xxOjNN~S!QXXB6VQyeKAqJD(}f{z(f^$^#G%~ zCqq=6dc9HIlR2t;4k)T#v2!v+)sPa^Ir2Uzsbxs65JbADyo;p!P**wG{zGtGNI=N#mG~X~jTZp!@SPaQ(~$L^VcjKr%MhD+au0wVnkju)jLFm1n#S-hQ1+9) z!Ku?u%k&uzT~Y*z7rVsxx212$e|Y+a{)eZ}EW285fB&cTJN!Sq{6_qTr*Gtcc=|^D zho^7!zb<`OVN^UOW&Zf*$7i#j_D^?Uq>W6H=P_p*CJAjJXQ^T*TU!V>m$~jZYZ`ag zD|WMDcPngq^+C z7IMae4Pvm#))tcEcSndjUb;(L$a%}!!p@%+8-~^JQQ~ftwLy$gvCWD-2iqiZC+lhn zuO|p3gB@mVNHc6x#oY#L3po!ewq3Cfd5$w(+!a|{$XTe^62a_Y~fd?XVn<45ul zGJYh}C*#La-j7$L#5vdd@y{tAH?;QgO7F*aQhbtuqX~L9Zf`7^cKW1G0-|_73 zKM?4EOHq_|tS(BJQw5UX0?#M{Zw3MN9}{ zPUX#WeESLz8pctU^2FXzT#!`RyNn^;Ovr|)!9?SG^Y2+!a9>}1lyGr&gZ}zPaWMD@ z4QN8J?A((JwofQTk)H-0t_|Oxf6w{7?||2Hrxow^SH$0timi;VM>{$z7>!R$6~F>Z zxTq2>yRTehWmB!fS@RLgssdczu2%Y2e)9Cr+8o+ zJ_H_0U^4u=nniWTu3WV0l-0F0Yt}4ZxPr$;(%)mvX6ohdt?3F5Qin$DG)*t`-Uu`E zFxfATUDR-)S0sFa!2X6yASPFZUw7;&2Xxn;;^)kWNmt#n+Ewc-mP}t&ckG%Pb27OT zV&^F~sE)uaKDKZy=;;CY($5#T(@P&ZHFAF~yx515B}(Ei1x%0bGHD z-LPZ^v+>dJ4sow0W-IR3u#1^UEAPhxH*ZTCRynDmio9QT!>h!-msPA`5&8WMKSl9$ z#%_N&j>PtCIK^cnT-{NKF5!@yN5}18dZU&G(7vI{jn4bca_`@EBWs0wzk^)MG~D|g(sa{u?{|1} zrri6N-GtEeCdP8_FK0w)xc8S!L}|JAmwO{p?){yaBC_0jJsZ*r_kOfnGU?n{?tO7; zM#vTg>s>C(O2bmml8hMcJ^KKK(;+{Rj(e|{9qosE|5gS*Hy2wjOPx`@CGTmu_iwp5 z-A`1%%McaUdfuphmpQ869Z*!gVi#nHswpL^3*$ zY(c>N|Kb+JMTpHjxtXXOcQ@c#*Cj-uGEz9MW7eE`4s>fHUB3T$)>$UjULxOZ4?N#( zze&Cil%@V}$#=#rlmGI3XWWYUFVAiRFwcg8KW z|MGli+?xB($v4Fw{uj6W{xdR;JTu?v@{W}RMSq=Q{1VSM5l1X&OHJ^f#lQ}>?x?@Ogh%}a#xGAB80=BS-c;;Q zihZEiKNMSwb*J&W(b_@|x4RAYD{Bim2ZQr(uwrWqIe${@UB&*P*k_8(#D-fIfJl|X0V~whBlBUv-$MoVV_9NvTBu+HkgcOYZILiC+3Jj|vKVv`6^?p=w75i~RYag%lepGQ4>odK$ ziv5^QT&4NED3Y$_#oQj& zTg~V7^@d_JI#6B!T3HfmUS6RNbXUB<7i~T|D98J=aG2j{8BYi|_~04@x7oI@qyBVaSf?kiz4$L`U}gjA#M@QEoW zlXymoRW}>IqtUR<CJpZuS~lERhODO7a8pM<#jx+?!AO5^?+Vfdd^y;&gZP006)e9la8j3 zr(6O^$e-Z!jHl2=>9Mb0yKodR^7w%B&Wn5)}@Zueo{ZTF$>yisss zZhzE#Q8!B&V5WVB&!%0E@FW^JblJiM_s{U(>5U&B3{J6fm6s$H_qq;jsvD*}5S2XVKSL{K>-can1 ziv3-&j}*HW?cc=9d;3gyoY~ua>)d1}zqXjuZ2)wl=WO*PU6vR1KEtt}+Cj2UPx7O8jrf4nNnq(I!G4G!*5nPvY=w+y6P3n7nj#AUCYD5W5%QaQgyv$u1|A(Ih911 zrDG#Wgu}&KS`xvijQe+y2<|vX5`n~!JI*m5DP#iEn1)Q?1Umm4k4!0L*P<|!#wK$_ z&r`JDZfr6n1CKqJW=&g2#%Y6*P%zlp))sb}6yxY*+;Ma=?l?LbjH8pmHlS^l$Ov<~ zwS^pN$28bWidn5_El38C&aPH8p_DP$xb5GE%PZmEfhIMVI(9!LRHkuyG~{qU*bF&5 z1h(WJFaqJE_JHwlg>E9c_Qw3HdH`u%Ga3$)89PBOw9y{m)fJUY795c@tBX#eZUycv zo=GQBfh%#8d5R}>>^6Ps^7P9)PeL<# z;S)V5p4^JoJhfC!W!oF_rq)LFy9ne7s z>;@W}CC0Qc^l|vPhw*s`-|dhr4?7p}jJ(j?-3XW7&?jiLR<995!v)f+cT?!+f$v>fTS*-_Ei}&lrw2~u$=)M<;KX#K4V)Oql!4P1pU|Z;E}fAX z22BoIzu2IOGXZK~l_3);na~Nw37udqYL62-!R}COonrSZ)}~kk%G7AnDRA&aD(F3_ z*t3dd?i9>wV`oDqg!9FQOsOS*EaH(~^4ayR*;ffAsB0gV5}8_u~rCni(0 zy)~ey(hk>@`c%;Sn__P(maSIo>4o?`(3Rk}11~uXKMhGZD{U0zb|nX)idp2~?BW_Vto~z*Y@C_jS3vhQ&i-<-7wQ5lN@sB- zbO>Fx=iWsmQHx{CPuYNqiVKQ*Rg^9)DxOwc)T_Gm{OIN>j42X2WdPH; zslYQ#I3~Hsk-zzv0h|@!n&J}1exdOU`+(mqjS;4r?<0LR-wSt3&A0Jmt@UG^@k1E1 zTiz@vT4EUgLD8iv%$em)D-3s$*E66o(^W%WzFQva3^w1WdHkjv@b)#4S0}DB2eYf< zr<7F1mk+Cozc%|J&QV1l`7}^+?szGv-lmo*7WjtPS&sl^4ZmGHmvOttg~ zGeL>=b40_mS-3j0L*K9zwo37xX33Y_H}HToCz@Q2N=~>BG4Jf655YHVLKz*DZJ;=j zE=SSEZWV3`!S1eTN^)6UEq(VKR5 zrV+hqCnw~te^w)UbN4J7(VN4WHKI57#Yw@gYeeshtl=V49kReZnCa`DZ@O={IDMZfHAzmdH}6SKziQq);q*FV z;Rx?=lv(#`Jzw{H)5Bfm^i#&8B&Q$uW8y9fxwOj^pVMDyIwhQUbOz1;O{cJ&_e?9a zwlp^_O8emRctlfu=F;5MuvSF!79_nA zl&$;i%t!36kHcikjnxJ8y*j*C?77TWRC2EVoN+77yW5;I{%*aRZQ`FBdq}P*$fu9~ zRh`r8mN(Wn_>Ck6MaIX$M!?7AhMO&;;9Kr!@MBufAr3o!%Rp*#%R^P6LqnCJgY$#A z-C-#(&|S9mFURar#Z_ZJ3aM9Nk|$p?v8YP9dcnW?k}i`{O8#}1si3*ya=&mY=wI^K zqsr!sdlQrCO`s?ULETMO5uCa zPx88oHVfhOI7^wnrV^=VZ2rCJlTG*kyXlid;$LR^o=4{H{(UNYY~AHcEudVB`9A8U zYzvSI8uihFUFUxddTc}l<7R-^drC3(or1ll*k2Xzy(-0^Hpq|5Ns67O*uhAlxINUTg5G$=I4kB?_@`KnVqaHmv0{|D z7XNtONZdZ8*k;8Nm=KG-D|{;GU9Z@Uiv3ivpDXsHV$UkpA4?bF-@ZN-^bS&NxMJsG z2}bN)=u<)O7mD4b*ha-RDHbTOZVP=1=YACXmSR_9j(-zk7V>`JQ^-qD67F+874%+F z>@~&SQH(1EbP@Clu@)t6xp5;{EvP;w3@YCw74$YM_LyQ&>F?WnMKSLFA7R{%^{JqD zi(SO@SL_Fh-JsaJpoST@|L`dYa$|)}uzH^gdKW7e zQw&o1<)|!g;%Cl8l!G%yR)2LybYTWGemQ$E^&z>kxo742o$Z9lw!LrxQpR=1#rRFPc_F!YQIme$oQ zT7LH2hItD!KxXmhDQxm~X&F812Ec0ocE`SGU^zYl=Kt zfeWT3ZEu0`Oxs)F)&fNwmhbk~!qhLoAM}4f6+aK5r{u8m6C3ZRM3e036}7` z%2ir|U9Z?ib-PKiXBA`TFaB{KuiR8;E}N1QgG zAkzL~eujHFshM<++_h;p4noVyuyGKg4|Af4Q=zyN%iqzWDWq~=imXR_*m3V51PB`* z+XtBq1X@YiKnNwT0yTRBmADXeD;C>p))p0Gw*#-mQS2tvtgUXHQykq~E*l9rbd#8h zT?9;a{Ed$4cw01aB90f;yt|EHlpIRi_~>soKKkRVMKRahxpt3@58R8zjgS6xWHq)v zX8hPRxxd}`;MbIR_qR$;5s<&Lv(%4ytf)Aj8zD=Jil;K_vFg?Zi25-S^?XEqTF0o* zz%`_any3A^Z^4F5ado_WKoycT99g&{XW4$y#3YKNBkmijT6UPY=PcM9C_c#Bet=;v zN=j-ZbF6no#W~>Rx}xGLMyRd2buJvY;zxdJ(ZL9cF32HCn z%kiMZMGTZ|Y+VgXHnwg6C4$l~gOUxaS3${k*4~JlV0;(sAW*W!wMf4%(XZ#}*L(Eq zgZh=jd~sWdhFN^>2}*qK2TH#35VL%ptzQ>_lJQOqlx&_|4J!5O;PZNS90OekTSLKp zn#X-vV<3BFu-ynkcz6yo8)G~td6;=$9GD*nnDNjYVBABKD}!|pEjjx6K_KS!3vkG^ z6HR=Mw;Wf;`Kowp;Z~mE#((Zp4mZF#@V~$)ITlCD>Kc|Usyi3=e4DY=@#=7xamX9+ zh8c$qfx1988sq zpZnulejDyLKEsY&%WuK`!-Bbon;p4857({F>BCz77|uJ~{owBw4R85VIB!IT9l4fm zyT$2ksLd{?UpMbbPWRXqr~hOej6&JXxFgr{UROE&neiye>5u)Gq;uH5yG&6|ugt>f zm0jTUx3h8jJ6Sk=?QU`UT9cmSzTEfx^x1v62h4jXW%@hDLUvC7sH>d*sqrYu>HqR$ zVmX^`X5jSrma*af6Ecx(Hpb=vsYwOW6y{nu)&3KgL^vQlq(m8D3GjMub^Xr+*bo1-GF4N8LWGU0l z?`JO4%^&X;r$rfWvP}OIqYjtT6z=Ji)9)Jx*~@gdu5!9Z8mEI_gwsC>=Z(*>pWplw z!|60u+7`MQq7fNe=;mK$;qkq@#p8Poi;_IPJB`P$nD&~cdecpJ>z7CKpf~@5aBxV6ZGOOZLvsvy4}YhBT66bOX8`8!^fz}; z?(~O_!7l#+yWHhxW5t1F55wfi{<2z*M|CXF0F}Zef5$(+c@$&krpw>IZyvhK{d*BT z;t>%MdXjKPbQtKkT)q>V$Y57-)9W_>ZpIdEdK~;5TGUh%&Z`fX7VhovhxruFYq}>? z2)T>{@-k#r(;g#7+BlUM`B7Ag|X^ zX2_Ha1R2gN=uj>In{rXmp!-Mov ziO%GIc=X~2YzVwFurPa+skM}US!1v)@<8`zFDLgKcO_;*NqL~p&HL547efS;>2f(@ zWrA?QN;sIu`R~jjDccAXFuK!t5QH3tO6xcRL$q;^vC(lRb%4`6{6d=LBTa^m@1I`~ z&RbDwuVVNJAAf=ts4s#jHNpwAr!P8lVMD5v)C3dE+`w^AdgDsy45QcG!aa_6i{0r4 z%spOeK>;IA*${}mIFTpsXBc0POv!s2FSd95nRBGDYoDZu1qE{+fM5>S6WGJKLOHBE z6v$zRc@TVIJYC_OY=SwAdRK*WIEN%_8B13q%5a}%As{)HZWc?Zb!I6bu5(Pw@fSyUTK0SeQx-qQ_j=Lvekg6o6^iEc zH^aQ-`Wr`2IbZ zeCPhsllc7`_LoF-BE$Yt6!DQKDci%$u~=7Rd;X2-5}BU=d+Ex$ANc=yeu+-t|9kl* z7dHIgOP5^8@Fk{;qEik3hW++0v*BQ0FcY1N?7@=?dRHiRl}`n|8x^}*vBwpAS~0e- z;@^jgVI1aTc|H~N4pHnd#U?1mV^0znURNak@v=z4_EBu0VuvVpm}18%HchebDt3)x zHz{_jVh!MggnPbEK}EA-s}=jMV%I44YsI+lByrxUSU2{xcnf;mZIUpk08OwzD)wi^ z-d5~=#da#z4Ps;B_5hy>c|#Ois93#XyenG5y;!j*1jq!d_NkyZOR-ZGTc}vQVy%iL z6nj>&=N04a(h>%5mzFsH0s?7*-Q`ob4O%grQ1tCRtJw33eW2J!icKuE{+0Vw(5qIg zR?Xz5DaJdhCB1t=;zGjR+oyuwP{j^b z>>G+TDV9*|3dQ_iNNCESyID(Ky=*qw^~rkCekhO!^>HuzM~!%Cd*_8^~v zs$|8EQf#tfQxrQvv6+g^Q|wH|mMg|xUB)!%eN(YDiczg}UlTv7l_nMRPUYmzU~_yb z=q**OL9vHHafdMEZSkp~Hx|<;!N&O%jz23_t=M&-BF61np9*?mOh*JO_Nky(qFAY7 z4WOnNx99s*(41osY@1@7ItlifV%3;RRU5apJ{9!tSFBC3rxp9HVx^GcsWong`4nzd zSL_BDAuIdO2r_iS&Po;P5e^DG}mNA-_3|F&4@mo z5nY!7ji;)C7C}!{u|+vCIoAzgAn0T+jJ85DD_U68tJ^ks22mii+%TYd3&+f%o%xi9 zP?db`%tJwmc4qeOucGZq%4H5g&-&Fgxy*^Mg$CI>62I@FDL4*dUy8B9bDK;ev2z z0@hBtg~Pj{gt;Vo1uEadUI@seFIK=3@|WoXmW*AhfF(J1C~CQki%10_&uX!SK833s z6gywBs}#Fdv6~gUO|dT{w<)BZ%c623lwX0;CEA2p23WjpIbiJ51Z^3^)N&xJC1bQCkitb3V47gi zj%Fwb*(>%f#co&ZPQ~t1>_NqBb@ug88zr~4hUY*&jfWFF-o+8{(0Y2Qnf!Mk>6ttT z7@rdSR_xJC=IX3GgHlc>HX#%!OYf5cUPut9QFVPW`w~rwlT&m?|Cm!4v3X8Ti4sWf zeW2s~c+g;aSpm@_=<-&=^I~}Qz6lead3@g=CbB2S>OD#`m6T+vV9Zp(0!Xc3g+3MZ zx?XKNYnmC;_wf4&zw`!qG%z;Ej3rC0JW@sLlKSzLG?kGTZe(nbhh=P#!CY9MJ*{D3 z-7;gLvj*92e^B$iSq`>wg2@b$hYhZ+T#QXx#bC05b(m0cn##t~n&VsRV7L2|M#>QDNHqL^vaTe@0#lpyM!MHjs_M)v9 zmlj6jO)+F%G=9ZuW8AZbM%l(qO&5UhqD7OQj+TAgSO7hk@kc+nJsO9bhxmoLeH$j2 zU(J~UP9z_$?6Wr?i{BFdGmoQn>6k_5*Udj+(S>y<)XkfOuK28pjfI?PHn8OS2rmZj~+4d z=#rx+Ot?h-{|nKLUTlhv&KSDR%nbe*A1ZOQ!mj)^BIo0#US1Y8oljG$c_lZi5I$WetLH%R{gS6x*m66$^?z zDi#!be^-pc!-DxW?f6;I@yFLj;}^_9wK~3bQ=|qpEnD5X8Fi~Ht!^>?tXl`-_fi@D znWyV@Yt;BJR<%;x{p&R=#XGHqT3fT$@Dz8uiiRo91Fuf$MUwTZ)bB-d3@=eEQ|i?# z;B9zNO11o*^0Q)d6m`vGwWzTWzw`tH75~ugD1| zeF%QGUXiIC>(!@PuSf;GIVk;tv4#o8T}8oI!vwomG1f4_9#xDrOt3cSwjOoSmc6TbYGdO*imrIDmDtgrP4Bj>UtF$GxCd7u@rZ^D%-p6yi&Z|jVhMn zZdcJTRqX1fELH4qtzzV5dKJ47ybX^?sbW6^geo?)lPV@%SAXrg#OJJ4OuDYpj8*KA zOjQi)?nyZ^*TR?Bb&(TH`hED>Dn_PutYU9!6(c28OfXh4!C1uvV-*vORZK8eF~L~H z1Y;Ewj8#l9Rx!cKXGUAzDv8FA9}r#nY{LQ3I4>-zDvp+IKp%#KWS@*_`{2JYG~C84 zUL!YaabQca=;X}(efalK+RPovHPZr$TihlY3(Bc!9fxJ}7S3JfRIko^3}e|J>g_47 zOo{&`N}V$`Np>nyE|0~KifLl%T=}>$7`8x?C@&bQK?yJHX=fn=IF#uyP~*r8hm7zH z@ke4wU)_TF1NvGV?%Cf3IXc2ftY`mS6z4)Hq3rzPuPeO47=>X!!ejJV3m9Pf=*v!% z$eEO4%ZY6Xe)eIWb5{z9gMg4cIH6=Fuvcs8CKWUqCIx#776sekQ@CRSU5t@gAxC9})$z!H8r)ddcT8JV9O^9}UGTx}Rq-uu`5un2 zQ_DBSG&iS}Z>~Rb+RG{7kC|}ubXvZbFI=*$q00qaY-cUuU(_>G#*3P=l=0-iNv68_ zP=24Bko*$qL=)aWRLLS9>b!{8B5N=M$1}hb@mf?I>nY{ehTu!uTtsTbP^}Txx?A|S zFb?5xXg?R^TmdyAwBIgjL?D0HHR3?jh(g4TwIS17giK&0Y^@+Kom!DzCs zPLK+EtO>r+8f69i+m5_=J!3VD@^QD9Zk{)a`dFV!Ncs`L(vPTR zwKWsTO|5c;V8~Hv^P{t2i$&xN{9Z4^Kl5~2<+$YVg_aw}jB?j0I`4`Y$Vgpx=-3(k zPe;O3@i)GwRoto=?P2(JGFAlgO%+RaZ9OngN>=k?nG7AAAI{Cggub94zc9CVXeh~| z%v~9W1a>p!IMnk~%zJMW5vQIrA`BEY3(q)j5T@!}reL3How(K7u0y0;C1U4GdX+ZM#jZ{He+u(M`H=%WwCsW&yY!1@z zJmlq(PHT~|((l4`dUw4G>&eewG%!=e?!X>E#vyBoRxjI?y50HD*_HmAyYtPALt$EX zZtG%+TNg9b!>)Aa>Gkm2XnZnt>tqHa^LzYkJtSW{sfV3)?ayjGBo*{Vpl0}(PX)b+ zij^zYq}WQuu2AeM#nvhIE5+Irdswm6s4EigH+`zpdf3O*L9-W-HYz>@HR?M^N^;hB zK0GW+tAuu4P)v(Y5uo)6uoWft|Fq?pCZ#j6-2K zm@>Ndt7C9ajIIwux5zP^UGdLU70C!j-c?GhJWVi zyej)WDzB$?>Tl-@l*wx6x<2Bl(T)#Y>m5z783y8+Lr9|kj`*2|qGz@-`WYA;cRoh% z$ANBst{tP}$X;P?KN+L<>1>QXK_}PqOn&ZijJ`jH&UTD$owzN=G)5#44yBCIxo3w- zdf_@&q6 zz+!v}di(lR$iwcEj~%Yq7{yLS=o0Q6pGs?*?yW^C?up_bbT8IM$4|y$+B4C3c%Nwe zgjvzD=Nfx#njFD5t{30F-7F?|nDrYAI_0m1U*ADs$??QUyd9U;2(hVRBQyiQEuA$& z+*OQXqMafOFd}6V-+47pky1!;m$C6lvEH%G`QH#7)5J_oHZiQlRVXB~3{dUYYB1J3 zJy4>PO8{?!*WoEWT!ry{Q0UR(9KuzBP-*C(&>5z=31nFkIK=pRpf)!wK-8$2HaM|M z0^IY4>MAT7chly^I&o{aT@o1Mf_A=u0xkPHZgb-=2}HWIBoN8uEpDGlZX1zyE&0vO zUS>&vAG3=bjdY|QY?G5s;(-}JjvtJlyEMT3bebEA419=sBaH|tncfS=>Ahevp9*qI4aNSZ81|k0FuMCx(A!(F{S|wYIS5x~-k+@2Hv^iMR;{@OYo8Z)zgnj* z&h19MPIb8FDt4;BUw(v4EqX1rY9CA1n>zdU`tOLVDIned z)dE5f+ycVl@qrc(QbCV{62X4vQ%Rvy>?+4!GU_WwMC0A5u(RnCC@1ii4Zt?sj%drq zgQ|vafmT?MI}SK+kX>uELui$ahDrU4Ycn?_;HpZQG9qZC{cH4Wfng} zb96`ARviZsT$G?mrDgJ1A@b#m=FMIXWq*s$oM`rx%}D}Mvm2JpUDUALphu4|@LVgV zD4>xuJY(*^Fn7^n2n#dRS`!7IeZrL~WYWQevFl2IWV@p!beq_E?&N1$uj8cU$kU#)~v{4-Q>hs*>WPclTn!G=LAP# z^uWmp)AIq&J;2Wi%*^pxf}eeu=4^Sv!#6S+AQkl1!LDGx@~NQrcg4t2vB$g+d&~>L zHcBz4r91JfOk+L#*XJag53YolmUt9#r47?4uaR-XDi;k^g%Q8#TzK3bm79TZxe`N0 z(o=V|lFl~9ms(|zJ}ts%NK6w~r)(n?G>e{sErxBu9`-4mcvZ|fUQ<=rp&_xSqH<;U zQUYha(cmTr%>M*(QW{&?->`K)2)}jG4}x-97iFd1T8-N$k_=9whSjknQdrFefbQ_m z3Z5lr4c$`~0NAdD`(VPis|l?=uy!nRf{yIE7{hgnwUq$W2FA=aeyMCH74&$PNw8+0 z3i1S$k9|imX06yG2gNP2qUo&|Ufl~1ppuOgX1O_H{^|* z+^gY`X#6-VTBY>^xWr(oqu88&pYjkEyrAqJcOh)UD~`6Jucl#v$HRCPP3J>Eg&_hE zFe;`?k-&h*0jp@>J_pqI4aVa>JZT^BnCR2cvm^^h8M13`S^>EXwg%uwb5Iux$fUW; z>oOM-elZ25?`SP3tb--+-Ht`2U9Ia0#a`Gl# zR_hq7+lLib9_r_^)tVkq*VR&dqOPmd(a@+-rj#*MM%pQ5Q+>a*l(C?c`ydVSEDEl( zD2ye5X96@xakUEPPh(?XVlOE66_}7RjGYM+GFC>z)MKERrfF0u2F8by9?2&*XP4c6 z_RL7RzC_eZIay<`FDcQ`Ldd4dUKEKWL*xl{*7w+}<2bZi3tmWfK}sr{VBhh-2E8At zy`L!72f^KHhF$%A3JUQ+iCdOh@sC4q!DcAN{j$A`Tke;Uf>w!c7CYFdaA}reC`rCO z+25-$7x|R_xBSf znDcCyC{`_A+So8{as36z#SWOMOx@9YXYAm1wKijGKn3DuJ2raec5KWzUK}79M+!R! ziha+gpqhky5jH#lb9NdV;7*@!?+zO-$;=;<@Kpn|B)qFVyX{XnqDVMQpvNu~Iu47N zp7j3xqI~J!7b&|)K|2oY3bxv(phZG4Htk~1Vd0GcCwIa^4n^c~O48)|C5z{tQO~y5 zl7>wmVLY9&d~}sfwrtR&-DgX!KkS*OY$1iRhXe>#?^8i#hG~PlwI=+Q(x~5p@ zd~Z4J#9K(iE#Jf~GR3&aLu=*>tcf0TyI0Wdhe_F2iK(Gnr}(h?-I=BdJ8_@+eRDl7SeFdx1{T* z31)E}P2j4x_?klFe08xg)(?QODTZ+Y+?DNU3`NVH!G7eUa#khNKu&iZC&P*CI&$DB z)M)r4)Y(eit`x-_UaQCWHY%dgB1y#i&v^{R8u?u^`OjG!98QqDw4k z8izk&80<6-$vwNDbW0t5^+4C3TpJsP;Z?X#^Y>khQ(|Iv;mZAXD8}UB5zUL;<-UHf z&(*x<%duS+2zQhur~x}#kRYypFfu%04Bzn##H1=28UNr)p!s_)>YrQzY9mC`wPAPf zn-^OfZj>q68U9N12>0NPFU8nAT}~zJLT-u&Z>Br(ry$hV&3nl3eh5X)+wca}=xxN@%$!&T&Q*!%uIk|n)l8d15 z1hXYqbe|`aE7rM6n#^5I?%pn{$xRUyb8XnEOv$~b%gMbaExGGDPcCIi z-Q0A&?w(}gFDHta zyUYCKx-s?Jo>0^2F6y^EKyB=@#{Vd5!;L==d4`z^e|DPCLY|60h zXZ$}k@0sHtdm~f)V{h2lWsU!X)`lB@qYdN8SgWfQ-B*VZyNkV57JV38y7aK?c!=Ly zJ!sw^&KUu0A$~u?JnJuL39g?ybgY@*Jpmm0Edx0hK`PJ~#1x zLLBC#>! zV2X@pL1IPXK#C0-PpVVV3K_tTp3MpF}Y^!2_QH*mJ3HKk0?NE%GbtQ~jeJbev zO0o5dJ*U_UioK@TUlqF&sTTiu8d<{qv0}F|WgF z`Bc#Rv0}F<_DjX?R_txX-dAj=V%-YG=b-mPp9*#3cZt%bWzI{kg4wMG zSx`S4n;v<7>uh~2_DY-?$i>+34Hq0sahCp&0D-hiH{2k^R(U_imVZUzQGLS2M~4G_ z!}(}zld~8RoyqM3N%cd65S$qcKMHv#QXov(nUo&Pmz^o>!yqyU&K$abIR7NK3!^Xx z<#P599|*yi=@|rPN*%$OQFi3miQvp2!--u8&XgKUvmoy>B9q|Ep=p9MV|OVyGs<{) z9EJs>OomW!rqW;>_jD#WGtStmKu(XsT2r#Sbm{EEvL)rcaN*WMY#@0aGusN#FiXFn z5Y2eAqRwiHCDjs@d*N-*@6 zh6RfDG{a<>}QI7s`lCygJKWgEy|-G2F^qK7&lHN42(9tZ=mvqJPfG~ z74%+Fd#uf3j}kKyE+u9JLo1ZJCF+V|JdOmVD}qGEn1>AFSVkVFAvk7HeM23N`9U=w z3DX2rj!s$YN^VC7kXgy9YSytR8!p??*7H=8@>X{HfCDNzvg_mw$I0PYKf`~e8BR)+ISRHAwgubbQz4I>66{sQ{-T&1iN2Su-h=3XutbV0 z+Q&xeQ85X&*ho*rk7Gi4 zoV-at3w=o{VDjp+)OE>ZUX9R!H2r5tZr+(iyCd@5#?fE18`9-z{}AJEa@udh$uLoi zBKg=b!_(VDD~bloT6ah4{u)+jm&#k%%phB_=re$6S;rlej;} z?3s={l1G_NAd}_p_72C@&uRH1C0d;Y<7is26>4v_Vt-KVRmI*?>|Mn|V4(O{8|G1TKgn93W_uQ0a2fLjx%B_obH^E%MX(Q!Y@GEOiY;MW$ zBVDL0Sy|b4*x?5I4tFxngxE{y=>1(E#G&z%FIcM>xmOE0S(OED! z_XNA#r$R;wO0XWtIkDHvr-B|=6$Kll*n5hxq>0<44AesiGff!nW+3VP1|}@#!EC{! zgqJ){ft)(`?7FYbt#7QWor`jbdYcNEqWH^f)wVM+6=sO7w)DWQwjKBW8PD_q8urbM zY~RX-}$qjj2HZ5tWI(un-9UHeg+*EMM)D*z5 zXh%LIkbQR2v2(D<@ock(Co2iUavtTFJp&);yfpuCgzl zJ&lA5Owul|Kso8^ofgTe($jNqU*`Nd#G^mmgLcU3MGvA2B#l-! zk_vhkDR!w(;gp5S-FAs(KZ3*ZPFTih$u@`N5 zQ_33qnYZB}IofUjQtNfI^I5#vr@NPXO2fj&#b=#1At{Y&Aw|K<21 zd`3B_Q6}XoIf%a;jeooiR=j^cl+)1TUgm8y{**yPpJ9Bn%(ywkqfBc63v71z)K>Uc zfhr~6kz?p>xp5bJWgAgp~sw2hta~^hPsJRX@FxXbC%DWTR%5TW^oR@{OByr zs>pFrYKN^8Z>s2g$<6j5MTjVC{z$l?=T1}0ivKfHYWa~=(7RHxs}=jPVw@6+y`l9*6%Gr9xtE28}uUXG6*eg6Vm}yCOY$r>)9A~b!2nI)HVON{sOuTbd{$W~3l?lGDFMVE8A0B@Vwv?bjW z{ebNDA)DRDv>20;BSwO)_P@%IO)w7G#2(Ky2-er9f?kPYrHWBxN$jztiCh2pu`5RM z&y6_^!F$OGzv%imu673^hmQw>N-eri0y#CUWf=}EAHSja)nsZ}QWtu=(6FQ}1GC%~ z!*hFAS+XxI?sSflyeE|l(l&!SEDW#q`cy2`XxNE?j4O@}YcMeSZHCFSAl#KcX`F_0Px|3!#+6yCZS=*^8-It=K(^J)+oF#a>hFuZn%3*hh-xlC>tz1wIw@1}QdFu~CX0p;$z* zO2vMu7)!FG!%Wvu;$OCEgLHj?leCeiJQPNBrlF^%JeKDjjp!tI`hEc(+& zzWALiT`wqSX;QbACQMM06F0LLzt{d*y7NBpw4zrzys~}usJ)N|sP19UYo9_(c$C#< zn^F#hp1S>V2km8ybNaUYQePj%0+Rs@gj5ikTZ9UE=P0&CvBwqb5@V-lVeDP-rn(cx zp3+su)-GFe?xOj=VDtYT<~I4vJyV%WDri_LSR*(f7+EUV(~4zk)Y+UTPAWk;W+|vb z%bw^V)VtdNc+jrZyP6AT5MzGQAS>D$`&Gv`X~}=Wpz+++f{fh&hq$Mk3>&5t%f%!_ zJ%FVh&%4%8wfc1ysM8E)yO1YQ@zRG|Oe*tp4u03+kexi4YK%?;m#1yUMwatFdn3DJ zs?kM9XQ@Ub%;)lAeqPKTlzxSJkWc zP*t7Lg{m6a-Ktvq@2#rj&7Q2P={1%4xhHEX%Z06}w`ffz74%y0O)w581^ba=KT(Wh zDzV2wfY^Ipv6mHlL$SXp#$lqk<$(!t+g~vrm=KILRqU~*3brmsj{&TOhm+EZKGI;G zZuoyNCp_kHIw^aSD$>v}7plskV9aziSr1cnNx0G<#1$ei=d=`?U1nv8iG%!O{I=j9 z(&I1qm=pM>(Yy<|G@7Jj+%Fi%{eu0X!;)-5 z5R>OFu30jF(Si$%(munc>j!4(uy>bD^vD_OW@1zNNcUl10JUD(L`pX41>+{YU|W1j z4v`54on)<%ajlVZ<<>2*m44m^11IyaSA4L{e{tsp8TK6~*VoNmhI1vtNW-YKoyO!k zMbHcdtiNd{W|!>iS&p1-Gt+&OLmUIxhw&^y`Z;1_kIM(WLyYE0Fgdq5879+#9@-SJ z&B{4aa$ZNU3t>yJ`+Z8p`2~Y^*lPg0+F@6e#)u?!xRz|gJMOtp%%Hy5>e6!a?pP4u zamHJeymB^Pjn{w??~@tZk-%zAs=flM+*$S1wxsO0(pyrNT|Ug=?`Rq8 zN=v$|4ic%gjSVL(ojXs8URG_NK~wY?HA<(xg|&J|sakRct+RH-E-KIyNBJk47R(?# z`Z+CU`JxN!&?ij8OM2_ebf%Z72mIFeEX^}g()tR<)>p6}`Bcc`ctNnw6l32f7)RZ* z+!<}XxU}TN$c)H|k*`H&MiY0GuKBRN9qrCi42s=$XXQdfE)w5S9sjuKu4g0b;g{^z zN2q1Qi@#9i3m&g*FIxF+Aojf~UI4Ov4JUxn_?F1eb1KKQMT+je`d!q7ZLsL!FotS~(t6PBgKy4N;4>uB_$v)?eSsx6Lcp z!9WiRYd7LQtW^$!o%Nur;+GAB-L+GUnVJ4iEmRPBC?)V zqVcQrLp1&y6JX-o0eBOQn|MVN`&||-d#PdXq61dIW8jI&pS6th8VjRXr7qjh_)c{A zE77Ly#>s|HyCGy)Ldb21P$Y5udkC6Qv_TI5-w-rCieIH4d>Uagk@K?#8fB7uC6NERJ7s&_+NBDxwpXPN4&Ty{$v#Q0=4|g(Nl~_Ft`2cn{bjODPJ~aLn z$>sGz8$Rw9f4=48VA0hZTQ>IE9;t$*ab>liHI6B(4KyBBR$JJ3uzFT>fH%Ilv3FG> zIv~ZfznLTY+XM7G8m}p74_v|6ubhUmUlV`4I$l|FFUkkXK+SqT)s5>H6fHsi;CiH@ zODjstkxOHq<)C7mpGy^`wUzOQS+f+x$m0mQh{jJ`Z}|}cN896pRV@>ny~gg5_QxYF zp9Ri)voiixq~+nyBI_AM{5jh~`0v_+MAoC|qniKLT0q^6#6PQC`S*rlV0i`H=110} z5j0`O`!-v9?VF>Ca|4mG&zJoX^@ydU8ap+$Rb@MiR_uiJWPTM@VOekZ=4i{S$gds9 zuiK4pFRa|!IICj(nSsXX_+Qvq9c|f+9NXEjPsR9y8uyAOnkCD2Fv~V0%XT)t5ycsc z;TxkHc64jm5j?L)V%FymFlvdZJ-5$G%=+*FvN$m{wEb(*vWrVcHdK~P`>e6NY+9hP ztZZ6gLme&dT8dq)$KkcW=%*noN^I{f7*Ds{_4pFhBsmL3NgdL;gbNc=3DX)BO%gMHm8rYZ z3Pj7EZtU)Bh}gatwdodj&=(O;n8s*);#Ou5yfG$Q-S}_Va#5GAAEgAFa0F-?bl5be z-;DdMsu!EMZ?qE&79U!6D<|5NMtv5Ea|CWtnkdZFVJbDRE3 z%_hgj14mcHD|Q6peRtSG*woG@Y}vw!#AWR}+uN;^zPTIz*1hG=2TX~tSSen~IUW0b zVs3Q9J3U+edO%e?Kix}fhko>_jIa2O>p`Ub;mWdGn1G_@8OY{i<9!jQ=0G9h`5lh5 zY{bxtu@ASmLsTcOD`h8N6+dNMReX7QRs5o8Rs6Nc?8xbn(;}yy_E1ZEPSMI|k%R}H zMuHN@l)U*AUJgOnGL49WdIUv1!0C@qEd;g6V3&jXx}kod)HmSI(+1;Ju}>L_-JoE- zkR5_0Kz-MIr5@sWXbl41@08-c)IZGE-uNPJ2ZDMFi3xaPKs{r=MnQ>xwV+NjUoQtG zasIwiw=4CWQol!05_{W}8i1LdXf3%(sRO|FZN}$Wpv1+cpymL}^)6HFcBR-Q&of`Q zDE6LG%&#*Li{utsPfS?S)mN3l);MsL<_npo%1P;dxt`uA{5Qketit?98+`^dksC+D zXV3e*;FW?xvz0s&Z#iDw64}lLYyBr;78D!J*E8yu%sb1h{rAIm@&I6dv|XbzIaDTH@M+W;wMu!NwqBoT3PpW9*e1 zY%hs8zV3%Ge$vEDkFvO%MLSWY8knz0w zy2Y>?=~WN>924URW@-VmG<-I&3k@dk_2A4L^WMwbKMN-&FKJxduw0`w2Z5aECwd=0 zO2p1E*g`DA8gKC|_4Yxun8OE|V*4`cx86P<%{ zSVFn!MA;C^xQg2xvn+yE4L9N(0rhf2y&Jt^lQd@X{w5Cnj9m&ca0vyvlTz&NgZSKp zQqA&bGdx+YC-*uLVY0@&ZQ{|p8w=2h@Qaufpg}o9yn9UgSnD}E71q-~!+8#Pr<fj$Jev)`ze-Iw|IwowmI;_! zVe^d5?;wmqL~sf=TY{)OkzV~Z;Jj}0@O3GE_v7~%7J-=eZX)SV&@iSrhxy4O%0(=+ zsRe(}c`9c>{s!-j{3^qc#rW3Kv>SsB16fq19r*z4V}*ngn`nL8hWE>H*4?^vtEf7?&Nv;J(W$Fp_zGlExPR;g7K*f$4VL>COj`S6RqN

HO%sME0Mo#=)B)0y-68Z~*q{p)`a{XeSlkY|eu2%Nfb_i={km;z#M>N$hfpM^M&ir!;+CX2&-E zQ-Nd_tHZod#lj08OzNg$34&NF{9;|KVqMB8i|1*sSPQ^x6FiY9931E7^`Q}QOXdc1 zV|5W|>@lvp3L*%CT)}m9#7I&>qsZXSG?H|3yi?D#nxay2QV9;ek;@Zsp2vrqdMIZ> z;EY#mCG7Cs%vrGfUm00Zx0a)>G(PH{Z&B3c9Pad?`<5yw>g-l($DA-k%n5>=x3MTp z;huc7ZMLIoCI}RF2}Qdsr`;5OIOL{`IvKf#&{30mDy1M$ZeU8e*axBG-lRz1I4b3k zF9>6>P=GIHvnB=cenfcZXFB;0wRc)ov~z5#c&?suRl2D-3Mz)@&ZN2&hp$6d#o`0~c z7{vEuOIy;EPQDv$w-B{Sy;NI4&~A%G8UJ*~6AT%B@2r%9K>00G%2PWFd{6DfBT``- zS&t*u(rI+gpl_PQSlaYf&Vs=CKg_w1%hCr*w_;-S9odX>xqFOqw;`MTn;DOi1@*@C zoj5-5Ap;fo%F2`~bP=SIJnX6pf=^@^>omt1nm#jk2Hj;gII~|?VRlhY^N&pEs7l^P zj7;jIN(zE7ZMkHelKHA+S4MJKsjDRSjTeGryi%ebloGMM5jnT7(?7jGi9REHhSU5E zHKL+VM=fsJMMW0`(R*;oN>c>>*+oU~%P4V%n%XFUV1X!+5eEL)Q>8c-2i;Vl zQV4<+yK~7nDT+A@QL;B9pA@I0ckG!>&vEZW7gOXpJ=f85;OjbBIps>Y36SVdfm zT@yj==VcDb8bU)|PS&jK%A^CHFh%zw2*Mu7^4J4j56U&Euc{{q6cdHQx^@oBER%Lq z3PGTl8cKmxpiI;Rf#NWx2*2(*#$`~iy(rsVxd{Td*<7*^MUmi;O3s2qj%MVA##FXE z-RPhEx@Wft5eq^cHO$7oq7a>kN&QqRL7{UPA1l6oNo;Tqs3l5Cq5DTN?VtO}(V zq!fZcaXC|jN74;kh6=|;Qn7Lq1a8-G$wCxGLL}Y9S%{>yjJ!yi)_f$nMTl4s>bRBJ z*l}Sd26WKbOQjM7iaSFo=;A%MeF*}^{X)@9T=PY>TO-4C9 zL0INqC?NamY4U3W&lHxT*Y)CkvFqcc6VVnmSIXE2o&#!QtYP`fzg?VO>aVcS-vzg&g&G$Cy3#&XzGFXBX(g42pZQ0*JY_p)p{crQymA%<&cnE5p(%pW2XGb|_BckeF(R}5 zGMWE-Eg3wdtrBw=(RqtaS#*<^Tw+g`*3(;j^64!;`SspD2j*DbF2`h*_gKm|=^&L? z5b7H5mv@TFJDriczr?4_AgG+g0L-gV;o}G4ddajIr%Mj#< z--ta*<-EbN>jafk5UQH#m$O{utO%6zchrH(Hkdo*EOXYU*E>VftI{(|(sP~ez3@Q) z4z$>$r-Hao1c_2raD6Y{S|{Lqg%3APRKWy6u=!lKJsY*RUnVJqAW$q6ie|Q7CM%^N zP&P1Svh5csMcMItqf9 zgaTdaM*1@;i1$Tt+L}%nR`lxkY7oBQ*&hwpO+kDwv$RdV{c?zED+tu>meyKBZ;U)6;oaSVCIZ&3F zDvKbC-hRdiPlMYiE1VM&({W5%_GJM7;m&n|6bOYnji}+av zLp{jLAe^atlM!0$$Ba4>`kql2Lg_q8UIjz|{1-G+M;orAW2bDV6Fn}x6YZpTDyAEd>e`l(sGQ2M{CT8WUJxwb zflC&eQjnt?XQ89nk&(=vmg?+DE(-#&%u2FKoVDo_obKJTo$ke*x9qUF8`N!E>r0Qp@Lpqa;Ra0Z&2)}682+6CU=S$WoGA5`14Q!&ko?s^t7df z$w{=*<;c&vGTk{V{jzjAUC(bYEX859fffS?A%HA33wFPq#3nB-M5I%3j% zr4j_Hc|w&$Qu|~~rBVw5bv0AVsq@zQVq4UQ*pR^yv9XxTA%6@$+*G9;1%YEdmn<|z z5F5vH7GmQhMzji`#C^Wpe3v=IDWb<)`rq`0a;V-LrO#ABnsCrf3sew65M-HOkh4{g zAn?#x|B1Ib-E22>% zqxa4dq1880&M%a3ga*pEgsRtYH8@hwLdO-LA6j8`b?sbVEr>gl!fIKkwNxjqMg8lm z#ngcBuv*q@E%UgRhQ|7;n)#8&+S*8UZOwd}jSt_d5wM(SB?9om@OVomlHIRVe`o>K zlS*|_3#eXEs>@nH^`%l>(*ml0DAn~!HIvb9&Tjo9jrB{!u#x&0**LZ+7UBGc#@hN= z1>s5M3u80NtD9n_SB?FRSgTv8|PL==GE3y89t7J4T)Bb`;8#IlB$;W z^Z~mVdCeu1`4^W)yZVX|+SR`qA#jtoFcxhZ$vn{&IU27}^nm&$b&a*9rOh_EQmV&J zkm_TW08Q>H*2_K)j3zg}W>I-{RmG_K`ArLBHI1oP7){`Y3b$y5=O?Xjta*d|wpI15 zR&`EbRkm~xZH0RF7p82krxZWJqvFTpJ!N7|muO9`D7Z7|U-AUW+H$E>YJ$He)i#b_ zSXUi`vtkw7X2Wc*8S(KamiYkcykdpBN2(ekHMNbADzBc%l33$Fr%47#=YT!-a7H)H zn-`-tIIX_Crh(cSHMpwU8ft)*L|r>)L2NED5I*INjpcJI%jZ&idq>6t3Fg-2DXFP+o?8@QZ9|oNxG>No5=L>HRRqYF?0jeON}hBe$#*+oe|u9 zSaEDYRwemlGs?%k52!X#LwXlhJh-~}&_I5p6-PrSn_xe%gewt6!)Jpc4SXRp zQA{#sv&z^f!3xJ4bZkzbm=kxDGC0M2xn}+wbxYV^-uzc;wd=6U*%)=p>>Sb_t@*7#gif7bf5CUtltGP#8ITBs`9zMa$y4ho=ZdEl|DM~g}|7{U^EGr*O&)XkoS*){QT0PJZcH< zQqRUrXv z-e!%wb)ZO=sz&c~&Cuv0MrbwI(6RLpVbLqJWM{*c0IluQK(3$ra>M!tkrq9kNNd+2 zQu;qpx9p-o%WqUmY<78CCid#z#~t-^jnDa!OM{2BHncHmZK&Ow2AKN7bo6$7MArD4 zq<1bUZ>Wr4wI?65KyT^=hD4dP2(j~!?@z6{RM1$3vSzLjrpwQ47x*hpYlP358=;a- zX_});X=V|(G!D0$(GmK>Ze3IhQP^qPy+mhAwJnx;U}(ODqBtj%rx4koHpQ ztLCOS<4-hRR8>i2Z~s1kOKnTfFiefNe_)MJrnG5Jb=BO1V@p!hB{AA31ah|Zu<>No zNwkA2WR8xu=B*)&#lk{koN6~dPzKhnzG@L|NNv4(GXq)MD%tpm?Wo=qRd0Hr46NS4 zvt=i6>XL@WSTpNR(`+CxtX&bvcD^q+%m+uQkmWu))Z+>{CN`G`g!<&245XtAdo)49 zx34$K0$DbvvN?WP zfa$o)JyWK|zSz-67xcVTuXmB4iYCjCjp`i`n4-F*_U}W(RLEI~*WphXXvbn>H9`_Se*WZv@II=G%@Z z(-5n;7SJT9@pfRUzfWiwINv#HC=0=B|A~JWeUE zsi<8zscGSySUp{xGOo6%rXuQUk-Tl1nv=B#$ngWqflg=-*1*vGH@`1aN8#zAa^`*t zBgi$CQG^g(RZm9?3C&B%0Co(D{G>H*x zJ(*D*p*lv32`yx_lu!+$vj`o-Xa%8KMym+bGg?ikl+pEs8W^o5)W~Q(p+gvLAXLui zF+y_~Z6Y+6(W`_i7!gRC?pAyKp3CM@$>uL5HSE?X^@U0;mtJ0HH^hc{9Z{r@VIBC57JV+&B$uIdrn_L9zcy}1E|pD`sq{oD8FfR`N#c%p`M$1{7KxGp$A5~lbNo~D~5%^rph&FR@ZIUywwxX%JslmpM>}HK!Tt^q^ z)igS#vi;-zuEj`EKdqJyER0Q!RnuiRbSV-48YExE;42x4)aF33??6*^V^tk(qtWoQ zC`MPk#p)Ykljkv)Vna2^8CyeZ5SqxT`5UYYsm#HNvBt{U3ipbe2D6rrH1J|R;=4qQ zF4o2MTXfm)+*+!3NrFA&f2Qwj2Gft!x*sr_c;GlZCG^)zcWTw2Y1N-Ff@5(zSDF(c z^a!IuLXR>kBJ>!ep@cqV6eaW|qY^@oGb$zY1f#JNr;Zv>dhh{L2Mt&>X!hQe|JzG7 zYR$Iv{6-mUe`4)n&Hpfp5NgdwVa=~N57zve5v+MDUp^Wo^bP01nhsOIn%{HYOhR8U zDkJnIqe?>SnYND5os1R}x{J|LLf>+^vk2YIc`FFr!)O(udl{`Jl+LwXPw3xFv6fI8 z=dCA{&1eImANc5Fgfcj9YRRYp+c#bxQ;T-u8uF;Fc8t0aYR@P_r~{)yLV1je2+0sI zR8dqBf$f%FQ3<dxhs62kla(wwsh zJ;6s;5PFi)Dnd^)T21IFM%NR1meE>5&oEj~XcMCigq~yc7@?lbc@v=*IPXBLMO6YCQD zx>4SPj0pVy>A!4&9U{gr`=rQ#&b9>)lJ9mps`D9AS@d=$PJ&nQYr zEaCYEdL6_^q1VBT2>4Q^%JJoYP4}a<&ekpVX*N?p_cn~8g#Oz;9Un36c{bZMk7PKM z5qvk35fyQ+(ROt$BgEwOj3EDC7)1%qNa`IrxJ{`%VkFH~ONaLWr7R014e9|7;iHJM zDZiS`#5^ulM2rsYR0n!|9<>=*dpaX3;!I^!NXY8}+H16QXmPYu5~uB%=0}VkC$Xge zyHRtFN}8t@pQ{$HP>Xwg(|peRHKOJ`m8GM~vW8m@ynhoTD&j0)2?+e^>HLWCV<(kp z2S$)6pAi+YdhX7g2kQj&+?6aj+Ef*zQbMWp+!sWQ9M%6d-7nHQyQuC9xpwGY!-$GF zM>C3Vi}N^dC>@P4iV{k-=iWlIyYFc;0&AZsQ%4bH@^n&fW0y0zo;)flqhoR!+6-5! zKPuHqMqyO{E5~wG`ai4mo3xeu!XtZxgnf?l;FsqaAtqm71i!qnwPvTkP1GYP%R zd1Zv~Mv62CG4~Hfb%fe5T1*Jf+?JSoj}c<7Eu$5L)-k_Tgl=WDn$Ycxt|xQ{BLdqk zEmj-tq*36-;SF40glhBR@EeW8Z#53raJeXzyQ#$z9)sp@*4YDWONU zyB1GJjMQD#ex3*K<@%_I<-wqy?%5Vg*hVGjp%OgDTwu57Rf0{7_(XMM72N<%Go5kt=ni=@ zO+#I5E-p~6h%A&d?2!gK-HwOU;JID&#Hi|OCkd%}*hwAVR6-AkbI-#kEl$sl(5K(v z5h+y_5t4--e8RVFMCi#SBzN+JGfiiaZ{-ZtdwkBx+*M>#p`2V8fnGr#GnGUp>wzof z)$*v3NJSGrw#vX{JPC?(MO*D`oW5O&&G2bbzynuOvzSWIKrpzDhBe*?!Kj2tC}a0grL3 zj~&xgh3B^EwTtw0w!}2BbZm=zo&<}yu z4&w8;@=4RK>}TckOCTT8V)P8Y>c(8!lbRlIj@}0sPGVmYN^&{F=z=9XFGv;I0q0Wa zg`$km3mu@8rpHQl4jeoOb7`1xAEisf0XKm+noME}yAKj&S*AoH`kl&skYs81=DKj3 zp$?N^vk9t!$qoCS%%#CY?k0up%^6n-zUI??|IJM&VKp8j?4xUZdVr|XsYBK|Q zhUsP>J3{sJZdco$x9Ch!-KPi2>FVx(AXv+sTM@|IR@BDxRq57xEp_6>@F<^(bB|I5 z%Ng0t!>-fD2qC$88spbOro*N4xa{22X(PFGzAo;l&CkXSTnd4^wa*0cuIm=bQq^b) z*9?tLU<8eD&9JADkrPg*3l!?qCo!fnjBbP+f)~&sc7P)BU}|@QV0Z9E(xqk1h>l? z1roo(V>R`)Rqj>ovGX<3bF^kls4>!Ircs}~{Yj2Rz|_mELG%tN9m zVoek^G=^``Hw<(O*9QZwV*~@?vh!dAZPnGs_-hlBKHA6I?SidYTa&h-=wxJw$4^ zk(x)vdDntZi_v3b=~)HQlJEwa*w<_dtVSxMJ$F6|lX$K*N`<*r6oP9-A;ZsnLk)U3 zPF+Q9ZN1q#7>zrc8p5SFb%PH=;f+A)-}dE($@(&vhODpo=ui)2m7A|<9|I5KjgvZD z-b8DE7+3>pLHdM`!rGn&M&mFI-c=3$8OT4#+Tn8Bfd@N(9mp3l+vz)%Uo^oe?P+3c z5vIv!s>v6DHHQ0w_e~l?ZW)HK#-PAZ&FK}?&N6(tVPgNFV*iv>?8LxHNmyeuBW$iu zEF3YZ10O~Fc;Xv%!^F>GI<$Z`f&5{0df2bKuAyBkca|T2(@A(l895*;cjAFH?dZ!5 zle?43-PuQndN}UK&DO_<;6|$CQbI!7_0a?=3j+CSk!=LKF?aZ@A0xDvA&gMBJb(m) zf~@Fx8m_l$$^%Gf%hG)SNraF*fTV!XXqB6Gxj2Q{u@{$y|9dMPWI+m}8=!PWN+(qE z3Hy&Mm^Lo%DKqQ@gp<0(a)}g|BF#6LRDzP82u%OwF*gCv3Ww8;i6Ar#zgM6#IJzxK zTnuN6i(z1KG3pc-!`bqT88};947bQLX5egbafFcPVsr0(n5*_xR}Bx;PFzJ^8CSJ9 zRxyEJi()?;2oJ-LCi7ajc@v+}Ffvd8(x^pAj0kgz5n)a-BFrg9ggM2CFsB$1<`g3m z;Dl1fbQ9e?`)jP4t|U-$jq>drwn<|a!XyG3)kL%e&J< zeewi|vDI0JGk1iJNeZU9J2lF~WyB zh?MwrpQ{2ZK*_Llttuv`HqZv;)CRh=#0MXN6O4cqruL<(_7#CrL2Vk?;lEgYxT-<( z<(mVUidb9!`Byc?ZH!c-)#=>_Dy0ePFrz)orO^RA zuXL$&0BR_Gob@8Zb;GvB<_mX#eS6*|6ZUPwn{C*;z~GGTp8cuQ<-F< z#e1$q-OVlFKUSCgD^M48iM04_ws4CY_?AGCzVhXU#cC=FPAqRY+I@ICoufAAT&(DU zB@^B?Yo=5!+hP(t0U=w8eWc6Bx*Ea&h*BKu5* z(88UigZ3J-*K9nNC|twDX=mF&jz*^Td=$a!>1^Z=(^+JP&LX>^F?@r*p>sahhw$#o z2s-0QCBZsR9zP~rS-V=W?-9sqCtq%uY9b<36A|q?C^Imj?p?SRsMePeRKsoH!K%&N zyJ+7OuCN2KS-KPCnB6^)DUPO+`ZF~=z9%DeSMs1+D6t>sK?%8{3`%%cl$jMlnEAvE zFrS!#KuRfKo>Bp*)N8pw4VYP-hM!1X+v` z0c~DkP7%|9PD}$j6GUNjQ?=Q~`vCgvSQ*!qII>$1zv< z@kB&Ob7OPFFI5PB$?^^OT(>OsHjNDMHA5iHh-CSd$f-ftT2ffOcPDbW2r+ zQyGEIPSVuJ)8-=H2aH!~9ZGM;oQgLY&!zdfyb3!yp56&Nwx(&}v|7B|J$mTi(MuX* zlj|$uUXD;uRAlu81w~^=MGJ~XkB!b?4;Ir8WQ+m>7s~t2W;N@v?XYq~mLeK4!Ni-ONVat_)y5eX{l6VRJ5--7D;w97}UV^{GOYoO? z3I6iDl**X6O1<=_K*`-P(OeJsf8>SG6|V_K(w$v!d7vUVno1Ib!}MZsm|hGH(~H4j zdNDXm?-?9aNMX(58a4Qz1LgGhOut@~v#{P|96wFW07Ky$0)@oUuq38~ImC1@qL>am z#dI*DXF4+ohM8`yn(o#>sr;tn4VUpjt=)?#tMev_61OOfOK}9U-w{|djs_*s9y~;Q z*g>=hFVQ~L741D-Gpu$$BZM9vTWl;xKivd7@Dqj?4cfc8Eqc!mOdKB!Hfsp{Kwx#I zTJ!xdmx9uA8VyQ&r_s!gNSLEVRdi;eYN{rBl52*Eo?!$NJr*c4OoTflXNPY_6TQCU z5*S8!E|4LPBE85*p}cpgp%Fh!Wf2`Ji|B?1Jd-6z^E%fDmEU9pmGLNE+jT-OtpiHC zQxnhi_I6g>Fvyf%OhBl_2C+G?GO5!4`427)9%3lOh8POUysx~B_+cg!)nPJGod75B z45RyqYXRM-TAxtLCmCwGd(8x0ib`|Bnu_xJituj2b{91HJdpF3zTB3`Y1d)PYh%>? zJ=cPe_>mDp;u~Mhph8H{%crK&{k*Z7xiNVORmdx-AVK1)ErJk6oMbYB zPaoxLQ=y@}z6Tn<%z4mI-c|#zN(bvrSR<6@y}k#Wkisl476dP`Aj+FflQ6p05l9WX z97Y7)A#4Y|5Af?Rlvtm!o9r<-8#FxOem#x<=7e4y|ik?mnzF(r&Dri4+&l&C|37e%1E7bP`$V?I6rwmxAd15TqBwYq;xK_I4ik8ag9<53@%|SHNEsBIzuqu&?MU_{5%qC7_}gCil1i~Z{QGAI3Th$<`H8+ zK`{o*BE|quF$T=ivMwyB0~!~Be5sDnUs1m)XB#Il9UL;A5drSV67Lk5tVdB|d#5Q8 z)CxPvJyx)j++zhh$vsxE)AR_+LE4#&(1MO&gn{5FM)cwCLl+S8_My$pAuP^xU((q`zAog!?GF4-wUn=VzmAo9;@M$TmC-I}9IJnse{z;|H@Q5@8U&xs%s zjTg6u1D;JR9F~TW)3IbSoUa_9d00xu0Z##T$6s{BAt@OLJk!_Z5JHVZ;BZ+4rO_X( zW`zFW5=I2#l1z>00!Y0fk$2JQ+!E!<0#Yd=N+*xn2a4 zgb!qq@IfF+_#luZd=N+yJ_sZUp9mod9|V$w4+2TT2Z7{;k6C_(h0j9~6F!eJA_j3u z!YAPjen?-m9mc)p&R&>S0Xbp7CnEn1XKv(L;6!m9oG7k?4B|RCQCtTnitFG+aUGl} zu8R;7*TIS6Iyg~WhaM2z!xHM0;Rkif@Pj&^j=&b+fc&tOj02v~ocavvWiE}nUSk9q z@MLBGBtrWk_q0rH{cmyx^+urbWR?F)dOHHsBS_z6gfRMy5#0R)BREU$f`_x@{%8cL z+}evEm0Nowgd~I!q;l5>KM_L-8mD)VO_I%)k_F8F z!E7lbP;j!-c1_|sI8j^&CyMLfL~$LQD6WGO#dUC^xDHMXpDl^&FxLV1u!K5;W-54_ zLh7@nAP#sNLh7@n4qO^~cVYy+@wTIo*^=DqZB3ODZV8RwZ<^}cZ<=l{BBMpOxggel z`lH!eGR2y^*39E#?JQZ4-4MUYlsGDN4%Cd z8M*Ns5h*vGBO>L-^9Z3-SM%PD=corMY*dm6L7fsID4)t`){Er_U2jI9vs1um7ESs% z2iZ^h-wCv>-bXSPhb4du0&Qd4X?tRcGen%k86r;N46;a^A>t&?5OES`@S?;SA}-Zs zzZYkz3}pQ@UIql(Bp_aN_9IRiURF}quVn{gdkQVLJ%twA&3=; z5X6c^2x3Jd1hJCp?t&K~shq_hq7kxhpaqgmbpoS9<~ga3PR%WIOn{T_?4sd;0^;cQ zNa7HhPDSYg0^^dUdRN-JgVY1HHDcJsB@SHx5u$VxK>2sG)9P;GDe7x zYDVylJQM}Kktb;&66Hx6@l%*o7uFx}Ll}q&w>Er-O<^QPP^ZKQ%9~C#jP6jDA9RN^ z0-c=#h9sWCm;n3VACOwIl>?8O1bk$mO-zaH{Vnl@NR#+Nq)B{17KtxJn#30(P2vmQ z^QJDTuED+dGCg}(oXpiYnHOl2fH={q%WpGQOzR@!a|^8svi5pT+p>Js0Jj8vv9wHg`qffh(MWl0hhzwV@^DNsbR(soJW5;#X(0_TWJ z;2d!Yoa0Se#3g9J;gc3|Ng9;{&#;7=f+h@jk8J9bmLLvz4{Yj_mStQT+MdP;p@{ct z2TxjB@NTy>OM57LW+2nEeYs)1n+OXxh_H4YR&{X@b+6!BpyVGIK}oy@JXlE@iCUni zeJvL1x-gJ09pH2^A4TYSny0zP!Za5Rpt)#ZXk603FGzC**9Xn7Vg$|c=Ez{pM;6cn z(EQKtlxu7fZe0)G)=In$;@ZGE1H}%>yq>whdh(c0G%|V2CvSr7SQV|OKPieua0aydiN?O zH!K*XS=^xXZGqMN&6gXdY@*P19aeR55Ov?nwZPyT7$Lau`pIO$r58#BymTk*&5_|2 zNo;@*21;Ore}s=Bgj)7K9?=z!69ZjFsv{4TLX(>xzo zvC-fqKH75Ah>9?csA%|gZ~-`eL4O12Zx5$k$M*-i2OJah!-kDrJU7M{hYlN7wrE~s zIlU8kH?I#ydi$Ty7^qoOmA$ETQ% z6(!MmQf(u8>KGJ`RoEOwwx?7!Adlx*;(0(ap5+T;Gs>%*Vx{F(^$o*@F~+lE=vBF7 zfw`6O)v&*w)p~%udO~GSsK*Wh*yDNS3FPrSjE)^jvd5+n;N;oWeqr5kFWY?~--uzu zCI-CdE@dh{^u4#=xxKRUKA)v+kRCrNcm;N3>$2l9B2A>N}? z=WX6oH@vE*G0rWJzn9hlS9$1@iOVKR{mpebat<>y;Mn&Da~nGvQHI~}BseQ_m9>&(!+s=lsM`(Wv${WbzZTkP9 zb{5xb1jNV9$`i=rIhbOvI7!=0-0QO0qW%6=c>;Mn=hCtABs|C0)HO9uiD8R_9+Ym) zE`uMKK>eOYkudXv3}dtp0rF({l#YE&G8`EYn{*R~oNLF5$P&TLFK=wBkHy`Sm{4Y_ z^_y&D&xz?l#DnO$V^$W=nlT%*@`8z)xq!@~2hR}^-PI3BW(@Dg0@@G)-KX@Hc+#C=9E{=F0ZbxotxNiT&8@0 zJU(XLm>>`Hsjn|zGP@>r?CffOd8W;h$NtsI6UgKF8Oi-A^#c!|K!B4s(;|PH6Ij2Y zo+(2+D{Hj#wUQ`*cUY7-#8O_H>k-?U90SDOI& zZIYzj{HAU4l-dNyZ<8c#M{i~E4>terx1DFzCP03hBxyUpX`4K+HUaY6BuU%(P21!p zwF!`C6LTKo`hfLX((4WqhK#rc5e;9Mvu@G)fV}!}nz4V9HL7=JBW{|>{7RG`kjL*} z;x|6YxS8S|LUENr_DNb7kXIK@6OK$GySsZgY?!>(cT&^BIk9>=Z8EO5sV3pHAM5iO zT^Awyh(J=u8BXWU*Z=a;`Ny5{=E0Xt89jZ-qnmHXd8Y%0&7!j}^$oM;RLz++Cf0Ct zV{P56`Sj+9ra7}48tLJOvl=SPD@vyho?Rb1w!W${#=q+t2G5EuruP=qlvg**np?l5 zj>zg}Egmv>*5sx}+6|aBB~~4y^E`5_x@ykAx{5i@S6_bd!KL55@b+gfxBBtJ+!EG=7<<{d?&D!u{`LYKFzw*vypYGE3$G=T^?qB7f4KHxsKls@(AMd|t!)g2d zQ22mz&0f!+)TQ+SYwmof$3L#hoKSdH|K2Z--+hG; z_m?#Vr5_!$M~6=yJ|MPc;&*wkU1jKw?KJiBmHk>BkSg6l4?J=5p--LC=fK|`RKI-K zgmm+J$KHK*d}8S?MOB|pNRQk%_it<79d~Qzfqy^H{C@n!dsjrCyfzIbObG!83QB_315%#|IuirD^!6esynjxV&b|`%~tb-&ybV zUq9f!tPwkRYWnHP!G~`-a<|U6U77dOv`F2JWtr8twm19-zhB#X?1sBHHAPE)xMX$i z`k#OQQQ7^HdEoHZb{W*Z(fq#r+8&FJJ$wH{S3Ysf=*r_?I^^|={^w>yFaOZ| z-naXkr)`+>-k(SHnR4VHKHkRx6&`a+t|D4?in9dw>$clm;bo#gNs%Tnf%ke8xH<)#GvvE?z{4( zSI;l{@#@^-kFG!EszWY)ZnyS@>7RC8b;rvcZ`tzg2mf0CrzOXJ{_3dmkB>Na`uQsc z{`LHW-+%7mS-bWBrpq%w?$l$aAD-BE?dHf^51o76r;|SZafh_rS3da1b5G1V?%azn zoIT>>0blR(`C*rzbH$qS;gc>s@r6$xSbX{y6*nIHz_*PrAK10ws@D!{x_d=lkJHZh z^y$aS#$S2cb*=8cd)yDV|NZU8?`NIYdhZLK?lJk+9R}ZY`mt}Eef;b@KD?uT!1-6r zcq;w&4!NhVc;~hIPF{1}!)p%OZ`h!RPM(>+--u`Kx@*U)XW!EGJ( z-E+pcS1$i^RoS6a_jisTKH`jj-gEseMvvMrPd)psJ&*73&>e5AZPl$ymB}~!TUT9_ zUoq{lj8&06CqFj$%iDi{#rzNUxca(3CGvmatqV@;kdsyU_(wY(aokk{E;f8NW#9PC z{xfdtc}LmIvkT{5_?pQ#E(ecpZ1)|pWFAUz1}|H@4buvzUS$mE$a2{`hN}@@Xuw>>}!r+yZfGxpV;ez8|J4U zIrfEHHfJvX`H6dXUYvW<+BXk*YvfV{J-CFdgHbKF!}4hKKr?6zkX}g>`V9mV&5^7k2mz^ z-u2af6Hb5jVN>qp4O#c}KlSJHZ+!c{6K5a)Ozg$`&My1^h&vN-s=l}Hv zbCSrEGA2YyNoFA-W0}fSD)W%3s1ylB%9Ip^%u_-tDWXAyLPYQ0OY8SL&Pw?|&;Pxi zb=7v(UZ4HF?{%+n?{hf18Y87}-c#|mO8j|q3Cmfhfr#V|I|`^XtZ=$CC!qE))Y+M; zbyDo&J=qSrxE6~L=4D8`*k25dQ(gb6;)gWr*Ra0T@VXx9r<;OLC|I~Zu#jx@=*wi5 z=PUL4zPu)iz_U5rKY-3KP(bYht&t6!SKGS3dcS@2z!%Q9aGr(p@B<1vEg5;;STUyO zGL?xB=z?y)uwpryzi(fWO6_XS-I*{S_4ag%wu-Kn6eVqyrOxQ;HrGLNJD*3+nghF* z2dl43TgzRidxF8`c7E-^z;Mn9*OgL=ZZW~h7f0U&Byx;DE1&pa#Q3OO%0|Psah+y; z_D6>n8}E@fE~{YqyDlB}p(x`Vcs-+|+a8yZX4U?{J)?z#+kPB35oWt*o25SLa++ME z&rKr#HuY-R^Or1_1?4`u(J-REYWd>^<;I9sSRVhQF5#8sR5>iCxKbLwI7I3s)bBTv zRCEzvp#k&74D=e;j5Y;$73#C3Smtz>acDmq$&6=!LIuqgLefcfvrYbGYk2wP!3O_YkE?xMds%q!`IZ!%mYydL^{%|>Trc}>DK=x=*u zT3Ui~wiGPitP{EYa&iejEY}mKPQMbAXbsD=6K2}2_Kz=z<#pc&`|h(3W(O9FIlAFqa&dAk3abeb_%zKeIt2RRhX`|Tcz$Nem=%h zYnvGN(2@#?)MR^`>)VrPkGGbOuGHxt>ol{1I;|dCH*0_HoqYePL!f!o-kV;3Fv*L? z;sneKpKKImt37lO@){D&fm8X(G$qefPuis#d0kt%Vb8$&o&?Bin?GEB-yrhdA;*-J zi-K-Q?sd#+H<$c=6<#0lwm4cJ#qQ*99~~-;HG8iaOqiK^PT3s$_d^y z&9RNOs-FsBIqwFM!jp;IM`6BWe7B`*@RoA+#Ip|h2SkF`T3!~CyKKw_^*3C))7G<` z=1P)cXKR66)hnOfoH?HHc5cxBrC&d$nl<0(f_gBI@;1dK4LA~ z88>EjH*QCV#rQ~udzT`_9Keg11ILtS1^7!a9p#G%z1h-~X_saPS7q zzd3NjJF%K71LhrlBJa7q?r(s3*W-5MjlS-_FrWUUY?F#lg)YpGmj-pl6)ZBZjAN+U<%V8dtUo`dlnbus{3(H|1mXFlkaVjoSOMvAt56dYx zxiI})W$Om>Uv(y(O5V4Q!u$u%@JHL&^G{Dc82=ib*TMNy;V?IQ%*;(Dj=ym(-nq6kO?dhfy`O zs-2OuOo`^kuB@cvXFScABER#rpPZ)~&d3yu)-baQP$SYXrtUL-$R12VlARnRTh0mo%TleAS1WgIp)-hhg5b z(~bG9N8=fo|M4c;k>RdNCd@CYroW~AlFD$u*yK~P$JLQh9vY5ryIwe7zH@uUYWc2h zI-;Wm{v+JjYLIXBX_3pi_b5Cm`Pp&3sP@&zOTJ&)*b%gKnzVb-x zhX$1m-)Z6XMY&8#hrWdrRdHW*rxomrINP6Xd)&B8ihS>e4lfa%oq0*Y*RGH3yk{rj zVIb11!KyJRJ8Aq;p7qh2*Zz!~6jpdY_O)(H3zdiY)hvzfin6*LFuzhZCZLdYe7_!F zmc^Kpp~THUuE`^l1h4c+8_<2Cwjv!22R?lWBL<)y5~A-NSc;o84Q-urIx@;VR|R^`eJV zd7P)|TRV>rD?M>^qO0Moo2mY8$8FKA`b5s3c9~PnkdC9+_%U@?JJG0mn0H&dN&AZI zCsCNUcH8Hs=3{aj=36>`gd`m_-V61XsjOo>A@%qt%-i+1?$5YTxkY#X>$=>;*0T*J zaUGHB&Dt>EpE2#~vsJWswXomwa8|+1niXc58E5$g;q!)7{W%ivGki_eIJoT%8EYAw z)|h;Ev*md+Bp2S!^4OyMd-zecJ8kAu%xRk@-qdY=3Fp_+SEs+R+Vso#2cJAUT{^U} z$J#q0E$Kq*+Z(3)49;c0W|rPK8oE`I@F8xRHS>_+LxYc6*N*LC%;pzAx!Y9qQ}47% zJd1(PhrRbd`15XUPa5UV`E-=f{@q$sLjLJ1;T@^peOZQFY0C^pDNGMGQAEjAUf6lj zQ7?ntiP36Rf0(}BY3(}`RW9ee3kqj!nX7+n&KA>@bu}CxAg@(xI(|2Bm1kJrJ1fJ+ z<(f};M{hUPd?jO^qS@NHUY5FeqvVr!iWKqsjC9>KW0s?K1Vi&%ESyw}sYk6>Qy0Q{ z*KpLF@ZC7c+Ew#K#CRq1*?_0XIoERARABzq^VC9Hd6UO&7jA!E?LdEeH-lYY(wjYX zObz_Uze>OSuAI)$e@N^_0=!>hr#pT1U2-p#Nh+raVX2A>jQ=%3nr0cVt)3YQUh)P) zEiatqzi<3}y^S;H8P!nkw2310|B_tQ^5>%~sh;u2$^4YDGz#ZFE)Z$ws4TFKZ%3H1 z%(v6K@1`zkabkw|Iq?36ekE(2$r1yj=bQ@BhY#K_fcHZ&S96;$RtJYl6n{zPlO4DL z%VD0Wi|0;eSZmQw{S{AJ8thlX^N@o-;rUO4w{NXaU%L3V48^0sgi~y=pM+jB+qYG1 zf?v&lZ0yG^ZmLida=DSw6VZ(qJf6_@eAJ9!-j>`M$KkE{+>*M6M@1dB-_~=Ulw$8w zDH7`sJ3o||wiUExpSqHE#tO#!qd7;N(VMOJV7}!LXRZ0Al}sDlDPMa1Hjqh^-=AnIdnt!~WO8 zCZuo0_qrbTx2kA*PfqnU-7tSs|KSD8p1WHdl|T3Cp3kTF=1^hlcA!cK_P0GpQWeIj zk1RShq@Z=dSST0PYszjy-jy(_{7yTMBf3~^1+2e`$640%SFh?qF7K`C)VF=*+qf#m zT!IT%EP?s7!-gj>jqSC9*V*i9RK0Xxn;%{`ywa&%UUt!uiUit?PmH!7|4Y zk$rEOJ2T|yh9Y-Z5TcpRG1Ki2e^0Zeo|Ss*`x#C-A+i@^VYafq552Wha^Kxt2ha1k z81<^T94LYLEk+Lv(l*J`LVozoPLBg4?@f4U=mZ2ey%$%>u*lN-?9G2ob?RM(`I=^@ zFk%0rIk)s72d|s&JS>OTFMTVe9xWxO>-6Er`DS(+Cx_^OG2W&#ZTZF~XLpC5M^>;k*IIK}fctt;08&^*ipK7P-TzO|#!am0j-&pCDI39_+`laX~jUpRARJdEZi(`r8th z$bB+vrevQM=%qJU`4|`{Rl~f%mbzvMD(Bm9pP{>7O+!5N%UPKJuD5>6LC2nd%B}Z~ zSmknlD}&|at8!i#$1U1V-}+o4yVN6J?c-AB2y51D^}QWT)3hv|vFC&?Pn}SX)$Y}K zUa-up?9kN%s@Yc3lrW!pqmo0k_TGD#KO;aE*zAA!pZvBL9oLt!r8uy0HSF9z=~As( z`ZdZ!P5t1jDQmS>$&^@=3xdJv>E`XwA5Ury#ZC`{-WPg3MH=RbyR>=uiuFDmDueUy zbsoil8_Ht0_vPlFEq#!pQqXonUEn%}>(-&-QgUJYcL^(~1Q@3!&O|Lc7NF~7Vcp^| zuyy+IbEW$SdwfUj%EYS_ns<}eD!!mkQ_tL}F36mAQbYNTGXM9sS09u!SEQ4*J4~`X zZa(A4lfyja`ibsb(t732nLVN6eLas_YCVjN@>BU`nWjFlYDd!@lohuz>3MbD$90l% zJIssfefnP9P+QUAMZQmzOfF{PLnVDhqn48HzAxq7tr}tBaWQ7wo=jf1yy{1xdBsoi z-Ybjgc-yP5;q^O4izw7=ETkk4L{t6jpeU?pZ=33sW4Q*e7k!f3x1ZwVl?;j7?#d|# z^7D5c(J^zm-q*<=ub0XiknXZs(UHx&U-oNlXTo^m$j$v59y5|_?0yCBXD`?&mGZHu zzlnc$mG%nX4)eW(mrFgzI-03EEWP!}-{#BGJbq-cU)Kv>Z(g81ouKO?pZC*sqR!0Q#jR*iAr4?Zg&5hcazmQVK$Bz{c4A);|^YK4!km``)+mSchY3U>NqaK8oT#{+if@>kJ>_k6KqdOmPIdb5V^x=2^n zk*D9k`*;8Wo$UQo|D|7_r-6<~WwbuCO+RI34Ffc8*(_b2?N*{E=D zW{pcVOSnTH`Dd7axMVfUw_AyBaQtqgw^HO47nXlK=B@j#frkEa_Qc6$hK!vz{UU`= zonU+Hy1vd<(u;;GV3~Wx%_(HYxbBYIEo>xil-X@;b>MGj4x zwWa*?{_yzWyLaiCx!KDvdmLU-7+wSWFN}Z1ZtGJ&vYU1UuF{C{F|B-JK(Xz@{;r%p zTHzC&`W2zno6_`*Vq%inl;T~l``IrI+OdtLr1bXJ)PuE068FqJYTD|T{h{Er-?7aH z9b$LVa(7kj9~V^#Gu#Q|xZOg4{f?k6W#9)&`S15#Pl`x{NxETG52@E9)1z5uR z!}&Fgr&G-=ixs`LH(n(5w3A6*x9}!)0EJLx@44(h)9&?6gOS{KRso=qZLo)3!-+fdy z$F8Wb8eaEWXx-4qsO|sk%bPqRb8FAuj+S(I5qNXN#iq8IpmWPgnfJ+i9UFzv(g$$f zhv&N}REYJvdQ4u#i(wl&+!2P9OYr_GU0f?V?upJ zGBk9r=A_8G0+lX_ZtJo=Rw=wTaJ)Bk(KveEIc0-&^a#_<5$69xZ+9ZXpzu4w5H|WUZJuA3I-@SPSa`&&NKP5)NOi+yu|V z`IcvUNpVpioP}cSF1G#7;jf<8XG&@pN?9SOG|Z9jH2wTZ;S)!c#QnKKF7Z~ z*gS4~#SYD|VfLdno)#arSYPW9$>U^x{e%&&@4EEbK^c@imZa~quHmQf zV??D4HGF>)&Tr7(-p86pIeQO({IX$lk<6mvS5R-|xR}b+vMuMJ9a4SRKDiq=t5ClV zHs!d*{y=%Tcj2PqxLps5o5^AQpHzCCkqBLLV2z;^A6u1exYUKmR}aLg|MPj5QjfEJ zPMx$l=8~1xz(FB3_NsLVMgFRbz4qHHDTtp z;70nwJ{1-bdM@`xOLsdTw06u~zM3WJ^VpKT17UFimhIHr2rnX4PoCeqafVNL-9WQz z-ICBV!Th_eJ?*I}mgLmC4~kW8wm+!!UYN(Gqej2l*5qTt*s$NXcZD-O7M5B;J2TZ4 zio~}2#MavGV>?Y%!ZMhWC3Cvfj;7r3MbR1R8|x?BS`$3z7!UE@J5iSXCNZti=*E+% z8m49EFZb@GVUHLuWJ%bi$`@Fvvz$M_zSGfIgR0KpX29psx(7_s3YsF%ta@Uror@)Y zSiLrPr?6)dVf=aidjIlM%N&}InbEU+dHXFhYs9OJPb2ora|=cNBUYnMJH~Rg4juGr zJ93ncxt;S|y?+$t8JIuy;^5`Y2~*t8P27A5!Mb02<@9YhUj2AB_>SZ7-eC8PChE&4 zONZ92GrVovlw_eg@Z+-U2y>z{Kk4Uj^wQScST$Xc%6!#~5PVi+g794aO{A12r$@SL z-y@OsSa=^vdR@8yx40G!X5-Z|yQ!Tt>x+cjwdAuJlE+2kr+r*23}uswZ^(ULpzq zY5DUb1(%yNzqM@AyWF3`cDhF7jP;jwqsiYEUr=Wkc=k57n7Oa=MnI|X^WvwP_x;aW z9H%YLS{3^3`P#PuijxRoX}`06IdhZ$mTfxp zZv!*GN0sh2E8fyD^&3h)i#ftiu2Cs^yVUwYO0HrF?VxG}&*BM-;m?yi@*AfL+1r;i zns~5Ad>n<>M+EK!TM9zr70ek`<SQtpI%<*CoT1NJap8WfUll&6{Hp+1Z+>2;?Ho!q-_(4<2B z(wTiPhKtkNNV)m+|EJge|Mu&{I}R=7hJ7Pz-ikcQR&Abu^*MS*G5(xNXa-@c*~_Xv z`wkc{>g)|O(gzKvVIIcMgsDYXJjPl3>kS{L%BCyJp-%BlyNd-o>caNQ(Nj+)}ac$_GN=Ad5~<3#dA^}4|5tVRihF4 z=`WT`AD;bcZXtcXc6>yNnKW{V;AtAjKvMqcVcf1m10(mmo{@&uNX)`zrw zP3rzdbe8@ckdJuL91>HSTd`0-|9`h1^g~p}p()V7WIbuT6uq_63H3P-A@{eq{$Fu$ z{)yBtY13nm!LFU5=0kM)7r z{VVOkp1=9Qba&TfqbFaETv{T`d2-}1n~xKp0+o<0yMbfG)G^=hntA&JOtEDp;DAO}U!sH3+NHn#5g-4dBtexR+73&D=skI8T}eJQA`Ly4`pb2Dx0N^@(*qXd_6u5E;rX=2xRwS`6$SUTnIOqopP&|0sn!6mlQE^Nuxr+(AfV zmQna9wvrrju__|6K6Zn$q?~t0V5#!D3QssM3h@?j-??R3Pul-seN@IuXD*svH-qg8 zyg6$!J|@?XO*vu@rUz3bk)5u4WWeNP?ZDhRGLfeJ<0qR(FQRmt40_y3TMGRrr+nGF{*|~2 zW6eS18!~43uz$kw@;|)}_T$?uYH^1X*iYrR6?dpUQ$V=PP5g1!Dwk>gU)%q0uTTGN zJvfeiKkZRn#Nd(v=fN3qrs{8(uGsV{NMDQ(e<-6{U`t6@;{ zBiNp?eX&m$JFC!9sOM>Pglx`*{Q%zg!1)9ABbbNt<$r2F>(iI4qrP@a{#*7Z>R-`4 zP_HVJ8~7-C>%%qz^dGJ#r1|&j6w>`Jn-Ji90Lx8Ja`u4ELYpQ*v>AWPbIq-keq`-J5e&H+S4tm$=&3xB}XN^BrlN zp`XyNP%-c97!MscS*eT7-ojkEQ1@Eq)t(()6t5`nIit^P^ z58fZ26YVH|@pLd4>SvqfRd8<+mE4@4e8JRYJLBy`FIM{I_gKHHD&#WFD;9?Fh4c8| z^3a}CYr%kT>ZBZL9@bZHfZ`{w{UdeKa?(7s_iTDix>dw>O6uop^*-lE>FkKm=J1G2 zESl7LodFG7t3UC9VLtZ!2GWKqpb=jcV+hVf7WBj`CU1)`+fD9qu=Dq z$xa=%hzb%*^fVh6vW9x_{;%b{_s)8bJv4$VXx3B*85L-~cu}2IEOmpFlWciaA#qQ| z1^Qe1?&ism+5qVf@7{d<>SEu!YKyP`uu@^y^Qlgk+x1;WrW9Rqw;JNt?^%4jG4fJ$ zG3>u^9Krho(mb5sj336SJ{Xt^C7s_GauaY;Bdg3$**xE{yhEhWo3FZ2pb>I)(r2 z{~)KW{)#(*E8yM!C*eCy4>)A!=9%4ic{=(r)RP)A zl>b{Ejz4Jcf1AG=@jNB)owGO8Bh8cQla`a_A%9BP(SON9y&}gBE&8asbviJP&zrxp zFxarIoR)DOSMu#}hIV26VIDqTf%*C3@~WeFmz+cNgNijD8{7Jw4UH{3-}f!uVi4gH z9VXOcsHj_X%&#QM+Ht*xSjp9H=6~8Vu{Jnm%TvP#F(vsLS_O4w&<>pE;rJ3+c|@L2 zdqjnFe4Wo0D^dFqBLv46yw6J-4#+XJFwJ+E_;O{(5`qe>cj2&rh%XJzt*9k3i@W=` z?SuA6>kaphq~%*^Mk%JqXmfvZZVIm0wW0~?3JhKw4i2(E(XHRH&;G@RZKT(E(XCWG zxgxTz=4MIs=D_9B@Vbn|wr=;#5$?nywQkBpHZymJ&*^Kw-z?3k3|G2$mfIY1Nqo93 zyOma(=&y+4+p5SX2IpY;hC`Rbm{jc`9Hw_4||U80ar z%Plp>eQN0u%hs*=YB|&x4(plA!>pRy{&NWx)8l9EI{Am;eJq^UA*a~RJAE=G`F-~y zY0hl-A{N-cF75i{o>`T5iL`(5_uJmPSsB;()H-ga>--hI49;QBzE{&8q#R>g6q(3L zsX^C?&&(6cJ*Usqj<`)OU*iGo#tN~NGkQF*s&GsFW_XuUe7<(r{kl%kYgy43xbBkf zV_^P&yB~u0SFj(!{!W^Q@%L#WuZnU~DkCk2{fE?Vs1NG_^Z!%7p8WG<|sNCyv5)IY6(nYTLg2(@LNBR7bvd-aKD@Nb5(MhxnP#?w< z=Ak`UPtyF~;?nyiGB=MU?`y+d%e+p}m&`COnnHVf{h2=%jOuJ8Zc&Fv_K@CEw^{Gk@{58ElYt+ZqKDM`8EV-1&?JGCX0ch*dN z_SinG)S^_FR6L^yfECl&g(W z*}Xdd>L=5{F0v_#rm0&=#p=3TO#dkl@5|u+6Y3wQB8*O+Z!_+{JUYm;FHarzgAJ3< z&rWq}TP63`@g6<3{}Q}E?u#-rS@h-W$(e!Wku+bwH~&;4UzsK)a9C;Q|PJ;qy*Dh{AY>msiQC73Km@l7-+t(LT zNaueX=x$owDqYbyH0mLEiaEc+ba?v6WS3AF#dsdOs59NF7}X4MHJ;A{oi#Jx#Y~I+ zZWgTzT%2>V(u?3{yQ##MeT9SHqL_ZT1lkcmkAB1M<5Ca)9PxQ}>xp#0&*yEAuS9`2_g57(pcN>h=-(ea-R)#?mY?sXTSKk)s; z2Sxn+eTTT2hHXS{eH4n#g3sq52k&1qjW>P>{6>Ea+JpD?NfBX<`MG<$)*QKTQ~!$k zAk4#`1XD-ZlONR2Zh1Aee06(uc@4$Vm0E#P(Q4M?&gbM+>RlJO zI)>hwo@ZGad0J!knY5{g!{}jo#O^v%U<%-t_V5ip+!d7U zRqU+EYzk$K+c)JMXlzI=Y|^3?bYm?yP2xR$k@ zpVBD|>Wk_0&n$h}cKXG0Cv)ZfSy@MRn;-f4xm}U*KBEx@zr;oEfi16tlzQ&640wIX zqn5Y}uY=`$hKA318!}qE)T(n&6h0;6Hm)DKV@6j6%Y%5Fw8A!FkI;Vgm*&{MOMR4? zYaw^MJwi*g#VeLn2io~zFycC)5=Ket$0ENDk;b2%p{@B0d2;uYMD6oUo?Uvncg%Mi z&B>?&D%st6g5g5i*7^q-X!dD@_m-1h5A~s+r1qhIuzbFH{I|+SUxZatY}RA>o1Z`S zAK6*XW;{V!Ux5o5lilBU#Leetu5OfYPQv#%7?&~y$4+O#tc1VSdp>(_mw0}j^pJTy zpS@H{_HRqa95y)}OFX@Osi0G{eWK?j!DFB1KC=EMzc21GjKkCUR-!+#`tKlMIVn)dNSD$YWUcs<9n+n$RS^Z%9 zBH@7vQojn%7uYL!)5VBNJ$iYkEY z&h3EX9nPOUY?J=xmzM8?<1TMH^LR(hi7bcwWd1He{?G9GLpGi_C(KKZ>FBOxP0n>T zI4!=p*GlbD3aOrlntM{fOh+BmgV&w8U-7!>(8}}ek>&k`;rAX)JiAZVIVPT1NHx|@ z8Gh85Ms=G1*f7OnnH^@V5;g8`4BmwG`sz(|L^q!r`9MFkrDAsvi?(Oh+Yh&NDOh4C zLx*e)qOyhKy!w_Zq(|ma4jJFRa%6W=g(md3^FrseW-i7rSSj_ z{q{l9^Dur3Js)Q~eTU6v#n&G)%+#DKqKi%lY<~Ijtl5Rl5w`N4C%t{*{n=bb z2b5X6efA$qiB`l$DE69ZDmP=kxT;p`JTRV8UShg8rOu^(dTDd;A@--s z{-bm|Zf%xPr&F1mXV|3sfsqKYi7YB+54v}-ec{g&LIomQJNDnVRnI)-`s$GQeDi1J zCbsS!e1kkpvRN1Rq$@m?tUK4NUd|^n-*~mH4pC^8Zm}Sp2jD!h>iYQ^GU@dG`L2ia z!F>L}@;8(zSFdN@KQ$i**V)$+G;+~H6J(_85gZpcHeHsDC9Llwo&TVn_Zx*33r6WF zNw0_ckTY6$?xolE3mK$3&<^D0^B0!KW_+Iz+kYW`K6{t_*V|QZZCN{?ovjbvuX}C2 z{Ox?#Hy(ELF?1aEn9q;xi7VQB)(h;OPycH0&(7e+Pp$LmuSn=(+tVSVX%B84m(5fw)87oHvoiT@7M1HON!`XC;u_Lnpl_wP zX{7X-%Hep0dbsY0d2T7ped_atbX~gi{^>4xdEF$ZAPaRP$`FtF{9q8Ij`A3qEdQGy z`gv`hF7F#6=JR8Rh<)kVf}P0v2>tNBGoF)o_k{C&ehlkh4|#Qu_riSTarp&z>#ZXz z=Zp7L3S+Q<0I%uTZV8zcvLfDaU4`qect17EiZzdWN&Sa$-k=%#G{^0`edneJWF{i_ z-z{UO`{Wecb9;qu7E?bR%UxIx1?#WT@ArAB&F81quDz0Pb}?%F%}#Pt#T(^lLDBi_ z=ygkdd(;*&I-i~J=~KLFi%k6ID~IFg<@$;x+mE-Z%ojJveJk3sgp;Er^KW{5gFAI> z`U&1%o+n-vw<>0k?(<;0d4 z?;8yc+pDGVo`H5Vk2vCA{GNT)&n;e1c%j1H7sYw5gGdcWV`8>JE$HyE#vY(h21>&EVr z_Fs6vb)%|>`3QF*e;8&*01B7*mZ$)ordjlaV#~yuPUH|biYpO&pO)4%-p6AKS}3t zCcDRZtMfRM6hd;$4R+MG!TUq6)m;Lr{W~^79a{D5!%Ihe*c$2`QV+3wRfCZkc)dt5WwTzi@ysL8h&XJ50~)K#}clCQ;4@=7L+1|Y2-O1|b z39oDKrJWsV@s&Krthk-SnCTUJ&57kd?;5PUc)fM!L%kBR#Z(uIg>^>z>&f0mRm3fm zTcv7rr*m5|rTN(dXI>nmzG?C7ddSyHHCxSZt6TT>C+&j%lFk<&*UFt_-g|odZ+>;A zKU8mPZgrZ^FAeX{{DjL_sps=+{hRUAC3j@%7V6i`D#N`6`(`9b?ZG&~cx-c@C=7gY zm32P5x7xHU7Rx;mA+-zl2d?#Jd46~o=#sA6^Tq4Jjf+<&-))Han_t!)%CD(xF0#z$ zSM3Tbcbzuhv-A12Cst7|>pahzh5B`=N?=jLwydtd%^%JMNAjj4@>czA-rDo6?Td-v zjbhUA4(9_6W=^NFckRj>{AtW~tnbtOo81)q_S08Xa?bqC?j1g}-MltrP4jV0n-0!= zGP&MaZJ3uxQRUOz`!20|-Lp zcI&TgkZu{+p4?l3ZULfl`?;<64`d!Rj z|B3e!`rOmxV;zQPQ%;P&IWk;WSAYBGyVPJ|Rz>y8;;gYD4N{!1qYEXwwyVIr_-B*w z?NQ6#QfGYX2`wr#4v}EW;b8DO))o9zP$b1{xkuT7v{Mp$76qKOl)W`$AUFJdgLa(o z@`vk8yPX77EACp$O>Mcx_|tK%&OWuz#nVpDPMdDc{aC#P=EaPdv>Kin9~DqKq+`w8 zNXc8QcFQ4Py4xvOeoxtQIx2gwoOF)^SNJ@#j!ej12$?QkpEA~5>tP$J*%tdgY>diF z@V(L%srT!u-Rk#MJYTE-<#2QH{RSIN0jG6o_xrlmlulMP7cG0W!!MD)cZaOkc<-1{ zNAQhfJME60Nu=el9(=Xfvezv6TGB?E$hGoL`)=p?J{l}le%WosQIq2$?A@}~)25_S zJVaf8d0Jx9eTQzcn0D($;r;m6XM(iV!qNVysI8@=9~Jq}pZM27Z#`sX<|-;K9zjm- z`|FIm;}KDNOEUahoM+F7S~_E2s^xBlOORv#3FHmWcl1Z(e%`{0v?~Am57}@hjJrGyRyg zMr@r5FcFv&_!nX0iINOIN34T?7dwHx5If?&&NyqNpgQ<>$rH%gFq7QaD?BYC(m4*! z;NJvKAjj?C{*0ft^Cf0xeWn4-HVnYOj(ekDyBul@j}w7>IflZfqCspe1q`&cn|kp} zl)+2?_2+bXrZCDZo5S#_8s0(~x;ae4lOr)GLqCVHS4mm!-ncds6V(D1o8>2ufnmj3emy7p!2UfYXHNBRTt`TAUd3Y$-r#k{z#mc--Y_K z7BE|}0Ahm%Bu*lo*)hlk7&tC8Q=6=bnb{cPBbY!wiXXB6w)?xVK|tCTJhM6&fVVE5 zxQT4d>hNM`3FHx&&v@_exD}{~>hJ+ZnrJNZ66wtP%numo^APVHS(L%QJNe(fir0&n zne_+%p0&UEvmP*PMElr_dp=W z!;jB0coHV^XI4iPJ4+z{vkv}s9t85WL^`5~jyPaeV$R^R`Ri|D1E@dvcV807k7K|V z>=mBGiF9V$O9DIlZ(E$tCVzr5_;<|x%i!@r8A-t4ErQ2~ziURBn3=6R{{8L*@?-cB z`>!_By%qHtpD79C`>?v>Ga8;YAwF-$&d&9Rn3=UD4H#Mci2di_P$)%h$p8i)%M92n zJV_JTn$^K0M<9pmcK+~A3seVKA(zA|j?ag9+Jfldqx^3=@_-@MkwbJ87NCO-UCfp^ zkv|HE&ejF!C?Psq5uI&wbSC)o)6w{B2h3U`f3_hy$_vm@L3ET69aX^KqXRQX);h%f zo3%*|Fj*J?$Ehl!qYju$7=ta}WL~49*q20O9c9iMrvaF9Z2Mw^y~2|^kNT7<}Hveg5e-bp*Aw6EM8L{J}D0nnbo{b+iD3&j)ytd}}p~ z>S$vn1oB?&2>YrQqN4+t!@q33-uVh!&`9f!EoqnzEjIV!p5aLc(b2`u63Bxw9efu! z>BGGh)xpAwF}xUnH55p?hz`E>CXipjj`%nX;g`LP>gWT;6dUYtjoXdr>;cSitSb0! zpl-6~8>)kQf$b%T=FB~aj=>zAehL11RA(PxY>0FW5S{&iNy3i!K0(Kz%oo)$1Pmpn zgYP`>w4X?4wvQda&i*?enuYtsql^(?@Ochv4l?g!Ykg7X;2dU$b4U=%7|&rCe2#~s zjL95^|9I;elraSizO%*s5%5m%BW7m%vl(DkU;y4%ACHOuW{ook%xWw?QrIgznGwZj zRtKB1vG{DpbTEueNjUK$8fQzu+{X;zDLeSaRm(4?4T|1F-XkJ+HwO7zI(xI%svvk z6|Fnon%I1Z0eE}h$qlguc2NJ^o8z{KnOR$SlnCU1ZZ8kO;QIvFUdM@S&FXjpW;Mp( z>ys(FtN`k>7hv!?3bvOgk@N<2X8Nw@tMQm?M2MY`f~y>c+bb@%=gtq{Nv$B>wrwG|4OD6Frp#9rNz{jQAK3Iohetiy|9ukaL# z*b2wa639icBPK-_5ItCmG7*3w_6KDm0Rz`K#V(~SC=)e@xnRP52xX$@FqbZ#kVBc6 zIn0Mw!rCZvehwqc!C{Irv2z#-qm`~G69*W$Uf_EPl!>3i;A;voGuvJXfcbMjOau)6 z+y?fI1f;z#0EW0Nh?!Yi*piR6DeQ+0hcd8=lJ-MW>w0n>|}#``LsE)m(9)wzP5{o6QA0gN<}&sT_aX6N3kfFX_#F*9rH z8emK@9Tx1>JE>(HsL!c@d5JZIIra)q*AQE2*x7&AWqry-3Y57%hrypMqfGi7=DL7u z0Lt8$!+40K@(?q#^~wOupZi!QVAc`EFaxPq)*M^-dO^(0+PVptpV$$P^^ig6Lo|lB z029CH-?j24Vk;Xku)XlL5@mAcF!)+Y%*^_88!%vJg1y?5@eQjX_HWMIn+q6WY;uPC zjoXMncK`$Z!RwAPcL4+Egr*5yYhq^BpFF_GV@KSJYMPbUghc93K49?sTzr3sr#vEm zW_1d%vjp<5*oJLA_Udt+5w?*b)hPrF*(x%!d)O;H6%gsnj*BAf?7w{#e;$r9_|^Y1 z)#WogP^NeegFkymnfr4X{JA>Hl+0o9=lm%1U=DLwmA(pPux>}>bJpOZr^L)`3`+qc zhaa*3qN(@T&={5h2HzjTwkRcv;jGT11?W5m%uXVmM~F^2V7Ra&-jZ9|CTdWBDgYyg z>0rYLq;f>35-|8Z9ImtPX(uPD^8_%s4&JBnREg+RVP^^Ccx><_x=jdMs7d=+HC93( zUrgjr6{3Sx17pN-5iC_!t(ih~YOxXmxg2H;#<>R3sRN8KE`p_;I96<$A@!#oE5V*I zVy9uf>JXgtM!;Mn(rG|+ngH|X_%s7XohUv{h)xS&^spnIs=RXb(Rw|_N(kiL zm@%xAg4BZOv;u}7JK|CCajX_Zb)Es{G6rB%2S}}mP8(o&up_Q>Cq`BS)oBL|u}&MJ z(*c-2`|}(yF+~1!AUd6Z`LjPS025E7(~0Q31k9h?>lI+O61CS$M5k*3IoV-m-H6Ux!2G#hJ%I5hs@GdYr*{E5?*Ma#NT(Ok>05wK zKVU40bovmT_Y2VZ02o&yo%e{&#|7wo0?bz;osWplzyfqW0|wu#FT!5oX#mj~#Lg1P z|2!^+0Aotjp9c}0FM#>;xEMxsz92dy3-D(YFz+#cV7*2Vov#b<=Nn*JiFCdqI%5m) zXB;puiFC#gorwkb^BpjCL^>0Q&Lm*|Jif3c4Qo^UUIxZz64Cjw03B=!z;v33bbcT@ zGYincmPSmcgGgrv(ZQ#kzpd~1hj<9&RYW>uoSZF1)@W_ z039m8yvL4EhZ50Q1Q>qIOU&Fn>mW5?^f3UggNqOyd{;vt|MU2w0Sx}!2I?$Ebd~_d zR_FW6)VBh5=4gB2%$RkfLVtfaeH{8Lv$Db^XGBF2pD|jh5j%gI!p`DVFnDoLO~rSL}xi* z;4`bYgBspwy;uN)_cU0q<%kX|VDKk|)YyN*NiD1^k+v89jtqg^5>&Yrf`pGez+ z8!-580qSreIy`{+bA0eS?z!>dL3H>4ZSKWK z-`sW=Ky=nGKt~YKS&!%l0p`!~5e5vt>wx`72+0(2w*gWt_ToehZ2M!-~KN4zhFo>Im(_@wp1 zKedA0qhU^SgIZyq2Ss!?0p`!+LJBbWZVLA2O^6QuPA-AG{Fl$?`b~fH97!55F_X9r;L-4ygk1JTi3 zfDZojj6jaxg+U!nL`Q1@I@*9CUN5u|9i0W}>_Ys}L3DHh^XGA)2N>e{M;FoA4VXWV zQ+>b?ucx~aojrj0b9?Ot%mh)K_aHh33((nz=olb6`vH^mYn%?c+V-OT&=4@CSoef` zt^J4&-jfOBdoUfm7jLAK!yX!u_Gcr&e8G-z-8q2h90bgt+sha*Rlj`3evlnRbW8yA z=Qx`JhIm|?Ha~z!Unq{!p*b6fJ z{YqkH_8tv?`br?D`NeSc>tYWIR%)l*b&Aj5Yah3N9Xtc1R*-75uG!0 zbbjy8S-{{sH|Wn9MCaTbo!|QtjOd(0bVBCn{NA5Xz=UA^2Kp0%=!7jmCmhiULv$h* zpc4t02qJ$X5S=K%&|(bsf=nixRT%Bh(TGkIq7wrcIKH|+x?oEO>9{zL=)@p8v4Da8 zEKNW3oADKg=)@vA@pJrPJv@eO2T1)%0L&Sp_{1YRiF0&*-|iOx6G)_!i0E9Lqx1Xt zBq2H%5uM~YI=}DFmjFXtuVh5$GGOpI6_3i3Wd*y@_*?-D){y_KDVGtQlm+Nq1q|_C zD+STH1{gQY7QSz5C=th8BWodUpgW91IOv_`(ZtzQ-|m@0EX*Vy?#GGHv)!uyf+{^O@M*^{C?hO2243-3&y7j(P;q; z*B||P3K(L4S`eMq1?W5j%vU0RS`nQ#z?fkSe&0BgF|iMAuXex?ucvK@P6uFMe16|v z&jB+*Kvtx z#^*I)@b|mnKA{WI=?2W7+Hk;_oNB!vs3~{^nAv*5?v+Y-$J9q5Hwm78o&j-NZ z6^G;NJ)-k*0Xm-mL%i;MM05rgpz|3pKQN!6KLbQM9+p@E*&tx>`wP4_XX4fxqV*aA z%r5MRGk6+AbiOP=XBaR$iFCdY>C8S)7y-=USuNkdbiM)xpEK}O z6PbJ()%gY(d?ttS`HJX_EkI`+Fr`E~V~Ebg0(8Cu248uhKNE<~{5%}9+CFvX~5udhVAhK(U}1ZHpoFT^WU}>)%gh+eBOXMGl&juoIt*E zR)$O=Au|ruAqNaT5}^(m1>VAQKK}z4j$b-4wG@M>4goOuj0bfn5FLEB#QrAFFP*Zo zhuDW_u~TzCCqo4od?trFl!(qEz^wYEBV1&+7uBH#48B4^okfVwV!-fVIv7TlCdwX+ z>d*it1OwnazZlV30vPPewGO95kp>EQDMo|Ygww1DBl%CHw?*Z63#553~A zh(AZP3^3l94(x}thz=cK@OH;AG9lTF-`rQy1ICm{hYrzUSbz>AqQijbFfBlb88G-f z2J6Ly=-|J#G~1u&uNMoVvmDW31q>G!8|=kAab5wK_gFdfhZWJmpA!80`=`HeFLuD- z;}q(!Av!AogO3ZmUT25X525Y83NY~)umof9v=Y(5e?xP2e9f=J0hlvHI;#<#HGtWP z*}#3aiqScR`ojsBwb&8%=QTt+$8iVA@X~*OuLS?QPsGgZ+QbDI28_miPP}{NH=jl4 z223|r4r9ngWNTK32Qcm!gS{X#lw`s_;EyX3j~!mXT*FS|_VC1m=n)4w)X0c}%Z!0f{uhHWZDRIgbb5x^Y5m=%~${f_pZ z(fEi02Cp5|5kYjs0P_ITz~{|R6$f=t9dW?m4GQO8F+^trVDM*pc;Db!F8Q0imIPpw zu_Jtcc>|)e5it0kAJ-9Ivfc!Zk0fABiF7t1I-3CFjcMTTH?1Gla6omW0E2%v75cLY z(b)_byhYeCo#=5%tP5b7IsI80FpII}dM#Fhr_G3t3}Eo5>$t72pFjNOo@fhTTCq3d z*5V>ql0kH20fXOH;pv{+@!#wLhBBG-N82FyTsw6IKYQRp-@n;)gmSZu5I!cJn_BlGg zfA)^|Kms}DD6oM2Alr`Ur~n3k{}eMvwz^~hTY|7tbNo>Sj4+WuDu|BS0(8^?vyMnd z4bjm6j2Pwt);-9q4}=Gz{_FruDOL{KT?5h41PseBTaPHRI??gI6ELorp>>!Ro-~Pc zX6IEcz~J)=9v}SoYKfWIIZ7Ka0a!Uc1~mso;!#^VfYHY~G~6F+Ber(Uv4yW+#LTQM zUBKXW@T5`gmxjhi4>0(>C+x4fM7Cyib^`{+?|>n77OI2K7zA=@Ob2qi5uH7Nf#dY| z<7+Qqx-oyD&K^X^05I4_7NnQ}UrW><{8RDR?=oQiu>Rr<5S{&islwV+6k}+|u34jP zVF(ygPV8CKFP;5FItjWx&CRCF`vWy-XDuO%o$PISgsNX2;H9z;t7M2k+01-0dHteasFprWhdjtB)N<`q+^< zw(vb0%Gl3gk`KAWp^O7yV7nJ~%hnMyvpzclhV7RxkJy&JL&w)qz!+iU3-9-MawPJ3 zR>ui2Dzn98It&-RP#tH$ti_Jdo)eHX?= z*vQ9D%~`+P0fRr?g8OhcMCTY_{=DuS2Mqqy1?~@zAvzul(D4L}FLs3cF%Lw?3ovq^ zR#+T4^|4gcotOqbc7A`a=MR`VOb7NuKO&vk`8fbEaDK+uN@8ZVuLc6f_m?ei(XZQ4 zpHBhiD|Uo^BM`B58Zh|tD9k0YmXt9{lnDY1oa@e|eS3~FXXY?Ix4fPaGqXOQ1q|0O zTcdkl=P1{XWCj>BTm=4@$1|vG5fPwAFw?Q9!6pfvl z(+|S{vzkaJ6wwJ^fKCLW6OQOa0_M;A=P1As@1G+Po#;6_zu!N{044;hE%pMWXhi2c zVE(*+js*+l%GeTl)gidbe&dnE#97dDW2XRAe) zK%_G}zAgX;jxT)QOU%snv5SBS$27ox^#3t-Cg3_&-5Wp0EEyB2%<~k-5KNIpqX{r9@}+G{_{e*Z4d^>x0w&;48X-s{=V z@IL1~@A>kbx_1G~lfu|xW z#Kl!@Nw1&H|J45a2%Zim%dL$ikt|#1V|d*8r~D&r8isY2!V`VH^KnpT89eT~J+omO z(*`4{@hpd@q8X3NTNcz=0S`SRF}Ap5=TEH+>#T&Qd!&aef;y|e#ih0iNjEhUMYg>>N_1LWK@YFNorFB^Nf1maV=d}Z#S>~&o z*Y-%3t+Nvzb1>ZDeE2y$RL$-8osl|rzkdNwbiYSEHft9=ea)gbgN@t$+dpRbH2UZ> z^Dp69Z;o=jslxov~r3+o(Io>_U$H48n5lqdTa?>rfL zzEz(4hV|V=gq|bH6MM`@l_&Pxk10>=tmDcPJL`n<#LhZ-7oP8wCw6~M zDNpZ|Tds!vIjuayleAtGdd?_M(;>OnhMw=0r|pQ(YKER4lqdFj{!w}8{wJ(+R(aA@ zUSBWt{G>eFhKznA^qhmIusIjd*`oFf!$yRjpH-dMJv^^Gv3vLnJoFrZvRV)8-8Rg+ z0FQgEN1xRhdVW&g(v!VYJLyS;s1ljT`%a_SJY#(=vBG@{ifKj(f)vEf*FhX z7i`xeS+>q~c=VWWzwZ1A&scN6;ob*xJyOSB<8Htc9dp!Uv;Km|T;8$G_^#(yVSoOH zCx;n=du{MnB+J&h36B{Lw%E_rZ^3iTI9#2ZL7ji#ao?X)c+!{Qc>aYa`Wob)pw54) zPVCn*bj3Emw;q|-e?cAk_`k&QZalH;B!cH;q)vQdT5Zwy2qlJxekN=N7Plbzxa#4& zlEBl?7~J!X#6g{;cTp!9Jl!L8k_L5>!{c6`#(u9_3V3!!=9N6ClkzU=+yl?nNS%~H zom6*G=U#ZC?^R0`)Jc68b<)7IIWnHqL7lYlWHbAUwj^(qi}5@v9XuD!_uc+V8`Mb; zk2^-s&iv8bzR?PZ-a}>x>ZA|q+y@W6&NIV~tG9Q4jQeMLcWYw&?IE{b?+fbOe;0K! z!E+^1B~mAMP$w@uuFrp8Z)KMD?fuCI&&f!gyg{A(s!l?=Ugpu> z?R5$Sb@B&w3aUEWKD%gk@9lL8!E-h;o`ON0!tl7Cb#MJ`p?L{@dmZ|OWP81E^Di9K zDGHB!FKE-rzqAhPJOU40FI=6XL7igoxb-t*Pu|DFI>q5R8ktwIpiTlj?)7x(!LMx# z>y)r{BI8L2>Xd}Xy+7*pk?GB=;@kUE3Z6reIwgZTrQtCL6}CCao?IB#c@!S{`IqZY z>7Y)TyQo9I6{z=DnV?QNc+&EC)@ChiF44Eo>oIuFN5)ews8e3mDfn!OYGEDvbYJuN zNRc|_gE~*ZpTe$oey1qo(SqxfalJAt_V+bUKN5mmEdvveZWtB)`a7! z3=chnb>pcN)OiXX*XP*%c^V$NA9Hn{3hGpWr=s!Dvz@9hZZPK`^B?MZS{0s$&2Dth zPpbrVs=@QVAt|fc+&({rb)JET`t0gd3+hydhx$yTI8(n>^RPe9!ZXb!xyv z$2--D{rPn@;V~yTInUP!>O2RJIXJP+yLWWia6Gl(iT)hzxu8yMcPoEF>7rk4_d{(CkGY{&p z)s58Y4W+&s552!7^fXW&dhbf;X{bE(ye0I!2u~4{OFcYPZvMs4(@52!_w9t9#_;6e zI_1VClnXsg?xIdp_9yS+L^TGn#fJhyCEf@rkyEah|L(gF4p>smi zW9Kyl9`glT?0F4^C;HlINMt;=&M#aQI3Vr+9m;_IeNS$|rI`6_m&)(^oZ|wK0zXwn6NS$|sI`6|{ zzF>>ppULo)GIh*gvArMEnF7xN^If|4&Gg==?%}+q!gJIN*d5DLB6aLO{Qw@fPw9Q9 zp=X-%&@=qdGaVlDkPde}6^g7(9QD|JIz#Hvqze6S#pH0zGvO%^>EVpXm~EX|@TBCd z=Pso@AJ&--j|sruro34}ojGbeao?1S@iUIO!Fc8bb>^w@#Qwad`N4SR1$7q4c+B+U zmfZW_u5exp;i31yxV5n$sIv&3nx+PwTVlWW@GiW7o!FH6A+8M?H35 zEP=(8o49lI~qz~hcn>QCrd3s1B^QIDP1I(WSymkh4zJMn+HOFlK+`9f-*q>eSOp4U`BB=8v zJoI}&v^IK=e=2)eXE!`An>ucPeHqmG3ZAlDr|xevmWFlqz|${M=c}O3UU;51bi+b!D+XoNrQ`$Zl+H_BtwI7}<=KF4+ z?u%sEItQeVncDyJ?CT&rHzIWo1a%I2=soD=d;klBs|S;tfsy}k%N$CZc1 z6ZP2foPejO$)FiOllyTq{M+Y#5}rem^>ZQ^&v)>+_u;q5Hl;_@W3x`dlb^E+4NW{P z%sLIv!zRmJ-%mxdY@IXkxG@i0a=BDk=X-eam>#;ddL~lG?yn!YF7|kIni~ zWo0k?!rCzFEIf1;qJ2->k3rT?Dr?L;qen+QHtQTb<_osi=kTB5i5?f{B3ZW1d3fml zkhXI_Y?&O6`4@N&neV&f>wHk>0zB?q_+Z($iidT6g@1$C~&L+hDl^YYRyG0x$C!c*MT zar^apQ0E3bHBAkgd+ht?zu@U@g52?SBT~m6Uw^|BJs(CrcCFrohwih?kp7>a7uiW< z^XuhA@Dz#kFg^)g71aBG;Bh^^`c16Q@=5{^{rt=M5(jmX!gJ?+nhc%}=BxSP7`CL5 zI(DBXhbOvEqaM32QrtyWN_f_rukIc@MUZt*kQMdVtW@y0pPTRK_Ee15u=m0feNK`p zl4a|pzKc3(;E6upNFCHk3(uYVOz(k-#dU&FJj(Y5vGr&XVA3Ao9 z*V|xjVN6kV-*O*3Gakf5iigJg;Ddj559jp|JaoNq*RKa7S+>r@ zs!pvRlMN5+WQ8aC+~(n+PBwV%{M;rxJd@3MXiw6XEvS=2ji=S=aofW2BdC*0 zjVJbVo7};8as_qhF3W!&QS9e7dEtpZx5*RK$p_D!kDdJRM4#K_i`22}kX}vu@z8y5 z)MNK)L3qrIE^Mji_x&#HVIg?v?!XA_Ydl4a{ugU4M<^CYaS687gA zc?#HSHb*jU&%B0X8U$p^0{u$PJ7M?}sYc4ySxayHQw$C--aeb!e0HLR*^3cAB zdhEQOgU6i@o|y2~fN(su;CaRz7p_0gMaE<6)P|?OX*9iOJ-@m);Jh*Q%K)~?zT=#c--;+TY=rj!XCDQr!%h&YGTWvPHQ!u z*yo>D;fbDqS_gI7!1KDvpx3%53tcyd3!SN>&njPor&Q$p((6QUkF z_jd4%EpDr?fruTq4bKFae+*IBtj&l}29BzLN-p{FlArFhJpOXNNfdip6(g%l_A zgr5G&^XK!U8i$?%%9H!-+BKnPpz`$n?`EygGYFmp9`ly6R|bck!OGM4^6KA1&k&WB zr%lyGp=YS7GyH?a*F(=R(3qZDnqYN& zy$KKf4AES|u#E}ojD?4eQQCI=_4UHA&Rg*0G36hywz#oDopJDtH{YjwwiLV9H45vD zhliec(>0g2aY3C4@Z>Pxqw7%0xm4)c9?uQeg4GZ7wh8-=b6A2@$|Smzyh zR!8bg4C+j}i#qSZb2d_EQc&kTcqZ_8%054HS2&*c;TdK6?5?Tr1$8FF^Ay)<`NfhY zVVx=P(EGLAv&zXqovHAcix$@NphuqgA*}NOJQ>Y`FJXMNO^wvC=jUngxNGHac~+GV zJ=2wk-k%Wl*yCabJha};u;YFmpQ3Fzo|*6*GT(RmeMV$Fw$3bg>YFuB&+xZSI}+nH z$ZU8ezYBfyd2@K0_e%%vBzmd+3>`JT&*H$BubEJjLx$;*!^>wk(|c z0(j`0;MT_c$e3-Nh47^1I>XyEY!=p`S4@fH>3NI$8OOq)&WG^0&$D`K+QDjJoyG7( z_r-^(L*aClwObDCO@GfH7v~hSTOyto-COr=+dZn#zt?wyP-ao^=IWS7O1CL*Il=rt zttE5UfUow8RSpNrkAd>LC@w3#>6+b~k}pu6WaV=i^GmGsig#2WRz6JPlqsxS6wi8A zsAFy8+nW0*5qJ#dC*Le>H6A;!8?2m{I+^V^3`2D~#;o%wdv-{jCam<3I)hl*CLa3a zCfY8nR@{`(PMLUs*kF^>yGm6DWTK%71~9%AMLIy&x<1 z%9!i2l2??jtn?7-dsY@EakEHf&UdtR6;BaXHpV;8^Q_p_GB)NO?9QISQs+1;#iY)E ztPBuO;S`h|7xziL%c{?c&6*f9Yan}uNu7^b*(!C8sXFh)tdrEJv`v#b?N})v@5VEZ zl_}!cz{(!+{J@GG^EC5c@l;lAsrbZNF5Xox#>zUWyq1+N;paGuBr=}OtYnuu$5|Pi$jvlSYFjvicyh8r zW41?AWmYl?^${x%i1Hv`RyD%ye6>nzRdk_;K@mseQd5j4Fcs|R*FjcF;;HM2p`TE)CrUcfwDbNZUjn^ z`){xON}x;%ly3tioqJIv{izlxg9Bwlp!~{8Zs{uhzB6qXMCr=PIZ;-!;`dj1_u@*% zvpGdH0m2KjAI4cj?c-qFFk9kI_&z_t@^ozjg?tYi_-WL6rAvXzy8MM;?>4qJLjugyyRc-OJstlSc1 z8!KsrN|`ebTP5*4!iwKJ8(4WtJSPIrtGR5Q8sZtp%1+7J%}N#NPomtGS|r_gl$DO+ z>CVb?Qu!TL{0OfGO65GZviHnlrMA@hEbt`Bdpq@5piBys?^$_0&UHRZH{Kr{*7J^39?!~oQ8uvR_s$Q2lCrR^<2?z1(wLPu zq^m1fDID+So}!4Y(_1`kSlKL|?X1|&=eZ|V=d%~Jb?Qi+^Q@E=<%vhE=VMVivC>Sk zX0x(bJSSK=Bc2S!Y#lqEA~DBPJ>p3O`>TO6CQudy%AP>^El}<&?#E-Z$_7faKp7b* z9|y|yKxve4dseSNnHnft0_EpGxv#|Sl`95H$3U48D0>3s_dv;5^7gDJ1Eq7I%nOtq ztQ3uR>-l?DcFFpAu$0Z}C&$+-toUPRbD(4|eftPU1`+&5qlH+|9E6<51 zV;SqYM?Ae*Ng>KFth^!A^JOj7QqCbA} zz9;+$6X9Q51kHUmD@_?`mCf8 z&j+l`PvXXt_!&#B6i;bZZ2G$~)7!8oA(5-Ig_SQ8JLMl%W=Z8T)oqroJT+$JE)kF2 z?^6S1H!B&X^8W%)u4jFgturi8er2Vj)X7}KQmbSZjaXSC%4Akv5^5JK?M1oFN@3|w zqnftzD5>)%D=mcD#!4qqeshY{Y4x0~Ge+u6XQhfz-?DO2RzjXymRcs%NLKnv<@2nZ z7phKeOI;As!xOsgt*XRW^!pl$F-;Zp{C(;>X;&p{1&eXBsP8 zBsrbwryfPoy9Ykm1^;B zUI$n?D;;~fsihK$=R7MFq|OJ;tY@8!ux@j!d@4$gm#i{Ol!L51DBT$Mvh}2r%2iuf zrA@pWVOv)Gymkai$yY3OPG&KQl_XN9U`y+%ELnS5*(f9I*~)r86QxvZtBerkC@T-k zEQY;mJ*lN~(Kc3T8}DZE0xNzN3j*cOKzZpkTc@!~YsPOx&Xc(!!5o`Ir_ z?qZeQLOs>hDhEW_#mYRP8g#Rs>e7wttke-@KzHkTPF7v&9#+{Sm7ih7cdSF8ObV2L z0;O0_TX}_4uFlF2@ot5`#)@4D_oRyTtY9R2uFEVoN2o*yxg01pdf9Y8i&?CEE$KTV zp0@GyNuTi!lK(%?p4!r}uD$Iy7f9#VvT{O3n6{7goD!uyD+}V?+?TLo=l(#<^k3Oi zU9wWW;fChw)C`mffwCu1QuMWTo{;h6WM#6a@%BvC$LWv1-qQ>^Th%C}gt zGtC=wrVsYJeO{FUWkjH4?SDJ9E>M1ErG<<+VZiOwi-9sdQ1-HtRp#{vD{Do`HPBaX z8($*kOlz|zw@|%USue^wRp-%|b@sC-ho9FVn?6TY-P^2mlgg`E@yErjKzVv_9JXq* z>SnR>z9_d?IT!ENVV)tDvU|B=%rVzw&%-k2k6D=^V@@;F)~O(sOS0m}+&@shV5LeT zH=ex1Y@K&S8On;Ub2?DU54Y4|NpH=Homb76^BT{dK0>Wz<+`MwXQh@XZO3HYavGRl{ zmsx2fb5A?kRz4|8X;y3xo5$>76ZX`V^o^`E6Xjo4D#=W1jj>s8i!y_i1w#G8N*)<= zsW&b4yHMR(sUgY%R;GwjWUQqciSjNhU8V9*tn3m`t+y;yMaDCYm7?PLiIu$K$ve(c z`9*2XNQA$m)b;^q}fR$pR>}MrGlss=+ zsS$RvY4$E078Shs3308K9l4_!@V^>T6n5(5cd-6&T2eQ&ml#8rPmGPv1$5x&t z%A>6KbHYGY>dJWLuyS0K-4Uv7{D_z%yc+Q<u$pHhqfhi}tMe^jWMFk&e}R*HR5d zImk*mnQ6iItS5_jR=)dBqf)^{;qlPPIxR@qF}wRf@_8*G{v_8Buz zbe(OL#G(wFW0n6Tec)WHT$d5HooAI)LUo&Ol^gM{V}ll0C7CD{7g}YhC`lJt#rAMP z%pUG$&rwPL@Iy;wlo7UG%yp!4jU`q|CZ1X!S*4_mxz@*4`B9YDmRco?DC3t|rMxH~ zF1N~4qHJAZm87EVUTKwhQMRnI$_<&t%+*#&EuQz+Smp0{*Tacxt&&2Ndh4vRT$G2_ zTgCQpeas&Iz@FohzI}tG8p|1=-bSmWk&fltWR<^#%D$Pi#8YOARSL^2YJOss`$QS} zsZ~mgvU;mko)G1y&#ZD)vW{=FN^?5__z2zbGyDTBVFABfhpu1yPoN zW0h-?^}#-?q!iDz{Z_di@47MTfK{#t)&8JWJ`zv)LsqffI1;lPslK(I!&2uDR_e=Y z`QWhilorqTtYjCZ$Pw$wB}z9|9ucL{QR}HM%0H}>k*>aW%z845C;f4&WEJHsD=9^p zaKd^r%9!h)||w;cR@<~=~W%{+>cnd|o7Wl>fM^%|c16H0Br9Ue*L|Mej49Pmk%4AXEF4)T1WR10A zWtNP27b|0hy3WctQS$t1>r54;1}oD<>CQ?n$vVQyJjr_OqOCJQsP?Q(5@iM}?}@UX zm8Ychc`n&H?}*Zim20AGWM!h%xy(vGQ9iwF>kJTO;%`B`CoQC70@fhZ6CXQ>&Y^kHSLC|g-sEJ|WNmuwJa8!MYd85SRp z(w~Y_C6QIOiIUR%**4m~5M?+kyG8kjmHOsbP7HVZB$j$fluuY0BueU})-z6&hOB%b z%6L{5i*kjPk41ShnXR)%l<}-=5T!wK>)9+yniN*~MwCvh92R9SE5}61p3+j^i87Lv zA4J)IkM;Z{%HOH1^0z2u?zKvCb3U{kJIl&FqP&yZdeVz>iIq&Ee3r&~vWW6QTB{Tg zfpmveH(RRP-S?X6qozE39-9 zWf?2oMM-nNrKX8enUy)B^kn6dtivm;To$EWCR^t>QO>e*MU>{5t>>U9M_6eq`>XH+ z)-yoT-(=OBFd+%ye@U_%V|ABrA{|ijtX^=l}u05I``$Zo;Knc%gPB+lIF9Xu0l0pB}JTDb@N%d zSCp6YTk1YhZn2VIlzs)Qr?4pJSt%(>!-Cc`NR)}J3>77LA?q0-%G0b&5M=->ABeJ^ zl^LQGDIAZp#9UDZv$9Z>1FU=`%0opgwMvwyS=lJcaaIaQSBn<4R8vvrv(izNoR3(~ zNKsm_azm5_tTd3lld+hkUKXVdE7L@o$;whuF0ry!lqZYZI>$wsz)DS7b*EW*L6qJJ zmU>Z?q9v@-Oq9K>^bn;;N$WW&^P0~}H%b4CmG8vUwUnj0i|2DzPKl>NY3u1Bo_AO| zEuMQHwVpGg3}@wgQT}D+HBow%vD6QuTw$fHC~eDH&!=(jNQofoXm$#nLqP)V&SW(Wg^0p{B9=FsYQM$0QT9m1*Y!apT6P79{^BT%ZGf{4` z^13L!p0v~`QP#2Yl_hO)9xl$)$HlFDsgwA8Dj zY-XjeWIfc#dVZEVlUV63)Ol9=i1K)2OPv>L4J-RaDcZz(+6Xm>m41?bnw4LKdak~p0Oc?$eL@i`mtu=o;7M;}`t%{~5v5EC^Zm@GY76uK zc7$$-UZGi(F`kytVjaBT84NxT(i&bafJ3ox#o{ z$^cQ^cs>cJVS#6B;F%^Kmo-HcS9y=4N)IP2;p zP~%6Mf9R6~(TxPx4pGXQZ)4l-sFH4k24aeon&zLuiJap0yC~AtOwJ?915R-Rj9U{Z z4FiQfwao5i49|R_&mYrDmw=+r7PB*TW1j6i32w|@q5jY|#{6R`r%>0d;s(9V^#^rc zH{YkvezYDpRj;^o`r8fG<-v6!G+N^Ae9J;^`H5L`k4|J#0qzhK$+GOB9(`Z}GUW&2C=h=$!DT`L8<8 zQ_ih1QEk*qhJB7I)r6kG>sUPs(Y z5T&{sp}SbcjddPT4mm~UzQk2_1C0CJjafW7ou`Bw;u$jn%&P>Ie%X9~o>#b%C~_s5 z?L0E~qb>^yov|{B;?84UaRX}W>bT*=rE!$Zf<7G%BNWd{=aKXTH!q>Sbo~*}ETP;! z&FGYpuJkHLiL%5g&JtJHWr@-$P?iN$U*~aCH-GDg=T*v$XN&X5US8)E$y(tkQTjWN zRKDgsQhBTMNac-Ak+WzvQE+lGd&Vp7ESlEs3%P!I#d(qj9_Pe@UVFqn z$|nVS`3*&8L7zwuMP|Cr&0XpYa|)*QfSK2WZl=<)P)X$~OBQ`1z0TU`DofS~r%2Yr zK~|`wmda*u*tR=LDj#rj7v+#sO1f!$ZCKkMZdhDhr^sr#*HtdzsDVzA9_|*(9k~ab zB3XN!Qp%NH;gqtj@(*r=PKcwwLWL2^EWUQ0lC+omoA1|l-6;7e$BQD=30Fs6xtwx} zcos-yGq5B)<$~cq0d&e9`hgAM3FwvG`jBCJ~u)+v#kx3^-ghEp#P+8Qb0wue?i#m46!#J_ud7qW&8wYL5=tA4-mpQR)@v)5 z#?cd1iW`L?s8gZ@pMM&{ z5(P?8m*on_opFj#m7F4#ue&U_pyHCrc-*{}io&}q?x>@rPR3w7$pWRMOP3M;=oG1Q z!&R2?q>ywsp5>yr@f>$lDSF&Pe|>`fA_jU`sw5w$qDWSnV1(xJ9aE+tw!&_N(!(d5 zB6Y4BC$ePBmql@7UL1`1kn>2LbU}KOKuHMFuemysenk|Q{!x&A*m+76H>OeM`}B8D zFpCoIiI6A>ZisZm!1E|6G^gxNDMPE4Hc{lsTP~y8eF1~{@`zJVht&E`!IMBz%DB19 zQJL9!@brm1S)C$BWlB-p+(juz3jN3+qnl|0oik|@r5vp&@?>_Na_%xCN-0;lk?~?) z^15=7A)%BdPdoEpwZ-Gk38KhdK{Dq_pj|lAP|rXyU*hVRr_HI&|34c?KRuym!fx`` zL&~EjY=WWkfP%tJRMxU! zURz~eHJO4(Wi3}(C91x1z*9Y#f=6Yo5Q@e^^Exl{n$8qFDr==sZeE_+!4y0yYgI6> zZ8EP5Ou?hFR;w(Um#4C|uswuFWvvm)&Fg~9s}57}sI0X@xp{eNC{ysLtaWN$Z!c>% z!~R_cN?y$rJSuCw%4+aR&%Zo%mMM5t)&`ZezueBW_HQ>()_t$oZos3mHma;O3F()6 zsuWZ3sH{z(GE!-?jeM%*wHC6!>M;e6%G#{5MwCps&r?g7f=6X-0rh~5imShF|F)Kr z72nd%3m%pAiOSknXJA23)n^JGmGvp8hdHbI%AFs!k*q~b!K1Ras;rwY@2Kyog01Wb z;Za$isjQACMy6^lSsyY5kILGnvc64Hx2mUdx3*dEsI2XvqUXbVWX(@w3LcfULuIx5 zKG|4LU1SO#m9W4f`Rhr(SGhM+lF~`Vv$+&U$;p)W%YXaW zQ-$dU$!zc_YCkC2!?a~OpU}`#iLJ|& zY?O7Fv4iafJgOTnAM>{Wg6m=3*wDX=?%M?6{`VN%q{G>6-TYIX=>oyA>MV$f_U55jt8`GGA zM|I;gD7OwLY?}9tr}i-gkIFg&D%uTCCGKQL2#=z^2Nmsxr^+z}kD`76<+?%Z&{I8_ zf=5w5%Dmh<{6yB_5~ko$-8d_hTZf+djwyIl)=!|KogXHhPt)0U10I!iPGwQ&J@qtG z@TjbxK}9?7sXk1>qp0(sqMi5D3Z~#u)Gwf-o%hslOu?h53ol*9+hoPC54)@49+`$w)svCa_<<_C6 z{$L6om30GD4iiLIqDQVbp0`dqpSOqY20SY3FO@a-$=AnwYBf{vsI0$1MLX}Q$~|os zJc_yrihhDc-GBb%J?lMnkSTZ+bqmz}hM?_Gfqm&c)vlM#f=5yR$h?T6dw@04jhjrt zqq_00P}KR4s_x3>sY<Px2JQCUeGN}*^)Rr=SYbGo_dxkcvRNCprU)(Q+=3%M^ULkMfb9&mM{g6qSAmeU$A9v zGWQKn{m2wNib@O0?d72@(`?Qp-MGKM?FKxm8|gr~y}av{lcha1k|}spR{9|80m-_- z6g(;`Ly+aE*9X`U!lSb814VZZv@IN5`_dZ8`jIJkR8~fnwWfCJjGlUEpv{6uW!*0n zWzqStp=7%Z6 zcvMyvp{P2|YYd%Su+?J<9+mZ=P;OqHdY>tHRMtbFqWi0h^zax{@TjbZRo3V|{abjd z@L)SHcvM!_Aj|%(UYb}xrr=Ro*;Lkx$9n(msV|v=M`dLP6+PR`mU-Pj#EuXim6bzf z(b>jR^_hZ4W#t4FJ==I{5>xOfDi^5e*~U|cnSw`Axj~sP*ywEIscb{-yx>t(9#GNy z`7v^yf0-$GR5$X1a%UU5pZC;vOu?hF@_~wW!&8lh*%88{sQjQ@H|WWdr;aiOkD>~I zqV-N2-Oqcf*>IZ$kD>~Ka%+R0ERB?IoMZ|f)r~@+q#NdSrKfU?uvze^tiqt8-SAXP zrr=Rj5m3=?cpb1*dFoT9;89d5Q05D^k=c&-@l@8)c7*UKsx+u*H*V0aC$=6;!K1qIC@8lM=^W*$ zB}~DivdVypcEeL=n1V-9WkE%|;i(74*m=RDsB)mp7i@Hn@>Bz+;8E0LprYMaB;6Rt z6g;XMaX!K1Ps2Nmsxrz*W^=LL_Vo&Xi?hNq@81&^Yh1ZBQRH$3$pQ}8IN z0;p&=^2w3XWUL(_JgOTNK}EaasWnW&qp~W2igv?OY2LC~@F=P>sAxAl)s8866!jD+ z^F_MhsXa`=qo}7rMZ2*xk*iT)oE;%NsvA{6MZ4jt=}f_+vZ{iLcEeNY$J;D;6jcpW zv>Top#S}b>dIpsFBHi#*(g`*T9z|6L0w;8ERp7L@Bot2`MCdulIJ z@TjaBK~{P>Dzm*|@Tja8R2H4*Jyq%*J1=-tR$Wlh z)$6HFOu?h5dZ41K*Ha%e1&^ZYgEC)a^?K@err=Rj15nX!bd)n&u}OAb@ThJy1m#vQ zb;DCVn1V-Ty$CAW4Nq-k3LZr@0u}9srxLwuM+lFi8iO)lq#K@ko+)?~)dZC5#`-OV z4!$n;qLZ0|M|GnqDA$dog^PdXsclTbqq3TTigv?OzcK}nqMC!EcdgOWx%QnpobgoV z_iQ)dQPfMIsE4#|YH*{mr>ZjrkD^`%<<4yMZm|y1jUG(Fqq@-ol6xubHk9F-5uuvze^tnNa&qta9Tn1V-T^#CQ$z6Lb@ zypGK4G*j@Xtez^XRp(n5J+*wM9U(j_s~4yoW>Pf5F3&#Rz*B=}SqdJN)mvq~J}7xE zPrWePQt+s(J~A)L8Z~uEeNW|?V<~u4)*C9TcBNZ|JawHZcvMzjHLn|;(;WBIuDLb~ z9+lNkWu>UU=WS0-oo6X{R91gbZuQcAZ&}%29p+mK9+fpfWfiWy@TjN0WC|XYH4s$v z4DhjJEVA>0M^U3d(NRJhJu&lCOQzsa)M%L(QFP~UM$Su^o$zj}G9#bVn-cvRNJAS;91vmIj!9+mZu%G%#PO9fBWT4J-{QCX8z7X37^ zpk!@h3Lcg9uF4vj`-AzOD*KVmf=6Y&r?Oh+eQH<_>EXvr!K1R?*IDLyucwN9Y_s4| zS(8;3?XO+3dKWVVkII^&vgm%^Q%RQEEO=DbR8a05H9yn$PnD6ZW=z4OvOZ8*d#hjk z*HdGef=6Xd0~I||JhhQ2coa1qRP;#k)UQmzqo^66%ol8Z9)F;tr*bW`-GE0?GeNm- zWZwGNsbR90>oNt8>c%Wk?npU4ynJ0xjb#cRl{Fib>ju4-*i$>0f=5wvK+&0v&I0cr z9Qn4V{$mOrMa`8gYDfAc0~2|w;&R&!coa1clsj+S{IdN9PxWOA9@UNcpjQS6?TO1sH}x5i`KlS>M;e6%32g;y(wAKnSw`UeWH zW0ke=@b$x$35FVAa6jXHeda5Q<@F;2-DEb{n^G2z-rek*J^wbol;8E0aQ0CXV zv5h--|7uTNWC|WdtpFA6Ms>M5lv{1*1&`{+N>Fa~KE1!si=G~= zBh98Xi9PijQ}C#)^`N5N@KnNDJ1=+?wL!AziCO1PXRdgvCsXh!Y9lCjXa3PIqwe+8 zXH3DPs7;`v-8dxONVd+75FXWy%`!qd_gq^u=>GjT@3W`5}e{|}GK`a)&Vygb#5DR@-YE>KjR>OR-2 z#1v2MVhSEbeF=*CN84kgD{S!8!<*~~;Zf9XP&o`i>+tiU^-Ir_d39zA9yPD8K)LhA z#1-AEd1@n5@TjakprS{LrxI_rBZNm$dqF*DMn~6_G?m_e$5XYLf=5wbgQDjEwC&t= z`e#qgW(pofeFMs!H|Q1pZ0W`&rr=TC*aymWgI>{ls{9r^FL+eeeo)bFcxn_=@F?m4 zC^`dBU3x|DsiRE6qo{+R+}fa5^qzX;6FWk96m>}EMLncr`KTPr1DJwGb>my1+_CJb zFPVZzWgQ0PI-lcvRL8pv;#z8V#L$J@pq;@F?m> zP;Op3-Z<9WQ`NWGdBLNovob;xh2v|!+`&#^3LZ7DpM;`3`b}g{rQB|_;89uUgmPIc zrH8$lf=6ZjER;KzJ++c4cvRMTP;@NQM!$WZAlKzznSw`U{i3qy?#olvci4Hsqp~gt zMOk!?`ZBSRuq|K;9+ma0P&6-kx3i}%GX;;zx+oNtr>t4h!_qtL2;os#mxOXX^i(gV z;89tZLAf=*w@sPnGD_BZrr=Rozv--A-OL|AG7`35n1V-TT><6J0Q7{@Q&~Q@^MXfF zzk`aN0X$WcDR>lh6%=)Xwl!5}HSpAMrr=T3|3JB`!^&#+u39B~c|B9`sBT;X<<0<~ zzxCMfo=WtEofkYR>km+_8}!`9Q#F`^M^V>7(P!k*+&=!Tz-yj*pDB10^`~S}H(pq~ zrc(H7TsP<$tf$5?1&_-58&tIOOQiGXn1V-T z-BelBc~2Gn(vA=wm30eLwDX?o#uPk?`Uh0B^Pbww6g-OhSF)&E)Ok;(+HFS&kD~qq z745vI>M;e6>W29cp~&xlQRh9im??NvRy-(|MNiBM%USe4rr=RoiBwkqqWg1ts_R#F zUht@_#6eak$vVpvJSr=R%9>HA`7%$n*kiNcQCUfaqR!Jn1V-T-K(-XtuFMVrINNOp33mOrQlIiUQn(Z^xHbwq#NHb1&``RJ{ci(gWjp@sk}efEO=B_ei@Ht&lD5@YRbAyA8em})i#ecLTghx?@Kt;QeR$jx7VhSGBjl!VZ zy(o3VQzw{$M`aZO6+KcsRrIVKAv}sI3M$$SPYq!T9z{I@D%uTCea93$iYf*w+Kr^r zjS@fE5yGRoQ5;mX8=gAK6g(;`0aUabp6Y+jX2GMV5}=~p@KoNPEd`IFN`i`Z!&3*D zf=5xMKt;QeLb}oSyv>3~b)z(>Xg55S`xi^Wqp}_a743$nb~6Q!qRN1ZcEeNMFW4-2 z6jc^fv>Tqv^Q)!cQB*ll(VxO}mTr8_6g;XMkAZUCXt(Ba4Ns-JXtUr^S>-{w&eOX- zs>ySJI!wW%vL07idCrz!>Zwso!K1RC0OdMQPY*ox2~+SW>Pb-M3!byl`=dPdCsXh! zs)A5-lG<1FYIRRNddYSJ9z|6I<+?%lhZUsrotT10b)ym}*Lk`>^i-kCHVYn=RT-4) z2HhWe>MT?6DC#N6a@Q|U&Hl}1!K0|BC5yU2*Dp`Cx?(AK6jcRO4nt7Z+C2wWtdskw zoWENN9@UMiGD5n3wP>;@zo))u3LceJO-AUhU!IzE)n>t?sAnXLsH*L1{^_Y#{%0w8 z6jfca3=}tUV&dAKDs;_K@F?n8P|>@}VbYC@Ou?hNQA0*Z-Jnn6_0+;YY!*B!tES4L zpI1I8cMdJCTM8bP^_h*&oKp$%Broh=shr=T5!W=!K1RC z2NgZODoa-Dzbplh%BrKX==kzf`oAp&kIH%hRP^}r)MlpOQB+;Ya>tja+TFBS@F=RD zWYJEhF8n4w=ufCy(kz z6B(g9zC3k*TZsr&5ftIn)f6HSpKKkQwW`jp%wO3iRzdV&LrKR9eSsjF;s`O-Opk)2U6g(=cqfm4# z(;cj*_TFQ&;89txt9jA>+ATetmC91^sH{#Zi}shNUZFoEWj1(JR_7q=fMn%PZ7FzE zRu`4E>008d zUVpWzyy~W>USJ9yMfH&^>M^a}ALMM)lPP#qH{KA6RxiD$!c)_kf=6Zb1?8@KbS1hj zSH0~_!K1SJsVurWcq)$maEjUBQCa;}7M*RrmU%tS6g(kXf*EmysFn1V-T4N_SrXKYF4sl4g!yx>t;gF!`Cl&97*1&^YJfTF)-MDG@R zZ%^7@o_d!4#E{wGQPfaS?%iTJO4q64sk2PMqo`q^-0@XodA0*5WH0x=&t}1+x-lG- zdtEuw{EXgH$C!dgWsLw8?S`ky(H|x<8$5~{3CettSJ|GL#uPk?8U@N7U(Gl4Oy{Yj z_uDLZ6g3)@Tl4f&X-~bz6g;XMV?eoX(3CD zs@;Co|2(yXDR@-YTPll=uLW{^rO9lw;89uQR2Cgyo@&4pJSuBEC|Xf;KTW?8UtO-S z)0u)tWld07^c(S>+Q}3=D(mfFUQfupE;0p=%9^OM=pEypN=<*N+HCNstanrv?XSsl z-YCixJSuCF&f1w_p{HJ93Lcg9uF5L;OVT0ZBFRLfj}yf_l{Jg)20SWjvdSu-W!4c-y}}ecDr*WTS{szrb!*B@o?6HhJSuCd%KAQc z(I%d{$P_#(>jO2fdh=7X_f!J?=~1)6qq3%{tmNBz^zu|srr=Ro(?PlO2Ca=rvcEPl z1&_*_p|a@j!g%UWrr=RoGeJ=gY0Fx5|B{($_)I++D+9&6Yy!5AH%?6LkS|AjSklqRJsTxedqp}tXMO7(ltz>m(3LcfU zNGO-(srgL7qq05}%4MyWtYb{Uqp}tY<+41LCadiRJSuAmsOXxnCg=IeOu?hFK2lk` z9xZj%Qwx}aM`e8+WW6t0Dd`U;n++b7wKT}`R7a-ZQCZ7W7F{dPNe}li1&_*FuCn%5 zy42KDaoOz%;Za#DR2H2#s>r;GF$IsxTB)+Ahn{+uDR@-YsvzrK$@-fqcvRNvAj?xP z=dkmFM`f)M%B{o0(!-rh!K1R)3PtNM@2pA>d+JZ7;89uYK)KHtACha(^L-?%0R8E8 zv%#aX)~l@6rA9ROR9&XvQCS;6Mekre)t@PN6txkQ`w88qmYte;YB5vrC~A{XG=td# z_e}ECcTB;fsLi0<{rv9AjlQ`qd-Top z&J;X~`c&pc_lMLCPwiw19z|^h_f$V)rH1`#NjGXR z1&`{+Hc+k`<%X>O&QlARf=6X-2Nmsxr{eP15yGRW9iZIWp!Yd=su@%8C~BurH1F50 z&Mxe!txUnAsLw&UcLa?%(!Sj^=|JSyvJm34kgmAszX#uPj%>l>kH zUc2g5C{RrHa_Rzhgz%`WeL~T^-rdn}yQk_g1&_+w4~kY4ZIg!#d^WdaO=Summ32U6 z(eo%z{lFAFD(fI9*F$3t5K>d6#5 ziaHL;e32(Go|?@RJc>F2%AK*(H-A2@rw%X$kD^Y3qO%QcbX1;{Zv4X(JgOVt2}P@y z?!G)#xUlUZJSyuHDEB1r;CnN2*Ok5eB2)0FtkWv%#`9gj^3OfERJ#~^PcvRL;cgU*qh|PjWWt~%5^fz05)-I;tQCUBOa(nsk zqHcYg$zFc4n9YJmWt~@9tMZhX=czGF!K1Q%0TtcLp8A$4cocO3)Hc&!`kUO>-YgyG zsocfw2;ouGub_t0ZZTW83GMfJsuxr6DC#1p=>6gEa>m}t6g;XMmq59_O!tSLN}XUw z2#?CT3@X|UPt{`z9!32I%H0vs{h_C3Fa?jIu7Gl98@fOA)McjNQPl6CqIX0!q#I>R z*m=RDx^Weh>&DGeMJ9S`22=2;tp9!n^%tmUH$3$kQ}8J2Z&0oqwPw#u?x_Pz!K0{~pxk+*%Kx5?ZzSD# z^iexPcvLrTfpXn=yZ61#JhhN1cvRLuprYOIROT`^3m!%N3#z~A6x}_f`Ki}lPmN&; z9!32JsuDHWY|{$0-|wl!Wo;HbilRS)=KtC|T^&5tlPP#qH{wCLZuIX{?wqHtGX;;z zN(9Pveqz0<{kzJYd5>~-gz%`W#479694&tE)Ly3GQCUeqMLX}QJdfEdcodZs)Kb$w zy2|F8zWlnU1~3JWqLP7nk=kyyT0gJ(z*DD~f=5xwLAljSo%dAP@^*yqsBWYHo z9kOOJ1&_)~bBC;CPueVaR94zMWOZN)9+j0&W$FEOkSTanR{A?+m8)P!2#?CjaEGi} zOu?hF?z=-)vWhkf9+j2x4p|+Uf=6ZDe}}AtOu?hFGN~+jKJVAYW0mX(;Za$c?~pZ% zDR@-Y19!+uUfE{Bqq4HxA*&-(@TjZ@?~rwfDR@-YLwCq}>?u1!cvRNIcgUK<6g(;` z>m9OEK5et$QCZpUkky4LcvM#QJ7gVY3Lce}LuLI~w@r1wHY!%JBZNm~<-9}ILZ;wR zS-I|zmA0zQf=6ZLzC%_|rr=Roc~q8O^QV}CM`h)`Lspe)c7*V#tb8g<_wZw;;89um z?~s-88Jh)<$|`V&tbR{xjp}xU@Tjc9pbD5PIXN<}y1HhU z+#jxF3LceJL}fjG?1}$*D)+NC3m%nK6jbys#Z&Jv1&^X00hQl8N~OPIyRX*9Rh~*# z!)C#wsA8Zd8-ljgN3-wp)Ig@-QB-kI(Yq8+U1bU$)r|yD?k;t$#ZOA+^wd?R;89tROBRjh($O5V-;#GnRIX!32#?BoLS>a* zf8Z-m^<=nWC|WdRg`%dC~nnvDJps@ z^9y!f@F=PhsOVAYshUi|qqnRx_jfS3Mmy{>B-!KJ_%6eL5 zEowMpyQdP>wex~UWmN&?I#18BJynV+cobC?lzI6p&#^t#mMM4?RZS@Be5-{;{_xa1 zrr=T3Gcqrt=sETd>Bcdp;8ESEE)*SK^y%)NN?*@*10I$2EGYMS`Q@E;X5^LQ>lvot zQCT%qR>etQRQA*)rr=RoH9@(~({pT3on{IiMLh>9ubGqim$<1%&wS#kqV?^(;89d9 zQ1q!dv>nL*#V}6|W(pof)dm$^^Pc*KDR@*jo(JXDJY9)ARj7d-Av`Lp&KB;=Q;SS(@epmvg+O;t6W1nLU>eGJ(Z>BHHj&BR91aZ?zw2zmuEC?CoAeQQ}C#) z1}dvX-hD$o)$&CeGLr~Eb<*6e~!K0`bLD9QD=$Y@gJ!a-Gj~eZ?kEy}}ecDyt=^Xg54H zjwyH))e6*oW>$2@Zn|v4dQWX(3LZtZmMm&Viqn-#c>= z+e3I%H`;)5-JttkPt{=x9+mYPDEF?aEB(qoJVovg2QdYY%4(~!T68JBBcwCHq~-6<_Eg5^wj1y$sskwZ$>ixypM26&&oKp$qB??dou_B8 zo*KjyJgOV7gL0jxbFZhiG6j#y>ZG#heGWzB4)#B$;89tfRTk}KPpx^$b^{)j)diG$ zFLBce16DMYtadM33Lcf!Rb|m9PkQQ4rr=Ro-9XW?Oh-!cm(r#8)X)|-3m%o#U1eS9 zceR42(!XLUcvMyoP;~vGtleuKc-vDmnSw`U^;B7dv%U0)r;4_;S@5W=UZALll$Gqg z`6E2Fi79wgR&SNnVCUZ{JXO7w&4Nc|^-)=wmjCg$r;acMkIH&OWmUR$;Halsx3*dE zsI0z{Wu_JPL$~6y%gH^!|CoYDW%W~8^cQ(NRp(Wk1&_+=56Z2L<%^FE@YGVK;89rv zRMzZTbB}o{bsL)nkIEV-^P>ILX#CQzJ=K9JcvRLPm36F0pFN)XiYa(h)?mq^9zOk0 zlfhZ!_$u_89U(j_YlzBvHe>t$JhhoAcvRL)QUXY+aLH>TiG)EH3iE`|Q4$pE=lj_7E! z;8ERp6O_9;&^zut^)*xQsI0M|qTTS+{jb|Bcog*(DEC)9vaWgW8&AE&6g-L=2g=Z$yl?7ZMnS#N`K-Js_H zo~p+bJc^nKD*7D2Q^S~oM^W#9qH_jq%Tpd(;HiyF!K0{2pxi5|k$>(?eM-7+^Awl!#xc&T)-0G#h?5R$JEd`It`dDSrimD`?-#Wxn z@Tjb%DvLfx+EX`%{vUhi0T@|T{r}LECQ?KML|Tw4CfNc@%Otzm-E3#GjXKOGv%3Rn z%p_aD21rwpCJGh=#2+eEzy?T>DpD0tKvC%+NJl`0|M{MKZaMSbv}BU(uK)M@vF;|{ z&pr2?+wZ&YJwvfZ*}78M!Ycc1*GGN!L_@Jg*}6*E!k(U|wm->GtWmap8nN{uH#%&3 zvY}X`Y+W6(<*CPnVvVwO4O4clhxy?Z&enye7+b7SwyssS7QFGb^E}mks-ak;Z2c_a z*PmPr_xXyUSfgzHT-iblJ+=K;4aFK|>lexvdbW?b-sZz!GZbr-tzRlz=-E8=JE2&k zZ2d~vLOuMDv-S1Uj4jqETh}RDsE3|9@9TzQjk0xp#MUTR=YMdzp;)7A-4LIGVbA8N zEzdC&YZP@0Q(@2Msqx=56l)aq8>YgZ%~OlNWhmCDXxz$F*t2=++;a`Z8fEJ?WedH{ zJFcbNb)KPEqio%-Y+;q{sjI(jDAp)jcSLNh>w19ie8*6%QMT@k*z#2RyM|(ovUL|z zVQ+Jlv$f~<48$l1ldK*vuS18sfTX#qNdd$V}cjp^htWmapr)(jHp1St?hGLDf zbq`baUfbL08`=(bJJR31z)-AFw(eE7p1b|2YdtmQLPN1e*}9LZu%&qFUZGf{sQa1P zfktxF`+HvA?M_cExyaaJjiMf4%9hvjXPngIsr7zfDAp+IL8fd=LEpQP>kls$iZv=4 zzh}y}6!g8G`ohJ=7HgEPKPX%1duyDn`9CxiYm}{rBDOrW?EehK8fEL@h^^gSfB4Ny z48yd~pPhImPL$OBL`eVe_{?69@KQt;Zv_{^@LuyTVYcQMUdZvE``^uQU{El&!xoWos|y zHa~H_%@abgM%j8o*+OsQsh?kEY_Ue!`fJ3mhn!!h{nSvbQMUf3Y$1l8`r_4wVvVx( zcV!FhYhzdEd#^DRYm}`gl`XU{PffYjP^?k5o>I2ZzSefOcKn&4Sfgw`t!$wldTOtq z8;Ui`)-w@X^{&oO`Guiaqij7JvE`{lerYJyC|l1dTd4DIy7D^eSB7GZvh}>Oh0(!N zhhJwX)+k#qL~On4Y|XmfP^?k5UX0lC)Q&e8iZ#mCKbQ*Z{AI4rza!~M&VvV9+XUg95edd9hdp&j5Z;UP0DC!NS z>{vPTuvZWB)Z|+Y#TrGu$&`)8yvK9D9OEMYj!>*o(Rhm~JHlfB&{Gp{GqzZxY`x7? z7!6OIEfi}M^)F`&>Hec@>>HkXN+{MS>K$i`pqi_0J!wNvjl13CkTr^Wmnl2@dicUq zKfJAr#;HQFMn&U2mqYAVzWVBW-}BU;g<_4e^>3F$OanwjfSUA z5Q;U5`Y%(qE&u7H?SdRWArxyA^*&SBTc#tvHD7({wjb``qA}`DlS9_1Xnf#uh-mzH zv!{>t)bT>GM%k*NitC^M!br5Iv-N;btWmbsV9M4*+?Dp!jdz(GvPRijlPMbw+?Af| zY+d?WL$OBLT1(l&U1?9vzuQo(QMT4*%HDazU1?9P`8z|gM%h|N*}`3EPhBY#Ym}`I zF%{mG_SB*G7+b7Swmz(E;jXl&*1OkGtWmbsWePDwDdVoRr+zLJYm}|^lr7wq_Eh_Q z#ujUot@V{H+?Dp!#`hbFHOkfo$`l&y~_ zTNsHv^%tR7qik)&l&u@MEA6S74;ovnQMNv+Y~il7r*0LBHOkh;&M%Y~?n--VuiqP6 ztWmZ$QMP8jKIwH&T`Cl7l&wvjEyNIarMGbHYui5to6m zX6D;CTVHy}*kX;cwYjo|yV9OIJ6X6Z?Wx&+G8AhRwG~t0U1?8k^r)d&qo}Q! zvUeU2?D@s6A9M4l+k|3`ipD3IvOV@kKj{0Zr_OxL*kX;cwGC5YG(2_K5&X z=H44$F;tQ?T^;79tWmbMXDW>07A}Slh%MHr81BGS7(-9};0cpM)+k#$G8M+qQ~iH6 z6l)Y!%TyRcPfhuop;)7+otO$^=&7ClZYb8M7=D_mFouQ-W5^n1YiFh~5+Pl@!TTWB zD&G@ZtWh!Cg((|De!q>QCOm0!$Qos9SEj-kdRwOn#TrHJ#?*F{JG9D+(&x8$>QSLs zqp01TErMzuX!!bUPwoDc$subLwFgsnZiD{tM{d=&Oeof6)3j|;^bWvh-U^u4GbPbF(E^wfpV7+b7S zw(6Cw$D4oqDNkjdH56-*&40< z+T^^^>w4;z=Z!7aC|hHct=`6yKH{lUUoaGFl&!JO78D=9=^}bTnr)*8zGx`cC|i3e zTbtgy**c#3rckU=w)SQ!Y$=|4OeoeUYMir$+}w8by7clPo5St@VRFbCMeV~B`Y2p? z?EH6nd7h=Zg<_4O_GQYB=70IaA;(R2)X#)sjf%#8E{CWaFI@h|S)SVXC6hzeC|mn8 zg_BO8nh!YUFi#yR6l)Z908=1vUDdGo_nx{_DAp*dktzCvN4;(4JhQi_c6-_6kTr@* zFlGDsPi1#{*;6M9#TrF5F@;jbHTkWYZcjZe6l)aK>~aWd)T2iSF>Ly$$suc03Z@oV}a3b(v7CQDe#krm%js*Ay=0a7eyYbDnu5Nt%6_Z2Os2omI zIc&MpjiRPA z6-L8TR|v%#Ma^J}{&3Oo)YfkpTdYykOs24E!*%lb_BThl72@$iu|`E>7E?AF*fI0e zzlCCrvUQ-NU<*(A{m$)U=iW3qWR0>l+fnE{?wY*IJWo9$6l;{NHb+@o7rB|k-ftOO ztWmb+I10A#Y`dq<5sEd+)?B8-7>;o z-|J%dfKaSawiYN`Tio-<%RRN*zl<%`C|d_H71mx)ogfrz6m>9Dw(nj4s#gMAe-(-~ ziaLZTJI*bfcgiN-R?|BshpbW5p-kDfJnnaQ{qU5!?A&O09 zIo%_f!dojaGuZ0u2jA|gtA&C_+d7IVdv{>;`CHxKsXqz@jkeY4DA;=T@U8au)E@sa z(SSzV>T(nmPtR<*#8VT6f=1iwb`)&AKKF(>o;pz|Xtb>!N5Pi%>-$1MWAgfh{Dh=P zC#cW8oQ_?4UXc9mNtUUpc}*y2OgdZq*ZglZoufIO_;%4k6#cpe8f`sWgh~kojiz!% zs1t;OMpJ!7s7r)`MpOMosJn!MMpH|RQ2!PR8ci)@%0@VS_3e*AVXjZUZ~g|2rj|Qf zQ1;HhBIl`kp`g*!3Z^hR;Ck+=Y1GK9tq!4}(bO?ap*7(;ee4Olchnw?hilV+2mRya8Q#_=9~cjzAu8xwzQ9z1 z2(-c9y?^s0PqhdIjkfhgXA9|ePFgt8Q^yJgjkfhArffg<-;U-BJ@tlA&}du7DO;14 zKDv*mJ|SZfG}_kjOi}mBevSIsxFbB(B@{H;)(J&yeN8B6H1%bs;>+t{p`g*!iH?en z1^*HX8cm(#C|hTtFxOUVn2{M8O`YthsI7g4f`+J|Zk)o@o)W`D#~ii7+d51rXtb?U znX==KF0bQ+f`+J|H~tD!+lePzAF$4C-qu4xL8Ga!GDUyzHLK~gt39>ZnkE|1XzFWB zp_Sme{s+JPou@t{6f~MTjj6E)s>zJq?krEW3I&a(zRpzq=OK`Ecf)B!}G2iURZx*tJdu8*x{VhD}4brw^w1+6aS z$wEP+ZJo_jJrS@qd$*d`y{#LBf=1i=MiE<22?Y&NL5(_xsnKKySMtc^=X+cGt!?~* zMpNHpYCi+jEFJs1zj>-pC}=eGEv60>>VU_8NS`aTF}zGDXf$;$Q{#l%_pEtmcqYoO88cbKy8oM~V9_iMbZF0loT zroPKmysdADEog`e>iqYZim&s}i!Eq0bv{$^b$-7OnP@;mR8Z%?&s2(hMm_x0V;|{) z!dzzx1&y|KfwL8@^Un(f4N*ZoypXBACG|U|{P!wv>!J^v973aWco9>xi9!ya{O>oe z^wgt5L8GZ3Fok=gpq{%TM=#YvUK<;ev+E`&I1|v=9M)#(mo*nNg%~0?JEwO#&fD64 zU6Vs-H1$KKuqy&v=hyt?9#4%E3K~uQA5)lpfijnk{7j*s(bOeO#rHO8p`g*!j~o^C z>&rqxqp2S=W&Qg6hj(g*!d%}K3K~uQ#8Fo3sjG#8MpKtEW&Jv0v;SQ0sk?-NMpKtL zD(csBLP4Xc%bBu%J@w(!zwT|Vzn&>&Xf$;NQ)rb&fjC$XcNYp8O9^=tBVPd??T zX+lAxsjC#Fqp?&dXoxaxndbX7H9uv_&h#F7f4|RpTi+H68g1)prff8HDgR0+Xf$<= zqihVkt%rnyMpM@^Wuu|T%2$MfM*H)-T<@ZWjs~P2K7!8#yS<^*5oQ(bR2BS-*6@@o%A^(bVmZiu$$f zhNhIE(bOGGS-*5I+AI__n!1yz_+GSKC}=cw7gN?R-HU!%C}=eGTSrCxx=&sr#9V z_v>V#pwZL=OvU?kiBQmJ>On_E{dzzsXow1Wo8L2K*XDa(F@F{m=6YQyXtb?AFlD2m zdz+7MWFilZrXFG{zPA}G6f~N8m?;|#J?hO93K~s4;;3jez9z&EagJ zpwYG-XUh7edz)i~f<{w+W-7k+o-Y(Mn)(YuW+mqiwywl=Vy3`Rj#(MpG{`6<_C{6$%wuP_xK!yANxMpLgc6(7UD3k8j)USldgh9BC@#1I<`M+*gww)F;6)-PS>4;2a;O})t!a=5lBB>K~q*O!EXMpJJ&Dq80+777~e*V|0l z^2%O%=bPTvgF->0ZT*X>c)#8g3K~tl!&JOq+kVVM9vV%(>!_$-6NG|B`}H1E_TJ6) zk32FB3Ug(Jf=1i=H&fOxJ>U42P|#@VKTO5XH-0G;G@AM^Q??%J`NpF{L8JY8pQ$~_ z5wx#|FPd^W6y{oMa}z^ow5<=AvVJ|^a`$1L+DRyAG*v@~OV(OrG$oGnBIdHT#tQ|F zrq*D}`qg;ad%yR#QbIwasWlb#m-RmRfu~Lp3K~tVrKtBh$9=(5KNAWXqJlnZZKiBn z-g^EsS9t14p`g*W)?v!VP}hz1KW-uqjix@tRD9joQz&RO^6o_-z_=6XjcXtb@5Fct6DmRp$ef<{vtF%|FESfQZN)JK_$_p41PXf(C4 zqI8{KArv&4+Qd=tLGN$;P$+1KGIgEvo}_(Y7{Y%EnNSU(X2z zjix@v6r!=VSn#&i`Gko)G@9DnQOK8Gr|c*cG|n&HP5n4iyAgppzr~}6Pw=*;2nCI{ zwFOhwFWr`p6bc$meS)d@wtSLM&}eE)rfl8NZTTXhpwWJ9#nevX*C#J~n{Gnd^14$f zXtb@ZnX-N@Z8_phPdzCVG@AM(Q~QxEoRTz`we_x0&}eEKrmSCE)IR+cZ)@W%O({d8 zsZS|N_W*T5K|@r~V{gk;4`mIdeC)MTzT<6uTPSF>t?ihy(a=5H2SP!ksqL8>O?INA z-Vs|Fzo6074oul-eB$}Pw)q_1A`~>*uN|2pDf=~PkMGeTYa98GZf$HqqixkPW&PTq zx#bU@S|AiOn%ape^Z@J7f9A5bz9$qkn))3{wIzR0nCmM-L8GZ%9R;oKH~u0NG?p^y?Z#C6J>PNLnET7nXli$+MoFH2a_!O7 z@z@+LAqp2XL_h1U^6sz@ryHF@-H1!!rAzgj;@&TcsAu8zS_hbrf87<|i?SB!R zBB=S4$ssh_)@PZrwO9914MIUfRB)%bj;UU!6x_6bte}c)ORk?NT+nE0 z3{&W_aov684{r9_j8K!S<%SpwZO6OrhT3`q241z3X$h zKT)`#(bRrSVO+*_<_#O%>Z$ocL8Gbtm94kecwvgCmI?)prVe20qsCOtgtkkk#wekn(bNP*J=x#2)Kf5n#9y>p)UF1W&!oQP|#>3mQ$$U$(Qo&M4_jIMpJW`T27rj_P@+!%i(dMpwZM^rnVz_w8!3XCu0j5P0eGfmu%ra zhqQ}c`1>JkbXO)X$*78zOJnsRgW?+FEsrVe822qNqV;bVBWP|#@V;3Cx9 zLP4XcLzs#$uTOm1#1I-y9a_ZJJfWb`)L~4;x0F+bf<{w^GZi1hON4?(Q%R=cWB7Za zpwZM3Oxe-=rN5r_J{0Eq4^gl#ToupS$>ED9p8j zC|uBJYKfw1pL*s!PhBY#G@8mVW&4aT@A}N%mH(NqspS5emJVLrKR z4lmx_*n&n=y-daDaQPmFf<{wEGZml1X`e9^G@8mX6+hqDU{6Cqqp2KI@i}}(C}=d* z$5ea{Z~d&X1&yZqnTpThSL+M~ji#0|6`#X&y`iAd)H0^xbJ*NqC}=dboT+`Kd{1b4 zXBrgdT7Q&jmC$Hv1ygn;KlYm5=RB1V3K~rv!xZ)baBa8$h4fczYnf2c5Eaabj%6x- zMs$Tx&}iy&OrdST!uQYL_a$%ZZlR#jIs80Rh&-;>uRVTyPdz6TG(-h!*e@`J?=NEw zyW3w{*7ejjqfHE<(YC(GlR7^*tPd3H?>Sn%`~B)(O#UO zsDFHa;sj5ngn~v>Uslvlt~e~XW4K%>Xf$;qQ?}>Yc=KD1^|nqI3K~tF#1uwGT&?fk zH{DY|5(*lkf|_tLQ&4Uhj;E{Y(Ya*P|9a8WzTHyb>mLs zp)l7A`x*)wqJrJ0Gnt~zbiPI{`q`VF+I&AlL8EP*#nc|ephn%e|2?BTHAX0Cw5_w5 z+Kvbx5!(Xh69tc<(bPAJP!|gYjn3gYOxY7<@0_w>uuJp2iZyX2?dR&&SwhI@HNWDaFYW}T%pm__ZrZf<{vpF*TY}w(SE7bDbp=G@AMWQ?_pCJBC*Y1&#LW zVy5goVXZfQFwWchqfpRjTR&vV`lZWj%|;V>Xf*YIOvRViu0lbhsY@IcEw5QZL8GZ3 zISRSa_v5}K6f~OpF;mtr-IlKs3K~uQgsJ$p{De@@XzEg?Y>9$J^YGL&}iycOu?^c?Y&7TXtZC~F*Tnk*!tY&=UfSexz-Jod@cntToy2?dR|bu&{o8oHFv777|o-NICSDc>LzG@AMiQ#Km9_C6yNG@82A zQPF5@(PE+jjizp6%KD{y>^7mG(bVls#rILC2?dR&?qJILrF-lwzh%lsL)ZDNP|#@VZbw-Q-qsIXp)HrG}_j^Oj*Bl?cGNxXf$;nQ}MNTp-|9h>VBrI zU%K{wMJQ;rUk@;~kCa!x z>JLm=zjS$x7YZ8f*F#LziC@`eUmERgEf)$JZR=sCtY5lSo-Y(MntFt(_*QwdP|#@V zk4#y=bgO()C}^}_e`1QdPVPk)ZoGLL6z2L!tBD~r+Sa2?S-*5WoFEi5ntF_>_tR|bXtZB{W2%`P!5rY2&oO2Fdg8OMWxTB?gn~v>&nxQPDGxpGsr9Cr7(zo- zFzUU))DJ0#DCM&|{~4Tk`LR&YXj?BbWuq}+{)=DswkAwBwxH3}KbV?EcIYp1*=Rg2 z6f~N8i76WmeVR8r!`OmG`}HzY2ay%{we5YUukbm%Lnvspt$#9Q{nDqDH=k*2L8GZx znA(r*d|15lwvG@A8cn^*l=bVHySAdP(MID^p`g)zy~Y$ae&E-idUMZuYO7f$htOzS zuQO%+(yj6Yp`g*!8%)Kw%IAfGMpJJxW&P5va{7TLhtO!h-eStO%9iV2qpe>Xjq8Pi zM%#LuDeISRm46os8cqF+sW}wCXscXnw#gwhntF#R>z8hoI|&7irruSQZk4lyf`+J| zRldj6kEE2}d-01mLSe2qgn~xf`ZrTH8oE`U*=GELMpOS`D!x_jKF3hdXzIUA*=Xoi zdAm^1XusZP%C^cG*EYWdg}JtzYivQIZGFI$^-H(PB|<@?DHQHnYs9z8YlMPEQ)@6~ z{nD-SeW9SyeyzzAb)DQQmwdL3Ho~o6z4MG;&}dt0F=hSIt@6)8L8Ga)nTl_f6XqLR z&}eEMrmSDORbD0(G}^BZF-08{`}KvcmxI0KZ59|?&}ds9W-8vVIYL3Bsdbr(_v>V# zpwZNNOvU?kolwwdzt(4JhWK^z&l(Sf!d!0)1&y|~0aMm5J!jkJAQKH}G_|3ltOalD z7@?ri)JK@Ie(5>ebwWX-{o05r+EC{5+UCISi@dG14mLT2M%(%*Q`WDJjs7;-Qw>5v zqp6LV+JkKQ6H3;@!-RrHQ=2el{nAgPoFWu7+OJKS`i%H>$pwEq$LH_{p`g*WHe<^A zrTfFb3I&a(KE~8EvPE5rT-LAmg@Q&?n=@to(*684hnUDiqp6Q8s;=o4Ix=f*wFm_b zQNif21yj@%xs>03b@$+|^go4yM%(%XQ#Klp%})fSeAb~RhtOzhOQt4}t#xfMTn-x! zGZZwM+KMR~4c&|WUMOg^Ut2TvIq_@pyt!Ram}|=6#uhZ%)+d>=e(7HH2BDzQ)HY1T z_cpsFjV)+2^(m&TU%D4PS14$-U)wT;b26B-J^kduUqE55j~-!cL8EPL$CUL;*WS@W zL8GbdnToHybA^INQ#&wa{nE8}sZh{pYDY!s+IxXe&=3{W-dd)(L)YHdgn~xYgeYMU%K}GN+@VFwHs6MwfEy4#uhZ1+MOxum#)1zp`g)z?ZK4YKinmE zTHx2CLP4W#eTJ!czt%~c973b1J(-I4>oY<@qp8m_74O$vp`g)JouiN&eZTS~p`alu zsJ-<}?Ixvs%Q^oEqH(cM&}dr?OxbAYnZs>DL8GZrjB#WL{SZ}c@FK9G%08=&^`ozL6LP4XcMn&m4+bp4=Au5PQ zf~hH#LyUSSJl=gA6y`cdC}^~;CZ=pOzVYWT&qyYFFbz8=RNg|P|#>)0v8IUz;Ckq5+Mj zW-w)=q2HS^TPSEWHB(W#9xfFM8coeoRL$8t1n*(^u~5)x>Oe(pc;^lGKw+-m3k8j) zW;+U=pL5OopY+tfg@Q&?ZHn6Gob7|%gME%NF@#1_a}=dpO1DtZ5EayoxsF2J82`PM)O@CRl75sgpGI`>5=%+=p%A`gwWbqG^78b90mnLl{yJ)xk{)S*mG zpv0pq#ACaREod}#7*jSHy5IPZP|#?<4rl5%vIW1^{L|WdLSe4!yNxYqw5=pl)~_ws zyPXw=>hCcWG@3essrdeI_g+Imqp1{A)-T<&{aq+%v|kIEx{$I2zj8Z`dm0LJeg0@; z3mR>!ohj?r$?Nsp;i->h4F!#+I+z+wiAQG+mk0%orqWDVzw{hnpPaD;jrMC1Q#Aar zU+cg4-~m2|R|^G=wzZfk>zCe-+Nsajf<{wIn2MhRd_yQ`G?ih>`lZjNuGMdBL8JXT zk|{iejq>`^+nFXP%r#3WXtb@Pn6iH9Go0rN1&yXUnL-ZN77O0ipM`=(Q(caN54soK zZmIDL8tqp%QL_G(-ixXpX5}DNBgP;tNt2`W$A2f=1iwW6DND zuk}t53K~uIJIcnu+xme}&}eEYQ#KlUt#_kP&}eFzqoUDxQYdJM3Zk)`sTPUGdAqkQ z^f}ymxrsb9+SUrDY&7&c>gNdsji!!aD!$I2CKNQ9I@VE$p>E5!2?dR&KBp-C2Hmw+ z7{8z)Du~ACnQD+|ocQxcgE@AcP|#>wUtr2cL$7=n2nCI%zR1*uVvGKVE?Y}JCloZA z`Vv#NZs?Wo1wuiispA|KtsD0W1r1R_G>&J=M&sJ<N+Xj>;RWuu{YICnnA zL>?MVeVM8F+1FH|pwZNcOxbAY*;kKH&}ix;Md{hscZGt6s300AGiA?y&+40Z9Teue zODJfxty7q?(a<}buLuQ=rcPyQ0wo@ueQkQIi6Jza`U+Es1{8WeKSn5MH1$U5@T-O#1H z?&nMlq0!VCiqbRKF+xE@R1l3bnX+}`gZXRH&|;&J5(*k^>nx^hH1r+tQ-p#>Q)e?3 zKZCtgC}=eG4W?`~^bGbsp`g)zox_wJE8pC16H37P^}0~dXj|W8%KD|B*4gCqCi2i| z>RU{WrkWd_!R{dxG@3e>DeIS>!A=qi8tvD4OwA-)m;+or>8y>RFxQzvL8EPbnbp$AuV`CdAQUv3`ktb6TRv4NXf$;`Q`WD&?>qci zD9rUEp`g*!_nDeQGWv^LmbzUiXf$;JQ?|VHd7CGNf<{vpD(bXDwx^=Aw$}Zki6Jza zx=2w!IbiMkJoQXP8MpOT% zsLP+h zg@Q&?KViz&joBAmwvD%Su29fu>QY6Wa>>rmcGf&+o z6f~OpsiIzMefb-ndQ&K9GgS63)f*pO=Bc$#Fn&R!sb47Sk@hp+^3-IZpwZMX6{TC{ z=Y@iXs9?VFE2bW%hK2EK*+UN>=xr_dvdJMd+SYYU*|vPx;h+7wr*=HiP|#@VdZzlw z&PJvo)1S62zbF(mn!150+m?^}>AwQ%rzaU(&}iz{iu%8Yet(>|b==8@f`+Id8aFca z0a-va4&S-uDo-7IilLyg-8VVZi*Ke3wi=2XAov*z|6C-PD*4GRLjka|wQ`WET4qE>nPqm(A zC}=cw8&e%*XG8JIQwMzAP|#@VcBZUfZ=du^aJORA>4t(v`*jCXXObQGwb7;Lz3gq> zBos8-)}2gQzsAkF{|--0Jj2+6MpJh&btu`PLs)Xz82(l$Xf*X(rr;OS)hnrKXBu13 zXzFf7>3fK~pJga$H1#`0=^o%sp`alusPp$QWqW{^({Iv(!1{In*~S($+Sa{H*%;~` z;M?CY6f~N;kEuS2M6?G;ont6yG<82ywr=PiV3%(i3K~s4peWq~ydxAeLGGzp|10n|G?OSMpJ)hD!$HVE;bZ2ntGBcTQ_uD-sy*if<{wM zDN47L7lnd`s300oGxerK2HpwYITVai5Bx0G8iF%&eKdX}m9mh$5t z844OrJ;#)dhHfdR|JYE_XuqCk>K*Z`?Uo0FXGV_yiJ_p;wq9V$`lVY+@1=%qS0uW`Rz>vAZ}^-H0k(Y9V@%KD|B4BGh$ zV+$Hh{gbIVlsNrGE^F&7p`g*!D@?&Jq^o;?{|W_-re0N)?g1XW(&P{tO}(Zl-2Mf>h-OxS2Mb{Wx&}iyyMd=Q%CXQm(tJd9Jth z=r4^eXtb^WFlGJHJ-|)BG88nL`Y%)QJ-~(6844Orz0Z{OOZNaLTyH37v|k@EMKA1Q zzuHc};%z9*^{!CRXj_=ZueFBtOZNar-e7D&qp3BRnnQ_Gf^u0~e-sKDO|8ik{6f0A z2bl0{V+$Hht)(d418jMtp`g*!+KSRWz@tJzLsU@b*I~+@O`Y+v4L%Enx!w~B8g1)C zOxYOf`<2_=WO4|NrasIR>O1P8xvZ`Ign~v>>oR5QhQ42Uh)~dIYCT6GH#!<82n7vM zK{VE9s*VWc@X{l`M#n~N4lfZ38f|L>rff9yo&9@-f<{vtI?7t`wq6km8cltKDH{!a zXMdBMP2{1`)JBeqMq@vrpdl)V#z&c&CefJn>qjR09DYtHXtb@3nX=K)_oQwV3K~sq z!W1n*W1f}%k5JHPYE!0cH1xf;eQq()fJRfBDeCy;uLPxhoKVmZ6-47>OwqApt{eO8 z{vzGFv?X_gP|#>wn=@sjp<8%IT>@rm0^4xu3`h{mUwI#8mq*BQq=?{j#VP|#>w+cFg&jf;hX zMpN54DjJRFgn~v>+cOm(joofHenDf>Tq-|7d77UbuYMA~xpW6kd1F)bHJ5F=-J_PN zsriOb(3o_t*XeYm7xpi%Z3Da`r-L5A`gQcW)G#T|UQ^4OM4-t=G&`|oLZHb-G@oY8 z=s+`Vy?k3cM{M;)(%FSIbAojGBbr?!=`4+Cc4H0Q3Ua>JMe?&dYeK*3Bbq%}6UJ~x zMDrQeV1{PnJTs!%GoopTXgLcmw6VWuVCM>VEh-MUP z!uZUIXhuggb0eBD5zV}aW^6<=Kcd--HHpCY1rg2O5zRpn&A5o>;D~0Qh~|)pX5WbB z(1>O~)^rAWK0Bh>pEXAWnr}oj2e2lrhu@CWjmC)Put++Ii01H!rYWLHMl{W=3F~1h zq8T62ER1L-L^SOYO-n@65z$PHXwnhQq=;rwL^GK+iJ&ZwjA&XTnxi6`DXi%Y()n(r zyr!}S`$)Fm=!~Q@Eu!g)Xr@Or-4V?U)`ac7J(8c95luRxnZ=qgK8qrn16lK*z^|T2 zer88By%9}YM00dRGlw;pK-w5)BbvDpO)jFD7t!=ZH1i{x{)lElM6)!aIVhr87SSBc zns7|{QbcnIYr;NZazt||Yw$%38=ol=&0(ww$DQ3m4F=FT9Fx|gOpGabp^R5sO>re7z!dotaNdP@DCWZ86If418S)7fmdrE-1Q z?)I+Un#TU__Ei7kC4I^C^7eFZU#6!!XPiE$Y4U=DB~R{m$@ZS!6_Foyq$#aJoJ6e1g`u%j zN?|Z1&jnMAWWTgBIcG_>XIZjvPN`zUndAcFW0EQrwFhn{T<4o7pg8!~RGqV#?#1qx z9E7^Y+J&iHrrrK>!raE%_9dxovM-y;^yLy0jC@{WEteLzwh4)bL=em{1XW1xK&oL} zg{qL&++-X3Ozotbyzg(P&H{gLPf-VuT1@?hWFAJ7QyWGNr{N~F!g{t?KloBWX{LI6 z)7>43K_}MK(loEWAt5Cp{osn;H1&OpdMJKf)c2u3PhnPqrb1F1ffrmF-B( z>+0`IFE^DmsH&#jx7e;VF+RJZx36c`tVAMc@o~TA{%QW`7PPK8&B zpN+FP*T;?e@i;|HpBX31?>I|q>RQbZ*OXn{-<9s}3&P}V4%+d?`odO%!YC|qS+QeT za#CS&eh|u4+E7eL^`$2EWV>ik^mV3i4r1j6@=%7hZbnaEYgcb)8l{o$h|5A1%A=r> zpg0O@Vq#HHn;(cWh4nM2Ynhko>`%{1WwN;-3PA?>_h_NhGdU`)_9cmel*{s<>^W5qVfXXhDmtygxH8BClxHGNOdVz4ZKse zjg!lp%+OR==1YxD1Mbl461BBdq2|@s*v3`7KPj_lzXF9H`;&=3mI0Xhw9)Qho z)zrDTC!6V8(iN9XV_n>@xoRh8pkBCNBfbguFO^nv(;z(O*deDb?OEBLr5RdP4XL%p z`pK!>k~!H_cWx1P%(PTePRT-MJT3G3(sO(14nexDH`Sg_l;kM-_&>9FoJfnm&e9B) zmo13*Y+8J!vVCO`h*>k{ENz)%O6ID$sTKN}v?T0Gbq)~2P}9_zS=`N|dWkrQ#qp`m z_Wn)^-h|9za;*%%5D9AMEhc{R(%HCOF%7NxW4j-stZ)%NkJ?&&=pRA8;$z5RWOG7@NRO3r|3 zGRkBI9bQ8@WD~V87*9@}Y`UsR>AvZy<@0IXIdkEW>GrH`8w)LgjkHV6dyll<&pe=MvPv>%}#pyPx-055kt+~p` zCHXtUIEoFZ3~eG&voDLIOg7KU8y_1IyzZIU*`HfdUMjFYxei_oH1|?YZRx(I{=S|z z>PS+Z)YJ0V5~w`f{|6SQqf>B=p4{!!xI@XF0H8IA#>3A@S~RPuR0}5qP%~qj0PJwWyASfAp->K z%^qe&v)B|B(1U=$!hMaQxnD zW3B%=SF^#DT3#J2vGF^U#%0IY*3Mx6y^V&@{INcMyB&2eZ*we{h~hE?>)pHXI-7HRDxJr(?ZPjDRib}a77*T*40eb z^`%3QTWU>n)f&8d(LlDt(WKfT@oCp4XS<4%T+ByBS0v``*O}^C*pW((9g`kgKW1UN zAvJo;sP#q?v;5>ELv> zCnm6MycCyB$eDEBC7KB(Y0k(^->44fNck==?mU@0!$m~Y{Zd*n=8z2C2sO_IjE+me z)#cFnWJ6J@NzarE?&`*iOYX@~pm@hz@A=H=;mx=Li6&$7Y;HWaLdYh-cAV>;f`6nM9&MJ3Z4~zIaZiD_wTV6EZlq)X}`6 z?5y;3^moS9d(^UM#*3-#HbHA{E*%aikO8@w*&f%2wP}N9Hr~B7oz11`Tt{ z_P$Bkp8np1GgELe!?!eOXPSJYeWTXg#1x%Nsx%o})!XQip;UG{4J(=6&J_blCJ2nF zr?f4`eveP(+Uen@qWqB_hSL~)! zD>U=;p`OjFglO>wH3v5c3WiAXoS_MAW@*}#f5oYzZ}3pzN@TWxTaKp5MIy%VoXY(| z-`ng0H_8-yYX{=gx1vfmv<1GI*U>Q~X~WWJal&mdrmJSk*RWC4oj1XhSi}UvH0SDB z3yUQ%)7HO`yPB$b6=R1R|Lk-}Kb{y8B;xDF+QP)@;b8WxE6E` zu09m$J%`X}ksh@=R#h+SoJB87O+g-OoKy`{dhuE96zgd^LAM^VO?)Oj-IodH32t0B z$J>ib)j9Xp+;qAtvbd*p+u`(WPjFF!Km|b(t>saiavSSvMk7L?I13PYL__l8N|^2%&TL04XiiiTvAk}+Xzd8J zb`#v*`!TnYI_a3k0B$SU`#yA&j<#hE>`(WH8`EwyXsnC-HE)TTt&{w-+_8yK#~FKk zyO5Z-GOWA7o_}0kkk!Kb{`sd_V=Z!w>HevlKjj-#g-qq$kE89XL}4i<=}(duFl`^D zK$|lM!DEF8p-rxYjMjv7Ga2cb$4AoHIX!feHa1xt4##Lv;IgA|Eo2A(bAJT{m5N|qi)osnSboJ8Ou%OCpzm1Onz1x68B<($I z+CXVbxAPNWi54t`%?+ZSERH*j?@ZHfdT*kowyr4=tjdGGy3OyVT#oKA(K=&Jk6mo| zEtrF3(h@xCij8*auoj?-G}g_suS21I_PIH_q2$hmx!>fPQ@OBvV9S((dEG<3)0Lk> z(7_CVj@yzSKr+Y#Vj)xbmO&>`UpjPwDg5r z-)zS1%GmcD&~%9oCDW6@i_?iRsJtCmgpE>Y9R%K3?{0SC=~9*LAjYmx8|%waHTBXK zyieH1A>yL4kmnqxAtniPSVQim(LqT!%SPL5&3QYe(wBQ;MO?PKm%ert@w|xGJ-_TT zXVv-fvp)|_4nZj5&De-gWAUv+&OFf%_)OvSbl(!X@f7Ay&O|oS_(SBx%<^=HIYw(l z=3p~kbdo@`^bN$P5tkeqLuV>O_n4OV$*J7xq>ovonE{W_^e&;jrJ*x`kj$BwI7a? zz*APPz_GP&CCoK1KRCxRm3d{&FAWE|t+!mP~)JJy`_?R8QuIvHU(QaDQkzv$!mWomn-rR)zj- z1hYH1E^TBpKA>K0CCD;&Y%U*#IyMoYV=JsJ@%&|3y%_Z|ZXH$jG>&>Jc@zXsGR8a) zRXQcpFPW`$>{~6H(bJtZPv{^`ni1&dq)Me|PWNG+6XXo3Or#gaRhASM_hy<)Z#cn2 zjBV+z3^vG8ct*@VKE(ehl`Hp*Y|I;%@W>5@8LUafP>^*=x$4&H8!+$!GI~dCFRk`DbgkyxFF!^_apX6+Msqi~!W(SnOc6JX!j?J; znjgrrFEWV+jvlk;mrm0zMy9=jc8Lm$a;-FG$dY+M8Y-HUskX{3VYIqSbphQk`NznRmvH82lu$9Ux%1sk_6z7_(T4 z<}R`s72>vU3qL5$cdPk@r)mLOV%h21ytqrV>~QZ=_0{E$Cp@_8r@_M!WzacNnHtyt zGR#>V_=vF*WwhcUVg&L&fH7hCb2;!qV1)8od9Oc08Rc%?+K!pD`;OlAd)QhiNR-{f za|$bTA73O@vq~v6a9}keAul_{xCI(U1gwUN*=ekwp2{61w+QK37I(+d@6);-c2@nU zv7?gHCrzxMI$zrT7M2C?V=A>nw4th>*59*&;evAFWQ4lfo?Li(vAQfKk2~Io?CWn+$!HkTvZ{t z^%r?}_#l&&=W!)j{ciEF)2E(}S-$B!Mh&Tv|9YzhNu9zjG?p_8(-SPz@^&_w|&7bOGKaah%z z8*QzvYo?M6eieI))XDH}dZ(agm%=Jh^qgsMAj};H!=2Ueh@3e9GF-u#*EYGS9&dN| zK48$LGyj8n)g&G5sfRl+uJ5KH+x6Z29hY=R zUKgHM|J-R^M3lWr^e-K!7sykPOFMlOB>%Af~r)l*lNf$3EIJjt4oUWU3$U0CG_P`Kk~)aZ~X zVcLKgaJmIHJ7k2%(*~90H@^uDiVt78sa|VK8!PaALd$H^jChkie2$171t|9P8Qw~U zwLBRx37FT72Hl8xxT)adYdEq`CXfbY!kEVlSf#-2v%vFj=77I*Z~$y${mj-0fju{| z=y0!pqgs)&kABgVoZpFt?r#D8A>CuLxt~6W+|zvw-qzJvYu>MxXr(D=gfu+)ZC|El zzc5@DH{KLkW1Y@5_r}2z0KG@Vt*}on_FKFb*6g8mngR{isV+YBo|m3%={l}9w)h9G?yt4O}MdYXwAy@fM;LbnLi zf;w4vK&q!ED%HZY)B@F_n5@id5qMcDHSWRqO~!5Mqx;kJL{qUko18>ZD=rLMNd;m= z$0l4XJjqEVg<%fL7vp;h)P>-U$Yw})Z|I-rJ`ND{bHQIRxhmGl(p-Q#XnX-;py_kH zD$+)HL%4pyn7VOsS#@0w6^D#4#iXTOp`e-~N)%3~oRGNuxapOf&gP0FjTh7w?K0GO zSXtVbCYMZ`Mu)-l9_x?)w&eV8GraKT>(U-wEHD6jJ2{>a|`8x|^yvftr~n{TER z7FSXMiblR;NtP2%dN@4OfhWKV<;zy4LZ_GHrf=W8o=k^%(!5wowAoVVv2ydUI?kgM%uBHu z5vO^TriZRG;`YIP}if_`KrGKc<8BofW1+ z5oXHWzLlpUn!a#a%BY0cTSaV$E7NK$PES=AXfAdyJ2|PaBAk$wp$ewke3rQ{L&yH& zIi9Cuye?R`bpaq0l_wt-p?M_4^$PU*+NJdTZQ&eZ@>R)zRyw_M`UIYAmQJditnuWe zbW-KyDz67FCsFCi^ZQ~yX(^pZDJP@dawVykyk4qU6-N!1x7@j* zpd15cqFb=xpsCoCKt@zXwk6hu5-qqmrkdeLpYk$a-Z)e`EzWX*ooV#dS$a`-eM#2~ z_x0fEUBxB3iDEoH3+D!l0VhPmhVexv>D5cIp?WErmtD(Sm)X@^dgda|cY||afWgEN zSZ-lTrHGE9<(6iV1S%}fLMgd$R380ONe-Yu3np2u5{)&$pJ6RJ{PKnw=6L+^)S^-J(r{#5=BMkJT5mwl~S>>$h?=xHbv@+F*5P@GP~%UP$z$iB}gnRMmAJH6Bb`t zy6LH-@Z2w*38Ev9xrsg5Im>z&%*|ZHZ`b9w?By*(-HOwb^d${;VcPiVLAE)X-bq9s z-!Xu%JmF7eXZQ5B&K>HLm$vLJUIJM^J5#w}kAJ+tOpm6VCc2>gWq3N57 zLTbfaIBh+^lt|HcX0GDmERcMbD)!4IdF2pBO$|GyilH-tZ>~R+gAnfD=IC9aN9gEA zE`HUPm`jcXUCvx=@8QTk?Y7y|YLkcN%%ePgXTFMw+?waC3+0&39Lulxv2OFAv)K%# z?yw?vd}!Hw^3-}=>Oln`6vQWflA%tTxWNxKI7g4*+HXozcSG*1{?4Ph2VVOvxBsz7 zn4QN+B1-u`L$#d^90&x7E$FxR|YF7p3T9D*pqG3rEN> zDW&ka8k83gd9R{tbNLSx%UeVLhk{ig0tF-VKUt&9W+6TF5qV#$YyiofIBI}6yJ$XG zu?Wwx|BuupIsqGftq}G!C?e`m=xRU0qZ2akc!|vB67yEmnH&}J)HFW-r%HGAbJyN0 zjk}#@I!rUC{htViS+^FN@SFWit`QiE(^+18t!yh6zw8MYe6%Dtk8R;lw`;PimIHpZ zoorbRoUpHor4vN%YXY*uUBzlwTt#y`6a{xI3cL`avPFL0GMu+i2K~rKWR!Dz76tOW zvh@M9Ye5@6?o3Z!kfbY+y$bqLWTri)cVFFn<}C{6tXm8C!(e$s{p#hvtRnOLr+o=i zqw&4np6+tCCRU3UP<%^5=J`REJGp2R3OK0|i?V)c!~AdX_Ju0fH_4}TWL?fz7} z#$P={6fFDc33GIHv>TKcn?W8kSiJ*R{jGrit$67p2a)}EzU{htMx>mjzUf%i7!S^uWimR9q!j#~H1!vaYaeFt=1qLp8Eo&Qn>eYV)USk8me9ESV^<)sGk zk6i@m=Pdxu3ozm-7u9)v^zEu-rh8FO0xw3u7ey+36-K;)!rAh_aqq{7Phu$Elo4;q zXQ}Y9aQo7RfxSLs@OItHBI1*(!rL_}sGkMiei5Iw!qGMF;)tiJ`Bsj23x)ILe`8C% zbo2|nv}1M}pDk;nPi1zd`{?tRWuAQSIiL+EI)!fDkWe{ItBlAOZp`$w+!F>ky%uqz z+!sX@a-(v-up{NB6+Wyd9~+5%=ALJy=A|D#`@u+s^$a$YkOnP+%?Gjg@c_G|qn8E^ zC}r*s`5`)N`41=wWKK`$s*p@=a<=J5tF}_2W9mr0ez` zwP^I1MdRu^+B@3QWANXo_Js=@_8N0QA~AuQz`|56)1J)Ho1nWFCniv>ZeNnhCi}9f zOka)!{PhiL9R9l+c+;`}s0JcVjW9X2GP_iH@uH*2iMXkSFW$UnPA?R&vyEhOVlLT5 z@2*~+prv}WC6w2Uyrq$E&I$QEOk*k6%57MMoU5F#P9t{?)+Sr%eLD0ajAYi;U%Yy| zm8xTTpK_t5)Jk=ul_9Q6$)>)ZE~?1%m8vYg$tIb~C6ZI9Q0>pn=d1V~Qv>jyTY;(c z2T?nokeou6tCqUF)6C^{SbP`{AMmDt>O?5thip27*PZlc(|x8asL0BGkCCsrHs%~~ zD)E6NQEC0CwCgZ=v^gzaJ1R~)Kdxoejf!pL)$U?7qvEvl^B-F;Do&MiOdq>KGeoVZ zI03E`bcbcml1$Fd;Y!U$6GdNvW?o4dpN4rC8ZRG1gWEyDTGR#<)~km4vpEv}%*%dwN$SyV6}S%TJeg`(q9EA_Q|MnZ17UK)MulT zEws;Pzq~~UX?pZ`)#vY(7owtH)QYIXj?D+7T-js_R8TLA#oV2>@K(Z*qx1$F@-j@6 z8S(g0#pgT{pOQdcq^Q=HL|S!)cDubLU#~vj7%N?W-L7wWNtRPSG{n0;pT5yk(n(~M zA7$}h^eHDcWRzW}VN`zj2)4rs(F40)mNc*W(-d0PDp4?Q^*g;Q^ItztfO<$$^PJTv{ zxA8k`@A#3M?ykk&-x++?<0qp00fQpB45LEsoOm!}$0x zmb0-ElKkTRXyqhdc_ls+Z?cbZZSaRCqKOXj4pmHoZuaYUg7^htKKf{C{NYQwjYA(a zh{P4&9XIQ|mTdS5YUb!m5mBIJIX;I#Phtius*+X;Li0zHUHWQsJm9N zKDKuE_V>+BA4y+_p>r#ZwZXq}U#!sQ#(fm?U5yP)d?)4;DI8K)dNX?Z=H@7iWtJ=U zlwutYKe0_qVyR(+D!06S$oe?9>Pv@3 zj=e^!ZK*H9Mu?`)&Yop6db+c;39>Yu#pge$m}qCI|F;h{^DZM`v$*4C} zvepbF^>kl~`l$j(5W`?nrI%>L^fJLa)MF2EQnN9U}^z>xyn^U=2(}zR7Pxugn zYz!26MFNg?cm@pyFF=bFQ>EE=I}$Wf)I-VIc$)6puNXS?iiaIkhO|C)5+ zF$%|D+^w}(FDtheCWw1%k+wg$ubsstH@7>}mnbzh@x8p_zLxoY#7GWs*Ni>|-`>+j zO8|3Tuypk+Fowhy0<}{9Vtk^&qj|oIi_B1B`d+koIz-WxTAZ$0g0uY$HXMquUm1MO z%#B87A2Vo`<@M$9gOW3n_pqybZBLnF62+xLH|+Lb0Y~ynE0mR<;!{na|JOwuJC>Gt zj>6S_pJZO@n6c3DiAepP9`{Mzk_}FGE%+CIGrUmhD+ZQeTn9s^s^u7PIj^Gg;lT64 zn6wo*{~O8q|NpibW>nJZ!Z)a65G_3D#MH3=|2B3yaZ3HM4q{B-?S>gUGcPp5p~s*i z^;LQ|DKLDLb#|JLSLV{)7`1Rzrh(+{LNWH4_371aT@ zV`7Fr(uKh`W}4?`&b+B&#`2izPB(fo9h6wf!*gZ~EH-zH3qdB=lkCqWn%ZX62MZd0 z-rAnQiP?$ytShzi8NDYhXnFU+f;Ju5-73~q#O*kU;Sp%ZCRmjhaN%WivAtXIvvPAqHg6@( zp{q{~-1r7mpA1^Ly912wK+P44u1Ry~qC0A&x;A5Y*ve+0=8Bb#NptAR#*FcebyYi~ zQ*Tlnfev=WrYpv9<<+cMxtlbHuH4NGYXnMZ#HMz}aCJ+`q&ak@G-9(+W4OA(GHDK7 zu=X0MVa6D)Zm>+6Ll>;QIanjm{*B=gmohR;|Gd-A}!)+Ygf0~@`>`i9}_!d0B{e%@JmV&fRgX7ABc-CWpS&u)MTIFXw zY~DudiHrjF<9#o7mKz6_dF38_s6Fq=fxs4Zzy0YUej-E6VJicBl}*{j{atidG}wA5 z`1C;q=%5a-t9{ixqZ3knsfj&VIz(S#j_L4dh7QZc7h%l4jp-!n=(s=LrItpF=t%vp{frpm?TGFdR4)Mq}r$a#b-X{U+PFC&N}5E*Ef9LOAq4v z2ic8{xyND>seFDi!0k8=cjeZKt^7I3%Flxu$E$T*)1_9eD7InGy=19v9Hs@)!! zWGcjD%9;v|uYXqDzhO6t0x!ExS z&J4kwn}(6Pv(hk9d+iM)wSC-Rb}xs2Mkj_xpu(Ch$Pw_^>@hXgtz4@F(|)l{waRTR z4KVBRbMGo|E!n&c(+e=fT=m{nVH1@7o4mtydHE0J&u+QmsJ-sC?tXc(xLrOD~qOm3HA>BGV(j@HY7y zx`j8_>B^2}n=Dm!EPIq$;8(Rhjv9jHu2~?il9Sc}W_?&Dt&+Fu%_41rr3Q%TEfq_y zT$3M@tEx_ZOp?Pt`7w5fe*$6bR=0=Y-f<-yYK^b)8Ka?g#78ZYzabm7Mvv5S9a*ldIt$42<339}JA$$_Imi-PRtc zwQy~i_x>f5fSWowKvBXzH1%t#$OA2U)%xJ{(#IopAKATv5Ew+Xt} zmX><`umys5_YT3ke7zNV=W9jh?<~1;4Fe`u!#@ldyTd;W7`wwY3=Gs-kzv3jIb_|e z>A0%cj%|XKPrOFze(^~4-NtU^RkKKCF-Zo~LK8v&0;s#cCvD>Qbi+Dn-vhoChi$1h*bZ?{V@DO>KYovP^eJ zZDV6y+I`E0-+39FJfbIyYHEAw%~+{2bS}ZxD z4OkONuFT28c{`|S!2(};<;q?13n(%YtMm%}-X?&>+QL*W({2-)K(E(q zUy{lu`?4weE^=amNtRyI&6OoZpLC<2(X(;I3!|#3Rx`5)@>h*~bE$&=Hpyycb8fPY z3zhn;ZYtjXc8WXxPCZw$FSR&fK4wLaJ;ONOP8)UsRq$y*_J=zF{MczBy09JDoFhOi+@ow}h+cWqs5;}E59azAwG zoBY=gasG!ceOq}N>)m85c;Xx5BfSUNx4q&jmsnj~Vm$k({@40^=7!g5dvEV@JG&cJ zcXRXrWqK~pK&PjAF}WO8^O@cT&cU!7E~9ptN9Xm-yI^nvaam;<=qo6KfGR6;f!;Zs zoD}Cofyrx0sY|w;7h()*G*P2A?eCX*`^KP+h2=OL_M-J*IIM>CXgKUuRAFekT4}Kh zQeoiBg(tt7)>G^|_0V6Kw7B0We2B`!o| z?ArN~%K8umz)|n zZ)^`J1)B*MKlkyma+BkVkerHeg!cifm!Qp}@v`FlnSdpy(kjT;)~cjsGd3aJmug>< zDDYA7XtUw>2l>1V6!$~JKvT#cDh8U4A36q_f(<2~MaDjK-fM&M{;A#~G|*WEk19c( z7!ljP5J$v(ehnCrO!(?EBIXBE_w35dZ5helZeD%O`=_eDHi^O21e;1V3e=`GxN@B9p~fZU!_P1M(c>ZY4tE2^8iuP4<_ z*A|@nq;nbHU3Udj8RP?B8J8c}%4i?B$~YUCX+5b9N0$8FHO<*^cBsHK1+Ut7!K;44 zKETyaJHHUBZ^0K-_0zV6S?!OPyTYt~!oD!8pLTv>R^Ngz%<89Y3p4ML3i&7AFlUwn zvBQou(C|eS0@8us2L7~1-Zq_Tw8LuCSAk(Qn_oMI)wr)X!)n&nDZHgHmvc2|R{z4z zO#9UI3b#$9_P@+Wneu8|LwH)SYU$Yw(yJcJ&0RBnGOBrAvD{TBF`Kn~U$dE|bV{#^ z!5esjHjB#P63JBiD5VMScxi2U&IKn@-7ZA2U<7(+AUUZ3p%&6M`SR2@@mc+S^k8jm z@LCrM`iB#s+ky&Z-S7c7c2Q`(~$) zOt<3`hlA@p4$OZ@W@u6mhm9f0esruE5;NfdH6#Xxu#~CI%(dIjcCe~`X@^#vGuYg& zUY#v4><*a;=SFREc3K`XPA3;f(`UpR1Ecri@0fc4f3Wd1T6H%xYIgtCL5;VAO<{qtFU0*_G<= zL}YO{O%3NJC!`mp=$oqMJt~mOOEb*r4mo>@1FvdNg}Tw|r|mLc7jEIxvlA10`f1VF zO5f{VOeY8Z5;rY2Il3Pc!}}*v}ev zyVl{^>5l&PVRm*{ZCXd$+EbmWtQ0DJhPx`IOK01|!sSw}3yO7kjapa7r*iG7j`Z*u z#~bh6PWuR1x6acuFx4pA*tfe?IboOO`sqC#bWX?Qu|$ ziXI0MtB%J(N~(7pL^REcd?C6-SWvIV6XW;oEK`*h$TDH8RkBQ8S}MzgHS5(y=?m7e z6-CCXVBB;xhN!9TS}xi*!o5b(lJO6Yw5!1;&ppvXh|cnY#6~vFMEbCQq6`jjP!Jagd4`7M28{X@lw*6 zsz{$BQ-^;uh-0vMCP}53Hj~H(3uY2c*GYML`B)*(t!x|tt{y{FgNDWsJ4I1rpkdJ0 z7-H*cLp?X34y;k*;h|*Q*PUL8)>7Y4byH07v)1b{nC8vppCSrPLa46_9jHo5)Pb4tM%=S>C>7M>|F*Yiz7n_Mrbzq2=2m68s zFQmC1sIjJwa&~fLNDW5^*T!gFlz)|>Ig%UV8tcum4Jt-)Vwv-8VsgA>GTAKXLkxlqeI68n&Pkf#6$WU)A z7Ox*3>`6vrgEh1|!MsHn+pS5C0~$)z@e`678$T_pD#uSz>UjLLH084)_X>9Y@py@* z4&`T)uEsF93}wYt#zV#AC*vVx<0RuDXY!Eo5Yn`5c8{@Bbn%Vx64hAs4-NH?@UN{6SLA4=HYtgBN%drQl|1A?< znTWeX($)m0!l@tUy(HC5$tHf>7dsBTKDtTm46sq^u22L#uJe zv@|CP>zdj#uX%T@0OMZXZa?CrB2H?_Dy-$rhuNr?jsgw zuu><#IJe~6{9@iV*XEZ9mOPtZ%xgK87Upeii4Dfp9!#0WXqe( zwIA}5gIze0##8mr!U0&cElnWAPokppK>XNYvC^;{L&!ZznN0DgNy?{#i%wE*Q@nnX^68wB zI@EzEtx;mt)P(0F%2MIR`IVHLT(i>TV$&@%O)gH;XQ#=vaN*;alhgjSub>p|s8OD-6pJ7C+3uYKydPIg1HSOq) zaD6!f`qFw}M^B$Rpz3qo6mHsH$J+>G>KYCjh}07iw!u(O+8J--SePC^e>j(3l84M& zJv9$Skhvufnb&eG#_kNAi2QMWF%Xuo?905HuM$`@aK6eRb8)^(pk?Jy0_V=IiL8nC zM-#La4O=#*7fq9`@-=?7n}?ihN_QGA%OB_hC3^f=H2lLUz{INj3vahLMFJrtk zAJ|F0QO9HQWMe4-$AU(wt+6~Bv!1o9gq(^%Q`*=IxUm9{jNVf)=0RqwxeQ0#e#IB^Kx;H!L5hzs$tv$>Tbn$*^c@>I&7$rDuB@h#!8X)yzHR0emxkA8%(T?#RtY*Pok0u z__Sh;Dhf+wk*=EDA-otBqgR}Met?msy0VC~BIVQ+Lrs?%1)Yg+gkmBHohT(EX%#_VURwqmM~hz_F&tFaayQG zmggiY{`Bl&Ra$+BQ`b9kgdjwi*SKhau^)lZPj34w*ch$s9R(c+#A_Mcv3c zSk+~jId(Jp$J7F{?H(K2LOG)^T`*@!SUoCd2}uXZSrVGP4X2dkD6Q1pviR95IZaLz z4~bwP2R*~Fc{7a%i7^~(!lUoPWoq5$G6_u#wy|SoA~;msnQFpBMq{TY(9XULQ3LU~ zX_tT#{i_UlJsnIVS6$H>sxu5sq&6-c-fIMU^`n$w>4-KQg24`UDkU|%R^gwJX=kjA z;%EtlYlcU{gR#Lg)Hv<=$fVvdIdKUB56ta>~|hOiVnQZ`N^ zoRf-da57FJoRj(4;AEUcbSGKWukGoU-a%?jIVL=Ys9Lhs<>p+%`WtqGckl{NS>J2!945Uz8b*QHgtAjl%FWrpW?3v0z z&S*6#dyivCs7@xtR=b-9tsN5b9!E<^FMahMi{2qi_*N|_U(zN%JebQQG%+AJS5jtT(5J#)#mHq6ni%jEH=Wx!ttYrf z-qjK`3A4B@9^HWHlbo4*+=*zSxLU(4m8_Y3+=*zS!02wYY=ftc zx^i~lZAH1S(U4iI(<5ac$^+Qi8}blE_G>(VH3=Kkq@ML5TYHCJZ--0K`S;39cvIti zY>}lN#uneInz2!l+8SGYO@VsZAPamaC8DwFT4;t_Ol{~KP?oCC0dcEca*%{HS`LV7 z7S)T$^cEGX7QEEvS*9v2nPtLOD`uIzv|yGAYu3X_7g6>(tWz%3Dl(_dyN#{e>=4sf zLqXFWi}v!fINaF7QkOIbZ)Ag%#uh)sgSNDAEdE)^Rntv_@{Id7Y(|kVw^qkVMQ4V# zX4k7AXC+xSCuaw|8meQq-}*SnXzXaGO|Ziy9MxmlE8Q?iGv@dj18mFtv8Fz@$Xe3X z6;A56&h@6j$+9XfNo(noHi9fq(n58)!VS(0+jJE?fHl$~oYWdc0d$7yW8Y&ZqgZ2M zAD;#gSaZO!9HP+$d3cGzxpSO~G*^xjvKl+b$w^nqaYC9mu+jeo?7)Kj7~W;eMKWR~v)rX(5@z9qSSEL=n1oq0A;RP?6_YTFCq$UsrD76h z$%F`#yHrfVVC_eBd3ANJOMo0EV-_cO)w8J)kh^5e;^eM^Hi?tFWX$5^u8KB^le=Wh z;^eN9Hi?tFWX$5^u9`N9le=Wh;^eNPHi?tFWX$5^uBtYPle=UzakRZo_=tdqk+(Fn z%QV{Nwwz758Aa2Qb6jQ{4t2DeK731=2)0i4W`mS8 zRW_(uZI}(3(zw~6rkTMo$1;Ahsds zrEiPl(E)4>+pqRu^H)<_#{SDB6An*OAja*Lv!;h@R_k(Chi$8Rq8p4 zRjr;QO4WLfqRDS4Jv_#B%J~^Z*OIR;qponIe^?Ew{X^IwqTBu(9jlG3@oM`ciG)++ z?h5SYP)_$H*N=EP24Hn$-%U)YHYJ?R(5)&$q&z2AKI$H3eu@Z z4OW;mI2m{`>;N-qG{d%;nFQSEyA5G>eX@8Bwk?_z+;H7gP7-c-PiwMp!*x?NsdO`0 zxX}t?KB7u{eq(F3@s-H5iXWAm;WOvl5Z8;!+>qx!jIu8`})Z!0(CIrljuuenWi zS#`Vq6|$_Dv*JVLye4m3Y;1j1_^{Wh@zduDIGUj;Jb4(BD&iKV9TYNcPg-N9ZyZtk z5d$%XeR}wQMD9&TYdYQ=kJgx3=1?lp$P@IZ?3ijc#=Ik z=NzyD*s}H>ClzzDhdQa)(tJLY@b~nnLrGRCBS$-rIPg7djGsaqO2qM!k)AbPN>*nW zFFk3$@lw)M&Nc~g*0asVCTYP^ecp&$mE5d#7zjBxjm>3ME9Od ziu~TA8kFEYlCBB8)l0``)TwJD!~IF0UE9V|l^UxP(=;Y;zR*~mAvem#b#9U|=sd>) zr5Gy5=^3n>ifN7)2vOE4K#?6{Gw137et^G*QW1gP#42^7ZKUa?HK zt!qxh90OT_slMCE5;&Akyow};<7!7wpE{tn4$;QJ7=+HqOa>c~RbfHRn(59Yl*Xo5 z_KQX=PQaVs2C2yyPQ=SX~4MW9X-}qZ=_i zFx*e4RH9% zjm6^HCeJj6A72~kp|0(eZvoMHfHX(OzXrv2!*r00MI9T|I6CsyR&*-vBej{l$f!2W z-RL-GlTZ1kU?<%;pa0! z`7euZ7!-x5!Rw=gk^W8ftJRGJ}clL$z-djFfV{f1+86<7N{ko(eRu+TFKNvrS%Y)Ao(zBLURfl@&0h= zL5%$C!kRqd!>$I+9WbuNvwsgeDbzUNJ*A5a_mO_X66B8*WH%K;3Nj7Wf8<0d(?z5s zo3Z$hG-azP(@^_II^rO}P!JRq5W5?V$|tR(C^veD$~nSx%I6_;E~dww51HI=*DTZql)4?M_WP24yd1(y^xH18WY@|JK***Qq`6 zks&Plv|X|vNXah93a$P?n^>+dvq^VbMdiZEaC1X_1&!9u_wDF){P`xBZZfZH*_{OB zO>}MC!vZ*vU`;-I2^j`e|E-|4?{Xb;t(cH(|BKN7PoNRmm@FCNU!ErKQ*EKbD zrLBxh)yIY`t%v(C>rHbw`*EkKshQNRqb(C|Y%$;zm)&A`U0TEN)Z}Zm$OccEelE?1C!OCM%(_}e^p{yw;ux4Vt@9y~NdSI|;YWC&xO)%YL z9+#py$v26+^0{7}_hC?p<|dxjr%f$|jDNk}he02jgV=YKrj`b5zd@0E5U>u?l$6+F zWL?H7(=D0`66r<~-J(2~$*Eg3Rm9TG<=idGV^PP}Et+BiYbJJ_d(F~3*Tl^KPby|T zEDD%Z{CZv~FsZoquzX-r@vCLH>aym@dbKSQ#}@QLuH4mGs7l36Z8RXuP$twC>u4Z`cS~bpg zc^FKrjl~DpM?g4T1}{T_P{?GJtWh+YCTm1f?UOaqMk8g7sI*jFpdIzFv!%j~uBHkF zOjgPYHOU;tAv_#tb+tFm!@F_3D1W%tvSYit z7F*qRLk$R)|e$y?#|>*t};-$RacF zln}?7v!{emGRsd1aU9D6ugCc~l?Iu|cPW<^5D7|3(v~=au z3bZk4pFTpfUHCPAYC3ae;dV9B-yg#clWKTfJhm~sX2jQhe1BwMO>ZPzS+S&dfm*(} za&6UuwM)u-dwP4+1$0;TtXVUE(Sl_@Ume<`Ya)qgPdJf`qh0E&LlYBYWbtq^9*HIs z03?#VK5A=TOGuc*6Uu3YiUybLAywU5jt`^M~(MIg)E8}OHp(xI-icEXL zPC!bUP;Aj#XJ0g-jftk44e+_16d!J(DGYlWsYk|7WV*)8i5bm_Ogc5|PA~(;>@mSf zJNlV%9!%DkUcAc~)7__x$nmD(;y>9;CatezGcgyx$YwH{5AZ2nwqzHzw@t%IKU|5H z!{S)%0kuQz=asy{eDbjivoExCwvNsPw5+H#EIgj@bTxsSV;fYQ(HP6BwEk5F(Q=rA zCPXz2;AF*E4#PRwrmZpV-R!8alIl7&ZW#JAJZ9a?#+RHXo=4MrN^C4Xl>uQ{c4nVx zYk`^l6l5uxecGBa(`K@C+8#sR%7COaU^W@Gnl78PrO~oURX0~zxHdL45*|5MDUN|0$CBuXG%FE}g z>@vRKVSeU30p0av15Bj12pzsif3(*hUpG9U4kitirv*_LNk;0~w|q93mROQzqxpjh(&H%$yqzyg0u$B#o38$^yhLub9)cM<6x37b)q8a@LtM zy_|J}@WR?L*XcBz5t?5(BFsX&z#zHf+Z6GUELBOheqU{En}2yAu-sRRVoj|ss}12^ zUcDfiK+P0O;z1TD)eA<{WObFEr54qO>irEh%?-X`USH~ODr@S4wV}Ft6agUDM7RE~ zuEAFy3N|+e8k&6epD448j1jf!1+g_OnpQkEW0E-@jr5C>&GKhko6kpulE~7+a2Al| zPl}^wXzwvJvw4nTHe&|SWcIOeZuyf0F_@V$vLQQ(1Z^u1Th<(qk{erqfdM^z^0T^t zud$`Ed3j?E9FFZ+sBv#J^=TNWs9w;6rWqALEMBv(rm408ZNZwf@p@yb94 zYiz4o?rTtSHajZKHT|l6(t51A<-VrcV5q6CCFHYRAwkU6Mc1i`WJgrSYVp-KH#Ic- z>sy^;b;gGWX@vxfwMhTWJPV&BvP#sH39?L?Wt!~S zO3P$j<@kh6%jGP$gnY}Jn~}$Yey;^9YpjoJ{S6dH_NY?z#;vhm)m~`{=ji#ip%s2# zH5P{l{65>)RjeN(`v@Ytv{zcfMH055G6~z)JPEgsoJh?UVocZtVBx_NQXkmzn@JuLR4EZzPkBkg9;54W+^KjAHjvBsxht$}yZKLSg5L9eIW|mwaDNMOws~p?sI!}%W!BCp_lAAQZs&u`2Rxvn& zG$(chXzZeo%{roOktp_!k}k>L8`yORR%Ote)peOc9KmkJF{A()N2Ss(7)kWu$Pwe_ zOj1Rfj$J{5aSs^Dsu!?Uy17&l8pO3c=i+FMeS-sN(m4WzWNF?@snP(oBEiCn5uj_sv~w8N#oBI zB-rzSk=%IzGv?ya4d|1m=?s#h zro)&7P6rmcCzyGS0Z*?IZjkcM%!(beCDx>KfM`XL!)qaq>su+0D~vSi?`WwIt0j5vrCL#A!Slld&KV?;a+ii?l-#8t)ST-Cq`}6gf1}b3 zBc&M+xJt#2hl;Me@e@G$DfOW7&Repk;VqjT%RvygoKO zh`oAK7Rw2Ru~FPQUt7!a=9<>#pa!IQhe0eni1K*V3liALH?cOVVumcq=DTP?h{vS# zNlCAGG2HHzK0Mp7w8Uc~zQq_M_lVWTzp>~q-KvBBv3T*Iba3Cxq|?R))A!g9X0 zM&2`$oT14V^80HV>+7+EqO7)7Ovw&YirO4mZ9V45u&$^LlU@$A$$y5}_T9R(=xlly zKzE$6#MPW=3~|j4H6{XZt}(>3cQp7^|GF4+4xMH~Uw3WX8r_ho7d6zig_>HI`+ewb zbwtmQQzqT>JU(DBEVD`1Ht~uC(iA-XjM|0!^Q?-7qw+bw;)xq)sb0bjxv142XbU@( zS>85hl5KfPOsv9i=nQBx!`&|LwKBs2!s-l%cZRI1PmwNa4b|Bc<)F}^o<6J&_NeH0 zV+o&mN?yaM=pYkQ#NMh zO)`qrCHA<5HO6pFjP$W=SWX|w>HKo<$y!bBJ!X1yr{_Oa`RU>;vQzKk^syY|q&8P& zU8pwbUygbXmJ@Dnsu0cP9614ith%xJ*h+IvcKkOVq%xfI#>NHYa9b-|nVz7%PH?(( zM~APASdi&;u~L3R#R6=9(#;C^`KH5I7#y!Om>kX%Tlbi&F#{DtB8JC>HDYMYI3%dK zM7~O7Gjf{eB5@~W_Rt0rr;?B5rA(<4KPD&3N0|(6rq56q{EQb06pHLW|)BYxAFm2NFYSPZUG6daT+ujO*4nvZ$D{6#oCTAU(Am}Q48mdYC|;nIDbV=phl?{A8L+;KnT&fk}DdU>l)zjF?{eL5Dq8D;O@X?`MhXt;!3*%c9lRpY?4yC3>LvOM8ue=pH3nK* z>wJ8FC-Y~E;tNfip>Q_ALMEyR)h-YCYwKu>s5<%KP7Q_}>)XHyzPuwB$2WutjG@uD ze5Vgb*>`$F+98qRlf6WEU^uC6f|%9SDVy_ptH-4UcI?*UmDtDBSJlnsVQbv+RcBde zM+f#Znkv!-AyOhdBKNl@?sI7#_b`$pZ2DNeoYv7N=G^z{&>Il0Y4Q~aY)zQf&`oLLv{%YO zOqtik+6CuVat(qj#_#jCfEGA!D`;&;_qD|-wl6hN^sc5s1^k^s7H1ICVq;kE5g4fG z$=koy7;t-QV8IP0m`H7K+H>QIlWci_nfUX7ukyGyLi6KFk9fg!Mrg@qXB0_@F@`u&qA^5f)~FBbQ+Ae0QxgRXMVug- z{?j2On`wzjC|hp8d$|1bJjNfHLubdJc)p^AL(*H0c+GGq|78ImS;-8g%@$bR%SoR0Sr0*xn?VT%uKE zSzDmhv{*(S-RI6S%<|Zkr^BgCn8)QP#F}nGL zBuF(3yjEY!og5j{dp(s+y`8bD+?HSWMH@`>$x!JzwV$&^I#t3p9m>t)Ot)nliA_KkqFm8Q$IK%o|oI4PmW2vvq9%91;6K>=%^+igUlv2Pn&uibeUFLiY>tBfSR+ib6*CC{$=R4~Ik zqcnXuBZScD0Mh*4kq(NqTREGF2c(Iwi9DXv(bTo|-84yaT}mgggIh4pdrQb-P(;De z7hV@h6EOWMX;<%ZX3UdwTC%+!$A0e~=Eas*njI~{!e4DerIV(4jhzxP@P!?Mduhw? zmDmog1K<2bdr%4UEz5l&e0mTV93JS5(V23-l~pw(Nwqa@-b1GhXE;hTm6b!~W#u&i zeFKX!ocTew0mRwo<=c+pLDTGx)&g?bj#7c1rNmhm_yAEH2g2vwE&fB5k+w9D1I(`GbCcG$1%}h zjpPb!Oy+$S*feZ`4qRrjHTkKZm03(7^jITGHyA60Dwmx$`GASdPMn&&c5#J7&aWiT z&KP{xK`*_37H_m)rg1fCGL5G@Y-X(TXi^JfOIGi(iZwG>Plo=`U~eRDJZYP!g|17N zD@@aXD@cgz0V8Ge0H$*yv>i!l?-O%(ZDEaGg=$-#GOu)vq>1AS65@EkNO3X+^A34` zs#v;RXvbMcltB(hj1(gcB%PkE8@aYurP=w_-Y~9_G=W?}LLv_sX_!pGLRWB4i@!<3 zfTSbJAcrGHijf8)rJ(VO6~pSV@pB!?klkC25xaMS0q0jT;p#Ge&}6@wz;>T$51n)v z8yPDNO^ESwfw76PvcPqf&f`QiIs{il0Mloo-}_n7-}f+*ZganXLH`kwb=qsGKG; zQlJi=WjC0fqTC8CMRz@fbUnCi1X3YUywtThX+4DjI*rlQ3GAISeJm$~>HeLbgmva7 zgQ(65$bg7VPGb|``d4*RXv<61u*`SqWMzs~N_lK0QSj!wIYddRm#I@y9=<~#pJXw5 z9UHun6&j}J@Rt8QnKov|7WMW8v1wL^TawQLLW~cE%%;NRLm{!T*!d6%EL*NDk4ni| z7ViG=W$Gy|w?oFB;!@jZ?hl2~#tg0x+@-Ct`L{mfIxxYp4&8BFNax>iJm{{tqglXA zi?MXi%kG>$%%Ce%pDUOG;<3Hd+qocOJ|z~#)?KY0@J2n&`+7y=5RB%jTIgJI&lo!)d@JM;}zQ%_l zvrb8A9Wv~cl+`}dPGM1v8CUO2=-p(eOgpjN*1by0N{*=R|xsw}XOoi^3 zw$4M>rKOjwJ61k+E{(lpzGsa=3d`OC=JP-&_rb<;QaazHlH~_-YrZjWtoibjcVktS zw+65XAsf=H$IA`Fnj_ZkF1<1w6TSm;d^Tp6r;wngQempw6AhQt(Tgc$OkPSlW>USQ zFy%znhpeRsPeoxJGV4?n)mY(AZKI}UTD?P{_jGMDEbm!)Z7w^G=jJ{&>9)B~OZS_J zN{aVHxqhj7ahJBLxicEb-K(FEQPcE7L(fGwm7BOVIfOS7LsV091bd2+?Q$RpdSuj=YXWPx30>(>ishWDzdN*Xsh^kk*(o?6B zkPew~Dv4;Uyr-rSQ!{01&&MG{=Bxvm{q&@(PMmbM)128CjT?}6BQ@%I)oDpLkC~4` ziJl}rZ5~iN)PA)mX*!om+fjfj2q%o@vQF{T}@#mCNHQeJAf zDi)P5T2NV8xn!{+5RVn*_t4h1l&DadB`;Ul+I~8)tc@rg^KblFt=a8 zadYtFn}c*M^kN9_zEDvf!c7;%vZZ$$5_%e#t)mR46ywK^UORAq0%pnQIBuo`y}O}^ z8-VHgD#ww4lHMjBh<{06w|rAk?!rx%&Ywk&%_LcPf7D=skt-m+yye9^kkl{MgYeg(6-DX68>gZeRS^(c1_7y${UpkGj)4aA!qn z0p_%4IBuZ>y+xpR{C7c*Z{lw*Gn04}p% znbUn5nBNGTQ@X>T@hUJU{eh8l^yfAZ*aXZYuW;N9{78AF|3wkL@2iTk1vgzg;kMJ? zd!YAyV7~Py22d8*9^?X0ta`rO?S^}igGhB_x**aDX!@@zpf}J z;-lpa?M%>Ev5Wx!Na(0hd1xf%nU2gPF1m;V-avbT?j$ReQcipW(@#Ch8{w$ZCZ;qV-q#Zr7 z=iXFl8ZJ9}R4nfY+evCKaO*vNBo^BFhq|oJN~AF z%%_1nXaDr{?hzPH&7R(`@bW(3t~kJ*-lu^31u*Rga-387ye|Yf7nrXd%yCZkrTCj* zyibtbo(-_kkdDgCH(5xyrdmkS)F zYv(US@7uuqAPv3G0(UPkjYslyo#-tDE)2|<1dja2&R_O$#nZT_4ggbwS0Cy=cw+S4f?f82M;r9UZ zjd||$h`;B7+3i@4bK~z&VE!j?Zt^Zg3U~ev!t1X9^TYWZ=T!c! zMgjE~VCtzuh3i1vcK%m`@KY8SC|Ba9%gJBJ(eDA~o+TXTBrnnXH!#O9b*G0aS~&@r z(~e6|?|NWf6F4XSsQfEJBWBtO?(_};ZW%CPfpfA4bvqKkd~#WOdY1w7LxFRm_gBz+ zf^gOD^hmz91qP4ovh!yu|K0`eH@@`r_VII!AZMFD-oVTKfh(?Yr$_D9dVz7H_a0uh z0T-<0^qks5R4-pHFmCjyJopZ9pQ&@_kM#Gjz_`&Pc^?JtM}hS8-Vqo#dgL$f0ryh9 zJH0004s1aC05@HfkL>LG1YTbY%utBqW&tPjuk1%r_-nwtEpUWp^ep2Mq?i8*3?A8K zm+l-maKZ8drKE|cYaWk~{S@+p?+J_`XDbIa)9wQ9m(84>lOK>?j%Y#q9yeW1dg%jy zw*a%x3OoMHdbtCb2Lz7Lc6y<4%qIng(xuBzFBgKq@$Ci5gB^D1O1k2M9#!MN$7f9>QT`yMGUgrmz&4yyN$0j{)%({n1v ziQZ~~AzF0V(W8762ClW&ogTWD$|x{jQaR2^FP9+Uqt_NFcSSjFPtbSL%huBhl#6lG zMgK~@nEl`iV6O9ky9JoLY;n@Q*S}8zz>>%*=sPp9KQwT&jM$bL#9ji zcuQdL$Sym3BthVxz@0Y4({&nWAUU1_X8+SU&Pk3i}F?eK`9lcioxevJO zKFzUayGeSazrfk)>7i+*1c5tuGsimFgY@@vf#KZQ%liVzya?Q#=Wu$v0c!*Nu`T~w~YTwVoivm`qNdH6etb2>7sw_=#jiDfcg06IZn67CiDCy`B6k*@W?LT9L!%1nQ_$4i2^q) zu;d2}XQ4;9OFh#2CUDHQ42-+7?-Uyt;5x)k+3Zn~W8 zLG6`e1%?6fkCQ!Wfon}eZ(qb8@JR1G;69&*9@*m-kM!;U?twJ)s9t&5BfU3)`)?Y0 zB<}%VEKn+O)1~X#raV{y%*j@qr92@1&ID%EinF12BQQU(;wtwuRa9KMuDT$QGcZ1 zD4i_=gGYAR;mGgL1@3Zzb(7=U!2D3)+~jx;nBSS`rSeB|yamj^10jnL=2F

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& z2sd52UTkm+foT^wogUA>EH3>+?am=!zA11-6?(Dl2iyqElLDuwYiTzvLHw5m29NAw zdbZ(j|GUvXz)hD<&w``;wj7vKtT;=$q?fqB5Iwr=?7I)bKj#5Q_PEXtXDR>4Pk#*D z%L1$G&r)BK9IpfOff<)l{v89{EnyG{aN@s0r9^H%nJhN z#@`=-`L`LD!e15WO}_`_Gj6*0IJMR;HuIMR=5m2^;_qnC_%<-V6gW5jUIykJGcJWc zsy{veX6C(|KS3`AM|Rr_m?Z+I^JlRe;hKRtUEnPFNN=xEJLh6xekgEma@-Hhb7ou$ zf5(H~OTZksoy$SvR8D@d2AJ~&&P|T50CSJP>2lb}`vPI^cL6Xf1kNqp7%-O#oLLT*1p9~j@iz#J7ApN-3sDrp-Qp2sfKr<%a74=9)A(O7{+6-tvIk`C-h9<917z{B$KSqiJx9f%_&f zzf6N8dana>@K4;+tplzSn2jEAqrg0!2Im94KLB&sBkt)EZV@mW?QxxW&92Yl-%)`P zK?>Vvtfy~%Vj)S%uT$|M!9I`jG_^3=%&WAt^w@fTs3}z69O`KHch&}%9vT@Oj3u$h zU^tPCM+euPP=2TjW&_(&)D{zN?x+oS2ii}lSW<3BBOK}swEH_-+rxE%ny!X$Q=mK0 zWJ{@icrb|#Oq-%>;*t2s3C(rkx{<-iK(wbFTbg3;I51cjsP}g@bvA`+mL58g*w8Z+ zPuj2@u5IrOcXZZ;TEn4^*6_+uT_D`i7N`x?hXU;#l=de=EwxQub%CYfu+JB6>*?zl z83| zw?X^6YeUbv4bg!!VtrkkqHES8+WM}Zh5-K~24c|-u?=VRZRlFRDbdZ;6=HFtDF0*kn;vmx@L8qnpmHV4Xs`mP4*41fq{qDu3eqzi}bd2RE6W}M(n<)vcHECRjaWBof;pE z^e0yL#7Bk@ZD{qTg;o5Ieh?GNUmYJ@H!rs4G-auBd`ZEnXzwd~D2FStE%-uG{5D5> z;;}?*ZL)N3`;nz|Xx>2d47gTlZERpD+ON|1J@Ne)+#geBmCT^!0PIR6dzUT^*GJZ? z;YfdftVcOa*}3FP2T{ST?Y6jdX-%jh9B8Qv`CG!R?R9~6WnX}HrXpNvY3&S$n%kNJ z&4HHAK%KImc!QDLmTrGjs4nbpZ|I_z%3k8tG^N(xLhinJla0p}? z+C!ZuhHHa?+Qu+t9?(5dpr-3|8M?l;9hpkmQ@kxwT04V*_HdxRy|o?Ok<1OaOYr{R z<#v3PM$8a675Z(~!Kb|`^|2q-IhOTNj zIWnXsyzsY-B~~+%R1=CSWW;himQAvn0y5irF31_?WOA>{8ksib9u z)Y72rjW4aP$K9l@}_Gh7pB2(>Vurtld`TUTeeJkPHFuo(P}mN1WT0FqsY7+BhYEa>m-Y7dyxrk5#cQ=m0%DsOIJ zl-m3q9brbUsYBUc1W!{~@JfHEGu&FUJW$)o*`+9j{2l7c_7gjUq>bf>Wt(Y-2NTG4 zYHw*zUnFkyQ|IiduyW}~C>E%Ec=d2g`9KVQ7lFl_Kj7EFvg{~D!Sh?1`(>9bFq&$^ z?JW&UmkucD5T`T5%`P+|X%TEXn99~N+{IwmPun>bbnDO0?7YJ8+{onp{C?OW4_I3* z^88gB8%#!`gK9iH6pw8h@utlLXqKQp(=ur%&MS*X`oleuEVZ)UzZ+E zsdq#M&`LvL6OIh_V%OY(Ar!T1`c+i^xl6Prn(T=U(I&lvXdn*v@Dv9oAjL?6d^th_ zZpun>OoYV!u-UZF?(3Vu={b&ss z>aiLYsP=ZoBZG;xvG@RM3oKI(MfA^_qidv>E?pVvUynB70l-{o!ZbzB7-<_$qS>K* z94~+1@Ul798(kY^eo_V)wV9*{Vzch0OWCo2y@TLaISMFhM%kdytm%ynvaXn^APf)eN1C2EwN;MY zzI8|)Y-?z%Q+r~)Y9Jn04gzgzLE1<_aw>E2{${lFUhlecSapg`?yK|$6X=^s|x zBGGt)aa%Uu$gRy@?rhWWr65`21-W#oE+Q0+9#OBd3~`s4;tr@}=I~I`*w}SQdYQ5h z;;W|kyh+UR#+jxUwuGJX2D$ddrs$k5JilWo(xV2|{vqUm0|EP<31(=PE1$sIubAHQ zXD2!nPjHRHbgpTx#k_F3zf-~!Xp$Rjiq}y+e8&1X}(PV=6JTjw*e0w}-ey!R{ z(@@Gg`U-k$%E^e`u5pB3(Avmwe^Toh#^PgV4aC9RejwjF2fH3nc^2Lfi}r?xVo{vP z5LY_!s#8l@mwLPj9s{a}rdr3oiKuh~U8|w9*9S!ZWJbvzs9sRhq1IIgdw3rbZQ~gw z4o4&;5OXRgMl{ctYT;E86|fSyg4$2 zf>F5!f4ArY(Ev^yRVb1fLeV`I2je~N?5XCM3f{a3Ap6SVj5R=pBG6P)l+qs~K}?v| zp$NL@;x*Nn{ifIa1=Vp{$sHOT8cr%zKwjttiIFPm+42SymGWP5h{fn~7&SMpHo+K; zwn%R;2GIE7y2w+k%%G04l-L$0STIFbjz$`{nc{XN<7#BU+-MVep;p;LCU7v4=o2rg zhJQZgB|kU|Ed&&90!VEk>ZMC|iApMP>C*cC$hw454gCM}gioOp!2n|~Yka+LBH$lR z_Q4yX;7jcd4EE3%rsRWwFHKfEYXieS_ zBK3HWWKWS>lpOI96RCEU*P$rnD0k6FiDXW`L>^H4A{(NBEe7m56RdVPk&F$nbo<-l zv7yL1=C%f1cSHx*FH;sF=I3o<){}MIB2u&M4O7I{;UtO?#Mv~$8g;ZtQu58hMXsS< z(@fLb4mNyf#2g09-X;vJE!;b%`4xc!3pbsxpC$-4s#-t4kV95Z0Su@5r^o zsqa?B;_Nl)VZ`(rg$@;IsH0TYKfKoT)|58GP(`-gglQS>@8|KUZT^bsT}Ny<-lHlN zc=4?11uJaZ)zhf)HMq`TXf0Fu5arWYa3XDzF3QrS1_TNpQpHYK8Yw9VSvgM&@%mpT zo;b7GVP6KG3_4oI$R21S+s$UuePZETycw9BED0o9SFEy$>MVSA@zbDN|;X zwAw)HEj>esShg9$E5+SGk@`?!fBz8Gd&u8PE5f1(lTKta@}gTsqH662vX-%;{yfhF z(Pdnw%m)uwd5*Fs7VBTedU)aS6tft1XjerkOcSL;vHob!h_Wkqp;Z8J_hv$4kbPc8^~@^Tx%uzVpKOKJn5Afjb^nl$#jtKdW2Me`j{-zyYOyYq;~( z(+_^O{^ZYHd`(%;*{#3--S+>j{3*WnM#80q=RDW;+WYap{j+%El>#KmXXR?;Uc%le?dkY&>U1 z=QJ#Ec%9+4T>s<=7ye@J$FKY67gkK$pThCiPC*nj#S{{iNrnz00{ zwD8R3Nze4Ui$pG2QK^HvHPC=r@|}W zS@XmnJ0CmekDsktc=>k+A3po5S1!S-e1g{v`g*Pg-<0eyKLb6egAmO3Els^{+4UIKX~EL z*G3fOUkvxjf=JoZ_k81y=96xibM(?nW^X#_m_*TM{?Jme_DAh^e(S5B#AyPsacSZE z$&pKTIqDzYuY0J$&8*bQZ;m(0?eEr3D5A6MaBrn4qf5)qT`N~dvK6mEH z=hdE{{B+4PFRefL-RFP$-}BepwBY`?iaW7_4NEOc3;kEAKfCRNr!E-&KGdS|9)8DVKff2VZ=D!RxB}*Y7;{-F=3KZZCUu&M%%+ zF=vY6zO=BQ;oXBCJnP(*yPeYdyDJa++_7)|?cIYn&-m?+2M>9tb!BOH2X-A}xKC|; zr|;^}ACnu8{q5hbIicx*cW*2Fzs)y2a_Hr+za9VPiJ$ruzA|UHf9!L@1Ao8uS1-l> z^S}QV?)vcZ3+A4MIjxZ$6kac9%YcdqqqPu_9E=@0zq>?a;P|Kj$W ze))X(sb5FB`+bV?SBAUtz6Hl_d2GM$ygdIK$}PKn?#L|_=k4Da`s*__e;B&qgl)V0 z9J{vBl0{tK$8Tw&?;jns=o8zyKUEV73E}x+f=^z>E4pN zfBWPYw*N?Z{QcV=E!=kRYjeMI@$+@HdmOU*?Hlp+FvFd3=m{%s82!tVKi=@;XO4RH zv)}sf^W6t+c_q@dYuT)Z_kKLB7t`;w+O2T<_x;bz{LALw&%eHQ#+fU-&-q~F?k^m* zcG?f85C8YlUrpctk0@Um?ztnM{_Ek7R-D~)`l2@%b*D!p=zH#7IF$_VXJGvEXz~0jEES(8o@?-YtayF_a#e}v z+o7{|@%-xU_+nK&Kab~C;`u(rJyAUW9M7x8^HVc%;)r;@6Fh{)^Y`!^5zkvt#wEq` zL%X({ ze~xF;Llfx#!tng6z`T!lZ;9~DkntVyd@Xo;S3JLsxbJD<;H`LXPBQ`gO!53zgdZlJ z1F+RR@q8rWhVV>$ei@in@%#*U?hwy#Eu~vLUx?@HQO3W4_qU=vyFonv7|%Ci>+okF z`@wj3lX(6Be^(-pQ#jG763Av7FrMp=!b@C7;N3Uy84{)SDs+CGc>W>67cYVA zz@7?R4W2InhU{1?p6BAZK|BZW9Ktj4_9%FJ3%?ITe+m{VVjN>#JTg#t2@!4ORT0vma8kO=2b49S6Nw6 zS-v_dlI+K_#bhFf32f+z^OdfwzZ)G~8_TIYGC6fqkIF_rbDG{J^vtm2HHQk^lwe~> zltT6vy$<#C&FdK&$}Z7?XrjkP*%>>14?5s*{xDSAgGD(BPBVMLuZ<2RDyqt}O*SzQ zi6_w~woyU$^6LgRn3Upf8S5B}R{CzlP@ba;hA?q|TvsXtk0UX3DNp(w72RFG(Z)>oBhy8OXM;+kWey zX8=?R+1E{$Nzy8ab*d<1v*+h)*~0&<*EE=VAI@$2O}2Li)s5M97iuN+p&9!oZZxy; z1#wf!3bb>dz%#mA%1nG0!=H*3I;HK)XzR~Z==^hfDpoE+dz_lVGnH-PsaW|Ip3p_X zeT#T1X5#_qjv?%)2&1QB`wNO1HY!O=elD*qY$$xmoS_w0kuWwC=F{3NirYVq*9!O`V& zf}`#G21oA?9(`Z%xc4?L3|_RltSz{0`jX&9^?3JiaO=NkZzv3o76rE*IHPIwC&AIj zL!&=^jp)=}San=*6!6#g4peSuNe4%N8616zy$z1O5ga|MtZ(+p?Xyb)O4CKdAomb{ z_MJVah(c!1X_+&-q#2?8WviMl+At^hllpyUGr9|dqsg*UgIgc;`A>NufuMQN=5*!r zczOdpkm>l3+v9BXP1Y$5CHPanUc?i+d&)hyZ=(lxZDynWF|4nnA;_c0F!qiGGs{YD zM5hrS-!`dhlla?T(g=3=-^)K*Atf#c-~cZO|A>Q7LI-m)RQTKxOwiK1PiHL*)yYa)8a={I z`XnD&ftyTDdL*wPzKMDQH<@|^ZenK>Zc+!0z&wfj8Qf&--{F1<_aAV-f}1Q&_B;gl zCvfksl$5MOy5#Jw1>D*9K-j4WBL_zqckpRSYl-p?gtp<MGn;u4G0S}{ZB026>J&b7b zu>19}LX;sqY-jOQtSr;RYV@$P^{}ma*cVaG@VJ+Yr(%Ul${8zB)Ru=vw+BamUHL)i zC-?DUb~6%HLLb~$v-tSp;dh%*x{f|l`7A3IS#ekxyy#36*k__BRA!eH&YlxQN!W;x zO(+C?tPu2FxHvfa02Qx3l!N8r2j+w1*PsMh_{G4UweX7pMO8#E?l=aA_?4x?PZVx8 zg3qQ&$RDIzHOqO?KVYn-bXqjipsSB5&(EHfTeGI|8#4D^rwwk@0F{6s| zuH8`F8H)f>-0fDUWwR0kQC8Z`Tw*Lf$^Vi3=IaX!DF;tC!dW?2xJ09*{Teei4akA_ zop+zL_ikG0^?igHF`ob- zIH$}WL^>j4GviWbrz|ZB083^!@=X3lnH{-;eUybC8U)|GJATi>FZtnC{8DEAuAZ6c ziDzaWMwyw1QD)|0l$m)LWo90BzaDlje4mG1D4uwREbZ!EiLZIP{N4VQ!7YEi1QCLx z7}Ug1<%7YC&Mn)F$I<&Q>MSd38vS$dqNcKP|L7z4{ds>p9pj&U=NkvtT~t>#_q=C^ zPY7;23 zx-uUcUrlJ3wfXO*mQ53yXRGQiOqTilccGkBLU-aHx;BS?L?s8Vvn!wVzx&4MU$*|c zI8o%^R=fY}yN=%X?lW6oD&6{sf9q?-zG<&DANS_$b3X|c2Dc%F(AE!T&%Ug#td!bJ zzToVJhl7xyTrhBI^R~4GcTw8GZD*C8+H~9>Hf#uuz7X8{`0UVezuvG*X!O^iZ8b-{ zerRy(`+J9G*Zd~9t+61uZG&x)7MubhP{D7Kx<|f~T#|F2x7Br)AIrGr)$oi_eCgUh}-uGjM6JF!h5D;^*y$|m`+b8;pr<-{&ZykPe;M~rYk-8 z`z#hllg0dr_T%~ld;51heTu!EkH0swrv^OH31rjRbTFL*B+KKaWfXyGL1;#DJiz4NrgL9!1r@oUAjQ$TWE z!GX%Qf@0;0f)S;B+RjSjv;vepgu`Z84A@yPPuaDATG8~0`wRuk&#BS1yHZ>7RYB@K zMsz0@_BDjTOOF0JUO!Y%iLi#@A~cA8amg0W8_x+8mTdCM3os$PU@ zBo8ojP>Fn=d!K2EE zz!b369OQ)iGmPeX-X-5U~+M$ji|Q8(gKXnfX21HPK(k7Eo^ zgRlEbs3&$1`}=5YiZKJqDQ4QH&KI8CxZP+D9S%yAV!}B)Wp+NaPgF zh;kTeGTMkPQ7UNS#4WFMB4az5lYw_u9 z5}(8ROWKhb#=UTTso+}}K=~;gm_vRI@|yQLmJVChUuLE8G%7aZy}Y z0Y@&HHH|y&EprVxn#?EJS@)uF7mQCFN!@}OMZ1F8r?kxSd1RJ7rAx78sB(mYiW#bm zup|N1(4SJAH*Hp5$0F~qN7RZC^2AfAN|Hqy8DJBG&vZ3_(eku71wzf(64vB-66K}l zW46c(?T}gwtN+j<3zQRE=FU87=AlKq&6=?bd8a7cnj;B(zQ&4Q%IL>3-tpZVs!olb zkpo%`16~i@{HD=SXsHTP*!(75?Xwe6_i?p|u^P&wWQBi{u9OF{%yOD?DjGSLA)VdP z1S&_UR&~!)N?}XsDPk;Vm(5sPCvzP=8&T9FgR2&wgB3k8uBaC+p`u!Jxl?f)dyrK58i$RjRM~=?>fT#%8;6gmk?{g<>o5{k$8Y1Nh67a{RGR$@H~9jU zVpIds@Di0R$Kqaydl7CQZYmHc>r)=>!cBRwSXo-K88WvbKhIHi62qi(%9>g#7gfN9 zB_+SY+hK;_P1_QLy`+b+rYUu0eF&l^WovV@q11J^A6!v@&IBYrlY>Y+1m#L}gw zR^XprjDeT&K^wlEl-|}3l(ax(pH6pY=9v1Q=7)237plV-X4vEl5&2*pJryf4JuD%f zij}kVu&sL7rFs}O(Rti!^spQBu>19}hxM>$^|0skuz%}e|I@>$rsn(|A)bnrMS2)D zOL)38p3iZudKfh#co_BbI4+@wZPddq(8EUcu&?T2-_*nI(8KQ1!~Ud)(K2G5#=Cmh z`+8WkP~&AlJQXV=df2D*ux)zS=k>6!>tVFSm#0CC@3?GF>0!_7VK3@ohobMxafgei zVr9M_woniIgC6!LJ?t$#>|H%)bzG%nV|Zq>tX*TbID!=BZ{PC~DN$2~tV-WqD^{@?kSm{hG9!2>yQz;Wq#mXR_cw8E}pr>NxLOtxWde~wVTnDhY$BU<8 zJ)V9<^bvJ{E;ZPK@r9U}OkGQ7>UADu@xH z2j@N@#&%vK8c$H^$p>Yq(%;O;EyNQafPqi4xm{{9uD1-kP?byX>6fY`e(~XSe7?bU zM^VEA*cSz#dEm2p{*fEo5KrwDALCfQ=+G8mEMwhA(YWQ^N8W4EQdx>h@8fBjn4}(@ zs?HfTB4aab62gUqO}sWzo`{WEtk10 za>_r!68J)238=G{%WP9Ej?bg1b|#yU8ZfJ*^`e)QU=1p}WbMqV=ROfkKV*|Danp3i zYTR^P2=kJ?K7(J<%_x3%#V@Mj%_ROM_{DNqnn~VF@_qroN8PP(|YDWR@kULZPQ(bZRsl zc_dGlhPrv&+w?GBM>j^gX|8{6)9C4Qf_Jg;V~ikU-l%!>`CuDzmbFT1vNE$m8BL39=C%32m(>!L1VcX#FgJm)?4y>})v zNwDnqeZT)+n4I@M_w@3f_q?Z-L@PT|F&&N!e`#3()ZLtSdf_812q+o;;j%-<)ukR1 ziT))re0wB&)N7Ht(SgX}sF_anut;45+TpF)YraMrceRW>0)tO&WaY+#KO}{=nY{{m z3FWh=D&EzWO}2&CgumHkbi`FT6YCBe%GCgisTy8;V#i4I`QnxT&OUWoB-$kseaU!P z5`D5b`f_pfdGl6WcT}M0snkQEf){l$+>8eYfXcY{4#ZW|#RzK$)-4zpyAHIhArgHx zfrsMR+7Zw|mmnrHxr70^g}kEzIZWOHCI5^QkKb$@TRrg&NTM*9%}VV7CHh~CUM)2M zlxTtrKnWuntzTJ8;(}kUz%SKVgTJwC>TvMlt#NFM@&?$fLzDC7@(7#ykvk6kd)O+< z=2b6RRyJ$-VTUa!UpQ+{dD)P`6+`+Do>eiRe9+*5v&-`a4;?al*wA4^@`lVEG-T+Y zyb*o4*)VLj6oz|wC*75mK{Y*O&~p+2UKJRLCGa6I#lv!q0^x`%qdl0eHZBPK8lG)|O87bF zK4+EH9!!V%oC!b2sB&k5rs{~JOI&wWR)n*G%koB;sItW5>1sl!Dygdh76eWRq!@SI z@viQ$YnQR4i2b^;cPUQM$pALC73IyI;+b(lHS%ImKDAZM8VG6^vW@*S11AU4pi)b$ zdUMCY%Z=SufeuhpPehuJa(=IBxK8HVg1}7V$7<(ogGZ1L*Bkr}*zS!{NU<#*7f*xQ zPL^13g+%$XGAzC_$vXy7qd1OXDvyLU&ZsTV2hMc?z9gw8&dnAMt{i7t;AZUOqcUfr z&z&zgW`(POq7LCx<7}V_o=U-fCa6-d(*sfJ-ss%wwU$Dy)h;zOq60KKUpA=O+Gac! zZT$pzELG!LC|W#Etv0LOa_gc0o7HFOw|W{aCX!YDY7u-rTqn%XRAN80#RS1MMz$SLhAO z85AUbZ5(&dS|nMv9JPCtgTt#6$sbf&8+T=t&+SdVr-2H9FLZF4%*oov`XP)ZdI#+{+Nf~dbNUj8S0%* z_NT&M=j=>M>Wb9RAZ)vRD!tYd+ zlVno%f#S!MEhj{T6Qm<)Ub4)DNHAqZ`}EE!nX&{cn4S_!Z_!|dV{Pqhe3$v0aoYHE zp!Ls)k)O+X@bUagyL69iqnmNr!o-V-aXFMfXG!}fZjNR4XQb4Aii*-Q6MxcL`>Uwc z$F~&SVS+E2wV%4)`wPu_yJ94!_TXpB1TI^yz_f9!4$_8}xniX2r(0y4%!!xG!=|?J z50{sn2+5pd8oy4FxPQ{CYqx8KaJmjf8qWwg^|3mq>pXEA0>KkM2U2m9WE~ z6fhnBet@PU4t4+#+o9*+<4k;H2aeGJI`H;D<^y48JSpIH#>ClKvhpd8&X$TkDN}U9 za3hL7GnCj4tL{U&X)9hj;P-?DZ))w-Ql`2UCi~gjVD^J~7tF(8-UE}Z_imVz?fX)g zzr{N_-UBdSg!wy|?CT$bxeMm+VSWnpVVInFd;}(&2j5%R_aQJJ!#ktS?;~NZhj|># zjWBCqZi0CZ%-dnEhRJX_WZ4Z`hAgCl4hJBDeP*ek^KZpa=grrk)5}s>rtcKD6urc4 zsoGnh*kZ-5RP0*CZddGX#kMQpD#i_*jA_v6lH&SzprwLNKg9+pwoI`z6gy9` zsA4-6dsnfA7~4v|oMNeUGB&UT-pEpgu1E#*GQc< zzHa|P5e~h}eM9d^6iciyG%t?Iuyy0$~% zyE|@=*fBXW(my6Qd5JMOmfppU$$yQs%9#8Kr8plTBkY#QLZP?>K`6>&GCH3MsusUg zXNGU`Dt4Uy6>83oxN-Wuu*E)wX2~!R=J^kd)8`H>A2OtT))0=+ z^M>Z<&mGu*aNfW*#yZ!)xX%)q@nFdcv=8Mt%ADg*aR0<{=S*BkJgfqTP) z^q6o4$UvWibaucT-OTX~^z#hHKLHch(?Iz~#YqPGHwHF4FPgL-jkJpLAp4H!;nBnoDwhzd3iKc63j;q{Hf5Q@|{9HC2Dye3yHdK zvOzz^X-XJa(=1e_Rz>}XQOppG;_%|K-OB~uc#hmxQp7D{z$P)YEN@z_%m zNHyG$NJ-EhN&@4dU-q|30{xayNf1G7uQ357R}wTgN`k(kBnTQM!JCPc1m|Lip-O`G zekH*kcl^-!`j#~&GKWA(&?&%D@K>A$$81c=ZN{;uB#IQn4R_HC36uy>NH*n}a>jnlI-#y)cM5!sd0jlV^gw$nBF2D6x z3)23E%=1sE8~Dx);&XER)zS{tLo3?TRe~=$E3lL~;g`(X@7z!mgtlV32`xKOXjv;T z9!ltE&I*i~5`M{Cf#YIi*^}EW8doM92W0|u0`-&$tZY9|St50B4ryhZQC-n%NaHAf99UAop2f}~q2{?y9y#Zsy_vtXHH(;Miy#Xf_sW-S8 zCiMn)!gTcp*pq1W2Bd-xWo5yzP~TAKvn`e7v{r1mV$@QI+Y=NkSB#Ri__so_I~2P| zu}2j9gJSO~_K{-P#%ld*XQ`lbh+>q~B`!xP#&rvVRVubnu}c)YOtCu@yGOAn6?Xv1=5&L9x3O`>kSM zDE5tFsn7yQxn)`^=$xQfxnh4;>{G?QSB!`DN#1jnkNC$`K7w(Tk6>KoBiM==v}t59dMoZ~GOboPLfxNtN{D(Hl;-oeJ%Qg$mU4*${bKo;&<>Yjo2g8vN7jz+$jSMWN}{84 zBCEfunF6&!$?z@JUChpZnJ~B8QvL4j-c}jWZ^4usPAFh!0A+*O!s@q+c+><3zNq>N z6ARaxiOm=|{1ojx)oj$3G51Pfha&x{&RS69AgRt}pvc)$F=yg_MTIk?kZWLfQ{3pA zTG?#;Hskk6Py8{DZx7W^bsrM0p!%t9R^sH+1N}KnH0pAW-8j(7HBrAA9buL;8Naje zqnyG4mpr*xCOV>3Pb_u`IPOF#6&&((GYiE_@ZQY;H{iCFbexZ!j+wu7&MUW5U6k&*52i*zA*wp+;&NmwO$so-C=#59H$LS#Ts}Ok6_>d3Q4xU>!eRr-AJ)z7sI$}#&9QiU ztOf21dViROF!|0|#f~tKgV_n@LYVwsYu~T3?{~xO4E#Qr`@v*x&>m+9_8`|}hJaKM zyAxcD^Am!l;EUMHuvE}YmI-!{V*Sf(7ys^6>_NrMCVlUG6vG||Zph}DB!P(GjXPj~C;mOM^7M}8q?2BeXmw8H zaa~O{{Oj!VHXvibRn5-)$ja}tmqBrQN=|kTPBCc}_z0`b!0Dcgtb7_u-RDp3lSDHs zYZV9k*DCJHf0Q$Dk?6OP;oGpj>N{?Xb+_NPc9%Pj-}RWQEQK03?L)Y5O6rb40&p

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 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%0DkhTyxlIjYo)ZNM6@b1!v|k4r|z)?m_?h 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,|k!G8J+p z)df`XGg!FJrl?}JQ!nI5s*9*n&j1TV=CkjhD&$DnNJkZ)0ZMl_KdGoDG8J+puS=qZ zdzr<9?k+Sg+Reb+~yFL`vl>O8TIg-~S zRH=`!ipu!_RUt=GJw_GZzpmDL@1&^m9Hc7bNUA5O;ztL#+u2g|>kv~RN9xy8sb77M zzkQ{sUNaSPB(GOi`6SL|cd)$?Lh~RXy=(HbvEpsgNUiy+9Q|!j7uA zq_d(5W-8=JUN0rD-ko~XQ&h8<3OSP3E731f(ZSeA5ji}_RLGIMUQ1r^ObkWkahPTU zIg-~KRPj9p<|sw=lBtj*sotV0Cke{uC`A>2gnA)IQoTbJA5m~`s-miNl&X*;sotZC zUs>vWEo_UC$i`NtLXMP;52)gM%9t6`mMW@T$EX)_B(IOC;@N#i4gAG@pTvAV7Yc#C-7H{J(cpsu(4zgJaV-8Iv5CIR$s|9(mLRDa)luU_5N)zuq2 za=tQHR|yuwD6H?KF0$t42TmPfuznCMhEZ7GGuAjTNY`ao-E+@y>5Z9>lO&8+2%~u8 z2gcI9ap4&+es8dD6D)>Nbp6O!W^Wj*z1MSH45P4qVl2HDz4qK^HyErHg2gZj>u1Iq z&V_2{etOVx2J1(`Vi<+>3uBpU(MzN^TA$#;7)J5N7RJ)Oam?+X&oWqF3KqjCx~P&# zVm(5=mtwG%JShw(jKWG_EIrS!JUA!8U?n}pSq!7F5*bUcMX8T{zKqvdg2gaOypkA8 zkJp}yUoo-ve46WG7)940#v&imvGkVRChRVCT`5=$qv#r}=(?;ff4ITA>=`bLVH90M zq%K@&%fFmvH&_=v%UKMg=o+f%dLnaUkHI?sInH7jMb|LK(raw*y}RCGu+Dj&vlvFv zwS%JT>Z8V8Zm`aLfwLG!(Ur_tx({jIW>@LM(_iE)hEa44S9E#S<&+q#<6hz{hEa5l zP;^mx?JRY5yv$h)qv#r`=%Vy8SYHbk!zjAwi-N|xFqB>f>)2PgE{0Kbr6{^4PHO(v zU?slFSq!7-qVKmRC79F8V4WdY45R28t?2sx;tMkj)=sZ+T@0h>+KI9D;J3AJAMb4+ zEq(Ym!D1Li*UpNr>pQ-~hsvl|MaO=x^E1OJx^`hKz5UwlzAGLbCRx`C7Q-mIc2#uk z^u*4C4c4cE#W0Gl-5ASUV;ijWH@Jliqp)_Dx==A{4=x<`w!vB~SPY}E_Fyck=jnL( z;J5ELSPu#o!ziph8B6zk{mRoi50Ty&{w9~jFp4+!k{04Zdola{mkrhm!D1Li*BHj4 zQc0|7W6r$aU=4YT>tYy1*H}f@xu-txw!vC1SPY}++MBWT+&lHnTbu@K&<3uHVH92a zD7xO+=bR#gb&6myjG}8_sf*;!9DMNAPSMc09hm5STA(Dqq%L94;~S+E#J(RGlb>xTJH9$>JZ{ebIY7)95? zjHR~@TVCJ0`aqdp*M7)Z45R28r|7ykp|jawP5p?o7)H@Gp0V_v!wz2z-)CQ`YrSAG zjG~Laifg=GmDzsbzYNw9A9Gy{qv$$B#tRo(W=Y{Y2I~dEVi-l&1Vz^#i!M3QU>)@d z*Tpc3u0t71&l_)^x^|esdRwpqf4NVYG=}W7prq7>nvCT!@3l zI&^#n7I~L2i3*Fp)18#C6GNd7e)v$d`&6IOG3Zl%CXC9;U@U80hk!-82&1wx!?5xN zi!drHi?Md)rfC1zar|zEh0Vf3!hprzg-KgN&}_!i+b>Sm<8_W;5k_TAk}Ota4m(s?O20T?C6TT+Y;xa;7sm)_JuJ zEXu2dQMJzq!&)X-gi%>}VOZA)7GYGDEez`s!6J;xvWH>)AXtP^S^12`eTJ2|w>*SC zs{U)t7tGZfVN_Ou)J2G{hJX4DR=QvjMr9Q;)(9?C`|##+6c=4rlVA}>Wfd_Nl?yt~ z&Y`a&>a5cQi!flB%6lJ=1YJjN{H)T@wOOzT1D2`0mok)=&f^ZN<)m0{SQEb{v8jB6qJi#K2s%s`=9R>#J`nfrOwZVE`un42-nx*I} zS@gKx=hyU~? zb5>rSqb9x7mP_IYqv|?}v2^KQXvKreG09Wi5~_-3NxQ?*)r6DyyBbbZ@A&=q~@`P9=;QuMWmSw}a)wRWB@RGjvTB zEW)U|IvGokms%?81&c5$%fndKrP3oRQNHx`h|y zf3dH@x?Qjcqq4k=MLrzF9ftpU8oVJ`gi%>O$s(-htw$OS*5GfsAi}6Dzry-vRibH} zk|S7z0n3yRyBSMQuly~GO?}!qf<+ir*CNK!y`iSpBEcez%391=*6DSQU=c=TEnzI{ ze0YOk5k_V8NER*vYMUnni!dtdSjN)hrIxQx1dA{#>p02M)0PnY82lYS6Gmkn&sciA z)OsUTun42FPLM2I1jMUQun42FPGl@SUTQ7cDp-V3Stl`;buD_jU=c=T^)i+oFSQoE zUa$zGvX)8~E&}59oL~_~Wu44e*75pAun42FPGKzTc58B34X4?E6WMhJe`1&c5$>rBQX z3kM0T!SV?fVN}+iB#Shtb??=JMHrQJmSo`~AYK~;i!flBddp`sRw)?NXZ!NPMAO(| z?2ib-K^RrnIgDlPjk$tF7?pJ{V_AFSe8D1&$~sT7g1zyiU=c=Vahw0lSbN|HF2teF zrjGuJk5dSvvd(9$RN#&D(plw#MHrQJ0b}W_2+BA1z%hE>SOgXwgi%=+GS-3owzlr3 zE7usTzX}#%z%tE~{DrZ`f~9LPuAUMs!lcj!6J;R>u-!jsZ18CrE-~I5e6*N$oFE#N(Cd>^CN!Y=|vcobx9ajo?sD1weV8L zvi9LZu;?I+%DRlP^xUh?HT_+%2&1wtm#koKd?Z+eQRB6Wu}(*k%;4tWzn%}fws3C{ zMrEyLtW;oweYi@n2&1yDV60Wpl^vw(DZwI)%DOU)uKx)ZVN}*tj5Si|aXs_j_Xxp{ zv8)Edw<3aAS2I?Mz-4}!ywG4x6D-20x~^fYT?OkP-_;(2HD9m@qq44LtTBRB@zKNY z8m!Xyp#fMX_1+uvZ_C0K+}S=TexDxqsja#4Z7dR4F(Mky&bFxK9JwflGb zeQmG~NuXLBZ;b`%x{m)X}g|ju!aj3VN}*_jCGJ;{qkDk#RjWDun42FZf7iNE9uBR@Sz@qb*x|! zMrZN4uYWTZ)rYtU=xPy$4ea(tr0B3 zsH}S!i`p+-h(pi4KL{3KRMx$WrN>Jh6J-zPJ|v9Fx=*rj5fHD%f<+jxOsTwvv20+F z+?#%>LS>*^c%xtuM%A^Jv2<^!Bj2|Li!dtde#z1`7`k>I!sA64mGuB)>E2LBzD0sX z7?t&)WZ@#f8@+->7_dyRQKGdb~a=TK7kTwMwuE zqp}`ntZWF^`#}clPQfCK%39A@dc5-f^ux0T>uJFvjLLdKVLd(kLDTcWO@c)juuQ4^ zBx4-{3&|T7K6CZyhORw^anBP*)%6r(>E2Llwkd)|7?t%jV_Da1vjvMVD(e}>(!HVf z%zc7I7?t&`WZ@zp&;M1h2m_YM8_zKo^M_;hN!O9gZ z!hqH6YV2-Jt0jND$5>RF^pu>QG#J0knD-gRX2Q$}!h8^f$qT}K$S`##Ikq6oM?rGz zL70yjW}ZpTpMx-;FboQVjMw==n2ka9TpWb?lwmL#D&<@fg!wGUo`xXI=M0l=l5( zLz;kNVpH1!Uk>?1)BeXWH}4w&(HzLRd5&V|0+++t-tK9#`TWf`TUNa($m#cZZ5g(F z4bS{bZAaSYR2SLjIA=h*2g-8R=YS95fAdtFTs0aPYH9D^Hqd07UBfDUMI_+8!( zcc;_u!f$s+7yflFa<;ph9bHbZv%`hkj!uuev&9qXK44y#zuViX16^Kkr$@`{?rd^) zx3>8mt|d*bF2CE;>Els5(q1}8w?f`?G z0uW>wC5|pW>}@XI>vi@xI$et$?XJ#Nf1Ak#ECv}&ge6G2Aup07vonRwAteTx9~tSW zYx8;*J3?EEY%Q}zhjWR;)$ZzWb^0CIC>?WnydB6|C<&~9uu_m;NJ-?FkHNwf3PSdnJsx6qbp<5GgMNI!@>0=b!G*M5*yuREj( zW!CTQZbJ2g@`>{7cle#HsEI^gA*GI4nOVF5_T49xDDF<5%j-v~^wGigBKz!&Oq*jC z8HpNF)Gd^#sOnlgh)@TrI;#FybtuC-QTw4*$SBgQEn9)Nr_1lDuD01^X=0U%HNsT0 zq+20^Qr}Tx1q-YtB4g6acnxm%wsup=G1)D3_Q|b0nL}%l-pPx`6ushhl!TXPu4|%2 zrdN9WWmJgC53c3`@}cZRtEkg$R57QeAyduHNarcC zwJng^W$T$y(C+DUHnzL03JcxC4J!my`mDX-{V{uctHsjP(c6kR>TV6&3IzOSDmzR;>-O}Rnx|-|I>+-dDyr^w3C{Us;y6n~6 z{sxb?IU~mwkwbNoV^&E+c7BiFRpq5PqS3FU0$$*CVR!>swO!68S7cG5*c74X;F!e( zI6Esm&F+?-vd*q4K}?T$)vJd`q~o4k=34U=MlEL7x}Rm!c;OV7t(Z~^+POnX&l zdrxFJ{Zm8p8aWR2rkXhpwr+gAsfLb2OknNTR}m#He}!`iW$miQV_Z%C0#7&kRuMC1 zeNn!>jPe5b2H6)4(QcnZy;p-(;OX=`-JL9NQ)5toQAMra*|dO$6i`v-^Ry$YHi~wRysfKz9;J-8O=O51Z{TIEj87f z@pgQfa&+sBre1g=zD`3wm}2U62vdsNyM1lZ=BYkg;HWHRqd=itl%km1oIcwjdR}O? z^!ln@m=v8WSaaH^Y(X`;-H(<%O6Svq0Gj0@UOn1aG_G3vTP*c$Ea&~ri*-FyV?KV^Qo%(OEr-VAP`E#O?P-ZQm%#eWD z*cxf3qm|7d_t<7nYj<`uHai_TlUz9&lNw!_&g@B9P0sX5lXIG;OrDaHp3{<@GdVkb zhRsF;Xf#KCN)}WVcKp$^2FI*8l*5^bh@LKv4!94_?QtwZcM?;pBHe8DjzU+9v%B5T zpC=#*_4#C0XXt}&_!tj=$iI0Rd15>Br2+=IUtIWo@esXtMvy^nC7bYVfM}##_D%``A(lX z*Rr7lr8M_S91=`JmpIt^&;>a}PA^jwKARmxj4a4?F3d|)?TjIk zS!=%KTpyJT%F`8|MJ^O2PaHD206gW4$sF|&WxUkry;0i#&ae;}r7u)wEUpO6Ot;7j zrZ~&OkQWV*>QDW-fmInd2{y`iMzOmckM%9@r3c+(1|j>+4l!KjkKK7^g$=8NB#>r4 z;^3&DnLkTL7?qi>}pB+BQ#jd$T^9OK%haRaI=`B((pHE(yN_kiY_3k;N#D!^W zbbksUx123z^4UUC+4E1#lM$Pbcra|@W7`m8oqCcRT42CPh#~_AS(0e!2=ubvmom<> zL>mqYH42MBW0qwF4yRdzmzNRJL8c;y>J8mWtd25FiCof3<-?{>bgESXo)BbUOdX+H zfGHF%5NW)~)ou$RozL)FJiV~MQ>M3WG^pNUlXoFlEFF#6HeDTWW%r2@yEnlQ!1cqZ2z631&E?jAl@5=yh9 zl9`FdJQ7ZCEaj9*NvMJ!I87E|Ww(uEmo;X&@%s^7E@~FjL;M zoGvnOmEG;_5@IVe86HrNn(i1i5~c>EBE^U(ZD6oInGmtD;8~(MWZn&krrumw(?T~G z)_9|y4wZB2BN4+k8Wwrn+;IqT+uUD>2+_Lr*R-$2NXvXS37WY&Li=|~v>!|g3{YFK| zGLm)EUSI5WEiA`qtqzMpe_8n}*V^bP=j-qfgfen*Upx^{KZD=tJP%+KuRivfc@Kzjh zf8YB^w(L^7mS+}f^+?QW1prM}vBzQ-BH~yE%zD}+vrnBeyqp^xAq$^MZLv)`Pgwy@e7);|URIS_=aR3uY9vVL_}uP4ovzGv+!&PwrFd=?@x$ z1&Af`(aidWB%7>=_+TvDe04MmENY0DL`FR$9%M`mllMW~{&~GENG!TjVITVh&aqNf zKwT%7BE~E*aAYb3%9V*R3ykLRk1-k$>MTjdtX1qrL^ZezHp7}0ogv{z`_wyAIyf03_90)WmpTKxxzRKG-`aRf zJRcs>(lrae$19ZPTr34{U;S>LUUAiJERUGFeql#879CKoT3>cx5@gZPMA^mTBIE0* zW$IaX`${0}A``y(jjajEj3AB5LLVCQNaEu&w%^L2ZeBb|%wJ(J)ewCV)~CuZ>_D1Z z6;FZY%ziD8Tx5LZF;c$oV@{1EKDL~yON%FC4P0K}R>hMSvPCtqeasH()>t$QvLn)m zN-L81*s_8yZTrd!+^Tr80w4Y44OB-vlK9x1uS?s$oFD%HGG}0$>qz2bb3T{WuMNoL zfsKD8@v+69OY7J8N18wAVD4-=sK>?1UQbPG$P2G4qq{qP)Dq%xL&jPngOY81jj0d=B z;r6;s>tfrAhlNNn5w?z%vLfN6z_1&}N^#*)QdorjW2LxAI4LmfezQ_sc$5?t{id-} zatsuyCffaGrIM%#x{4^bpVbva3zy<)hgy9%SbZe{R(4Byq3#<3;@gYXP!K0yH=uv_ zwAIb(XQ};Ztl0CfKP}Zo_NSTgY{uK4af(a7bO4q|#E;dC zUc-6<44i_dHf#u&mXS7a`z4Dw45$hoi_C$K#ek~Nvs3szqxC!y0VRb+vw5_X85Ovx ztBZem6C0Sz4qU)WN_}f@EUioP;k7bXJ?o8CIJ?jxi;Cs$%4Ec7@iM}Z_raFYjRGpg zM)NSLPt^*!O7D+u6=mjh9Qem&R{3CSXf@}ft)VZb48tA=#+K}Y5@X^CR&Y^_!X<(m zqay`Nx+B{C*<~4snjlqdh3(pLv?+6wAo$txlU%Q`u- zd4dsJx(QM|-WSx^d?-lL6W9Sh)K?DZF*4?K*b;7;^P|N}1?k(t?6Rqj-7c&#XOZo~ zpy2GcU6^Ig+S`ReeaqEiUq4xv;wl=tkiO<2T~7Zby)LbQUXc9~aW&zKyLgirqFgB(OAZV{?p3VjCOMFS%9!npD4JIw?$=<|v6{>1c@VZC@qn zMp>*(>eK70vO(*A!A2SEf7yY>s{b_@C8hsm>xtRdS6^k~^<9vWSbdijm^gixXe378 zWku`!NUsS;?fl4sqIZ5|S+P1lvc%|}A6b^}{NKvAUu4S@e%GB}&9`jmOXpa7l0_r4 z-^SN@L<;?uV#L!Z`!|?82-G&q(O|WX1m4b+UB$XE$Eh+*lyt&Gck`mN} zMr)h7Ifzo1jDLE#oyA#e7=~F#NMTwTeqyJ#4)DQzjs?k4;#`mELwfntkd=++2N&2n{`-WkfsTqh? zMNl&kEz#5rL`%`*Z`$KBY{c}zGzY1=3_(stYE56lwV#tI`R zZ5#c122>tPS!Ns~w}tvvRs>q`H_IrWs^boPHO|$Ymz)~8;SI5l{cp`tJ+;}f5{+{eG6J8{5CTugZ3}zr{wAd1zuT;QdDWKw+5gZ&`1-)1P|* ztB+*+SF)ajF>Hb@({Y52Q8r0L0kiLy*v2*3SB2l1<+QMZPzsb4(mv zQMsqH)#dY7IQ>m+)~fRDW%x`leW6^BNK70#8ygdgPf21LHYS#we~pR7bzveuCYJ6% zy#LvRZ^!Z%wX8j;X1C}GJUTgeQV^q#m?&J!uMA6+<&OT?~p5Nnlg>)8u7Fp)C zXz{uNmXnJ;-JQ)LDta@Xh8ue}rB*PO?d|=e% zg{aVG4@5->j(t=#bIhY6=&@Gj9OC(+d)P^xJ_$5@*MCMDe(FD&x+?>g562t#unV*M zD3sTZ!7HfyD3(_~{VtYU8@z(LU##tSv3fS3j3qxeDyKK`!eM@Xl?~IF@}8Z)$>H%f zxczMf?Jj3$cbCn;Rd%qd1`rmZNsxV4@+sc;6j)~GQ3^uTC*=m;PPKo#! zfVX7LA-l8znSpWu=6C9?Y4JP_vX*2#9*Eljqki9ZP6%vnx1A+M%e3um&@-jdHipPb zMg|D^XeO$hlVyugf5~cVn;2qb(rxb)Ba3W%Ta2t?F43%U1$WSg7r!{8pAD_;(T%_v%x=|C2W}h`F#3tI9B*@*tV`%NH!HApG?&0_Zk%<+u+7bq zc|NVexxi(-4{9^NCv+rjifZ*5O*$>>ruVnhN6vZuBFvP_`bAz)_UIR>rgZHWc}9Yi zb^7Z(wSKR=vo$z1`t-q-Qu7ncytIK!3K8De5+X^osw4T$5)=6 z-sT#Y9Extu*})^jOtGiq+lBT}U9fchiXX|6Sa}SMmikV;Ax@l91JIcp9s8mFG~rg12IYuimW~#>`$^ zm3w%RztR|oP2_l%cd!I23DfeH7|t(=s#V>3R)lZiww@i~Tbr$CNBEk5>)8>$7T$Vx zge@%bZ2!p$OHr7@Qe+esEXt0e3%d2JFr1NBQ)+wx$TaO`)VD|AF*L;zpDYbA$<+rL zrg3XpAH?_qzi!?aVWt6WU&I(bcGP;jen)p_Q=6-4fvcH~ORS$j)fanR3(K)|yspjJ zX~P38{h9ZcO?C0MP;aV&w}pCB&ATnsn=0IGq2843jd=w} ztJkyG(b!{~J+0l@(b(*Cv}8GRa-5Ah&h$x>(dP@JcJ-OcQ@*gDNcdGniD%NtUrG2?MT%$r-&mx0N=5!w!mlu; zeq)j1DHZvP3BSUW`i(`()JRo(x*TmTC;oZbU1*{lc*D}QBwQaYBhwbtt=rbTD1%ux&3EnVeM8jXtTP!`19|b`DraHa*Czid(jw4ZK{l1v!pwXN9>}yX~yt zzF^CUwz)61u@!lFj>)biO|CA#+tbNMYB~8f4Z#IAM|ysNt*EN1&|Y3tZmaKH(CJy+ znK#LR6Kry$v)REOy(w%S?DaZ(9G$Mkj&@gPtG`V_F!{x{S!I<4g+-M!ZIF{U$w`d7 zNucCS5**D@SC)k(D@>22K+RE5XO94Zr8VhcrPy*wPBgf@y!6n<96<}-Y10f$HQ456 zW|NN$&9sh;d%;4T`KGSJ2n#9LNDo$ltAc}WLU2HsmEg(#o-P+!krt25X3h_G+sxw1 zvZ`|XEX0Bqv*b{^(bevv+nACF2F!N0cf0Bkl?u17gY5(mumesoB@%$L zZAM8^Rbg>;NwF<2*C;D^FRyy0y`*4PHG=cf;Tdm_@KD|)uM6&SEpp{eGEpjQ)g>h* zWiv}l1;gj}cwHz4CQLz*t-P{gR%!XHVw-APUKUg!Zh4bBMC|e=wb-b*WFw=;5Or35 zV&&-BItD#z&WwqOTpI)4l%r{{n%s0*2t(&7)wpmt*b@4-Ni{U*7{%Wzr>i=x5zuCJ zBS?>^B|}>#YsoN>yuzYldwqGGqoCAYS&2&DC?8pPzSQXSxtkok;M)r8^XS8iUWec7 zbo;R(39r`x6ALjsUWDn>fBAYf92wyNrq>WZ?GG8@$um7dNLz>5 zhD(DA%We53#g#KF%kpj3A8KZGPaCm4jgpp8l3!x4EUzxKrL(Y_Y?rLwS<@tptH}xo z&t>H^(=s%}Zp%xz+luTq%iG!3-H)2AfN-J0GSpCEd7G=S?0LutF`^~JtT+rHz=o)h zauKhom~wU0)3LgX@%L*FvA zhQ?%vZfKc0x(kGgSq-R=z6NfK@|>) zn`t;IUJ;Y!Q*~tRdLIT`vYn830zW$@vclx3k<`g5x0TuL`Ll|PF^EblC=lJMZqi6i z7wd-=+w#jXYfxRBAIb{qo^(0A$kuE;L~{eu%;+N^d!+Gj^}cExT;vqfOhjA)(7%m? zXX^RVxQUNmCWrq7k@8(HJ;}pU%x@zRgO6C_DN`(kFmjETD-tOlx-Azzj-xo~KCb7V z{uDkA_m!fYd|85Qm{X!+FgZM4_5^ge#U=$-QY~SD!l(#V+VYDE?ImUTWnwQnS2^Z3 z+GP=~wiVATD6v-*%(9hxS~K~EkG0suQX=v(n~`5!RW!4>03!UZCVzcrlc%E#-^}y5 zscWg1_WW{NNf8Z8^KE>%;=~lBn@F73RgThpsLA2>X%gS!rnn`DJVhi`eoH&H&G3cWhnz2Q_ z#+qG9UyO&#iwmk}RaI1=#laZbiFrEm5@jnacEW=t%s=v6h&(CtZb6Byy24&mUR_>b ztD&76>$~ba72WNAHzqBsT8Qn&%w?;~i*fWKNkgeBD6THgw^xvF)=d?hr~>c;E2E;gx=W-ugA=a&JAWpR9*-sMC*iLCXE5H z^|2o{s!?(3b_d-M=7k71tOx}_r6VRUP}&MST|FV^FRbtDhFRYg)`h!im>3R~9lqxy z>lVGI#EM5aj&652jIcg3#E3&=Y=oEucDrh_Wk12l4Hlg^7GVph9#4x~B6=b37_kZo zu{KVLgTqnQ;cR7{3(ev1xthAYZhw!X$>Ukzb|GX*M~5vv;K*oE4{KOU04rUEO%k_* z&MIuOfCZgZSgwEtomJQr0Sh{7hvnp^nvV=D9i5bwl{G~TPR&S9&&kP2O`VjLnaS}- zCpVuuSeyOc!>%PeYg&rNkBQA*^qv>F#82(X1WkKg|Dm6gM`;tAU5(wXX|;OL=@4*3 zqNZi;#6t$*WYb3FPxR8(Ejmimj=|+zfzd;4TD48ctJA~I#KnU_ILK>iTj0YmM?c2l zq8j!qN3y0Nj)xW7%gW1&E6Qps>~#gDQ}=gvc6w-4ym;m`J$?T$m_=}d$7_jkRMZwY zW*5~=&p>)u$Z(X^71h}5s%jjCMfvq5j`E_}Mdg-~YPvi9?haSEyV2|P_DruRbQJb< zIy>A=H7;!1>T^N3c!pM9mOpj>4&S1tF0bE8WkF4yqqeTFtjbYVTjgjdD=c!2RQk*y>x_7P;H%d%QjMix;(ZwYD#)_j_A? zEj`t3tu5W%^=-am7cXcls&+4Gc6(bF>A&k2HMK5scO2_!t6$=7TmagF`lga1{=)-d z?nRzO$F?o1U$Dei)!wtvmYtuOo}OD=I3>3rqp&brjafzQY{VcSx>e=<+S_d%EVeVo#p#MkH`|OUpc8o3pvP zHrwHKEk@Jam$q++A(niJrz| zw5i&((FsRu+SA(3+CiFUsV2`A?k2Ct=V|e$j;k4;T7|VQ9qwcCSS+;wBT#p{%gb&5 z4YwA=-F*aA>OI~n$=;*e+5l2n0l&4NDsw}8EvbwIUs#4xgFx@UJ zlDGE&d+1nVS60xv4sUBsOsT2)bCp5)Bv3a`hl7T+WWFE*Bqc7q>fGecGWw9tPb8(%#&R z;mjge0g}z-wKsz1Z1Puo+TBe(+9<#efHE50vy~;TIJEi&6$xpLu-N!4=6UM?EX-rodG4; z4s%3Rr^X&xm9Lr{KEkcAWpCA%@P3U`m3AZ)eK*@2X?;tKY2BSZcWbAsIh9r?n9P+U zciN{(Y_c5y&Y(ow1)|5HOk=Xh=XZ2@Xo&9Bc2z>z#~aYvpcNiAI(3Mq$$%ULBsZ81 zi%PGy8+gAB8lcYgWlFVDW^o7ew!=!PvtcRZ|VjSP44 zi`5_f=>7bE$%|KY{KwUEc&GpYZd01WICz_TG#i>b4uX$qn=`ZZ|_|^YA?})@5UN~?0 zlb5~UbW3i@2Y+1mQ`_UW@2P1QGF;U)f1Tf|jXlI)(frQ0U$u;Xs`TP__T6`L{*P;? zUp4)kzqmE+bB5crYPxIGy(6w#uk;SF zq@CYvd+LiPw@iENq>GZBx4Sc*`sVI+kA41Ra>p^Z+ zS4NKb)9W|&j(mK^9_QToJ?pk%C!V}yo~C`laDSY=`Lv}~kAE=#FDKl7{*RM3 zx?G?B^TnHY@9z3{+GC?$cmn;enk3SjQ1b0Q4<5g)VaNGZZ>`$rtiv{a{_VcK!``^3 zbH8t@8d7K1YT9iKcfu*(v|Um5fq(H~Z+w2`^zt#^-j;M-?+uUcf6>OTy_X+(!U>u- z0_{&~(&pW#Kk&sZFK_Vt^vlmlBOji5+PEVdT5r1Q+$-O?diNdvFn)}tbunD?r58=U zeC<)I{b~C=y~4A6%aC*LF8kZEvYzFC-SgCwS3bU4(_Un_7xtYxZ_p%LTH@`C|1fvt zv4_lT64{u#@`~|NqzVzptkk!%$BY|;Tj&o|#O=~av=k15TR<+=dE!EF%aQYG_ zS0CN9Xu|_z_dKO~@!ES=YTCC9SC?9~*Sq<<>^f3AZP2tm-qXULf6%lFl#|q?LATnU9{x%1JDJxM3_Gr2_Q_j%?mq7iEs1vy>i+r9FAv)515LYw z;a(j7)TakMmT^+k!pWN^*Qa=v=8pfvQ!g&Q>&xp;UHw|`;02oY6>Ll%iht->;7c;C zc;1tW;jPOz&uHLhyM5ix_S9N`ceC3wFEc$ea~>M`j&6Kbsb}8of_Zfw4|)~UnVFZ7 zJuxeHVpdj0R{A`5XH$E3vuj>EdIo;q04iA2a(a=V(^CgSzo{xufMF`N3^&?f5lqN_WwnWNk9Zb!iwz}#Wd z(0{3j$%IB)**2igk>zs$y~9>d^YxVdn@f+W~*WwdciEvbGleC``B@>>+VQztp2& zYi}j@p%bE=s_nY#bz5FI_t;b4nDw`s{Q8_nHr#$F!uwS#<;<#XKi0X*`2izeHaBWt zZQk_ZCEq^x*5@w{-n9DmQy+ME%7F(S*VeG2=JUbY`7gB&Is3yL-6uABG(FMX>{&WE zVGDYgNt&(2<@8TXPd_Iip;v?~^0ZIvXx7kK)Od(_W)6PtZpm{m+ zk#U%3Zt0Y&FM_o>+tt3a4V_*ii6U_HVU()e3q7_5rtC<-6}Bjn+|4Q zz^rO6!tdE2Or`TVM%<^F z3o0R0fK!tqkN7bW1YFayRVOa`XvXIGjg!uJxNPv=;~#nc)MM9c|II_Kz;Mxx zM5!(9-v(?z1}8o}F@Nnn!KSY6f$Bsly{HR9^rHH;ucD;N%?S@sb3k1=C;p~uC8KeY z2Q}t&P*e2?d-g!TdX0(bg6et)=0h4?wY5c=n9$#ex&T&(Z8U^bk?_s6rb&_(`TFgc;=+8UG91LtveWZ+h_d!$?-S+^u|A$Cv5g6p8w{y>;zJ`gnVoq!JR7bND zm(SEap*u+l6i&xc^Txf&D_C>agm?L<>eb~8(kP4$%rvrNkd{i4O&t~L??mcMQXeKM zfx0Q`fzpLeqS6BBeZ)K^Bir;0ZnGU}cU0m#=Z9rv;rY06MCwCkOxE$#haANEkiQ^y z!-YjweaPEXYmvW$pQJyHlsZ{WEsgcjOfDiZ)R(K#y(#2c_2p7=@67-l4cHLV-}`dE zxxU=LklMbj_k^6iq1yMJ9Pgv`!glKRMBhi7R-5_o@n=tHsHoWQ*5eM(Ib-a{wYNPu zwCJ24?`*#H!PgV;-0Gi@N5|d}oSGC}->Zv^=+_2$VESI%`M>s_7oTg|1eeo*lV+O! zj9PqqY~r6;oqygzHxwPYEt_&`9n{0zbW(F1sp;emcd9A`zbO2$41HdNw}TPe!1P>N zREC4vz&%+TIDJ1&(|ZtBZQxIOpFy|4q76J}q^7Myn>ANV$WWxM=257icIuNhLLP87 zb4P`OGx6sEZneM?&uSip=6G%d=A~VT#d9Q^M=^DLD10gY4&D``O8n75QL>V^3k-i4 zm{)gaFf0Z@JZN4fK;CNzzhVzfI|0wH=?Eq7BgnfLm{Zs?A5GgISSD|Yy2@?@!e5e| zd6G!Dblb$PVBEXFeIc-rqWaSZPTs53jsH!*oVrSxHfCU2WOiB5fxGUX8$WwEXg_f>|sq^rA`< zu>$DSKoKhuc)Cdh0X+yy4+JhmU|RsN9$~gXU;_e6O~Ab%@#cdtdc?ybcI;~`pQL+x z0B?1VR-NsPd-~XS>eSj&dzQ8u!IesI(3hc%m2D2}>-WB_9{9>LtPen*j&2nYo>FC+8UfFiPvM}=VgN=wt zG%E)45a-mS$SVf<%EHJi2I{LFBCi-ck>Sqr zk9y(q*DG#)V@&OLpRZ_MzPa^r&j&lKx^R5*Ubk0OefzGaJx@as90eEwq$XWlKJUuR zvyV9Xo|ODs-rr%%sh=F1aM`{yUwUk4(vE*$lDT^}R$ek(Xkjb0hSM`NnCj0xUzHp0( z2X0j#b-;h^vx#`;E9=+3?#?_HdM?_W^=M}Js=KGf6^7il+R{@#O)X!!bOXXlSH4oZ za>Ylu%6hhJ?S>?}(jGbGYdYa5J>|jFqaL8S5t`>2#HRX4$rJbsd>%{<9kpxpEVc*A z`C)nyZjlUoPli!~aBk^}d1=E+SNPLLHBbVUuKb~F<;!I&pDtawiKSZU z%2VlFy7I}wm1j``+IzDThLo-xvZcE8Po-PLZG`oft~`s7f^{LC%U3>7y7DOz0@9PE zE9a%9m#*}u8uE6h| zSik}XKLFPW?6p32oATeT?Dl;2yIRtBRq`Ko?M5UWJYq-+<-Z-Zxh#hb+Dp^U#+~r_ zaW~{g>ZOv56YzH;{zBwS%Bu9Bnj%$|z#>IKHUyF3RSEPyA`G1}dJ2BhaV1JA{XT*J z)RHkGq};t3zq>>jotEN{vNk<&rWB+DS-h7bKLh7foNYKCjI$l*KZxJR?(FwWobwSr z8|MO?+i)(#nbNliXVOovX$Ra ziL{lj{DcZ+Y5B@c9sQ6`){0Nh1Pnc1@61Gu!E~S!fqe5+;@A%^bjbLLQLL0nh6kVqLsUH?O_r7D@uOAg0Bb_CV;^)&PCV#O_>x;F~*!6=pX(X-)i%5gLacC0p( z6~UPa3EHbHECIh~uoof|G`4FnyKj{6ecA6y$l%k_{}uNQehT=!#Pj{Fm{O`irZWXz zEaIKR!l;@cpI|y2Z)_JbK}KD$yWk~g)eLijmZ41)JUwg$3!^rz+7yAEgaLTa-sNn< zUS%zQCY$OV6ek?#AQKwx9It0ak4PFbVo2GDq!Cox?1b7T3CL9k@!E#Yfi(^$Tl51h z;7+JlzZ-jvEnLO8z;l4R^VKl3@emj325g=XO7%3 zyepX%6keiWJ`Ug?YHX?ZP%}dYa^R?&<1ByxLy`{-;m=epYSWv z&zU5@1b_Nrr2~0~bPP_^20xh0%DB!TO`I`8UX8*PXAtTd{OO04?89&qvhm++i5f>k z1D8uOdG*F6Tgjay->iZf^OD`JxWc-Z!~`tqX_lfO7-NY-1O*~2f{ za_g}dm2^H-{>O1g|CD;`!pWb$^4;#azHw{P{*612| zHuKPi*}0yq2`Al?y>R0zO;0`jeDaDbTixHx`K0%{(aX2x5)xWmf#PjCf>(p0>aaK{ zx6+Zs{>+OQ=uT1s>SB$Ud;R%uWB66@YEW8Y!RrI+tqca*EN2LlL-~+&9RKoXsGv!r zSi842dz$}gB1{V zrH7oyei2I#xkH2uk|8gNkRdW;5JiU_#KQa2ONO5Tx76n z1&d)6U8E%`VJ!W}-@>;q`k%o%Nw643(M6+hL)U3fy?m6x`iEdKjG~KHh$kgbE+Ad6 z-RS#|!Fo-w7)H@WLs&zX|K?Z58LS<6VzXgxlA?=Rk)#CnA6E+wJo_DkHCeFuU9%6V zM`Y-la2)pKka^4{SPY}++DXy%=Ck9UGFX2WEQV3yg>_3NU60)H(`N>2tza>XqKkPi zK`)V4UiZq^#u{zfs)7#gVRO88MW_)kt?r{o4A$5PbZFNk4m*309BKg8`_6#H5@h3M<_6q;YI!#u7$axyD(prY7ft;*1>Z z5oQ?84P%Hj{cDKP*p|jtPNhW^5Bd<0yE82_N;H=oEt<>52XSMtI$AWBjZe77AUj$# zmyM5(#vnUdw4RU=@{gW|kzl&GShAZgI~LAi8R{;Fkyfi_W=_fAuL;v?)$we#>ZCGF zJ5CgStJSKAOELafJB7j6@ZCyY8sgeLRnz`zOh=@efI(LR3Oem z-e0 zyT$H2jYgxUHQR*R2Z0Le--n~a6o^`jK#58Q&4yL0gR~>C9+h7wYSs2arey~}m6hS7 zWfwD_0_LJSB?ZzV@98WC0mhY@qd;nRgW6$2EnVYblTdpu1S*TfNy{Z>Ede`Sl-kWZ zUC_$!OAa!v{LWKXg@;-(z8_Zb&Yx^v!Arx|GWw(^_A@NUx0n&lz^!wSN64Fqnm#g| zI<*Y@n$lB$A{)!Nu~^)+PQ0kIyQ9uSpHQCW!ey$#&hPQNs_1(!6EbE@!18kAPVg9d z2A(Vq8+{;B-9VYO(~hjQ*y!8cB*)%;Hz+gRWD|zr857d6G@WhadZuCt-P2aWz(7DyRUbC`%8<#k^?Z|+ zn>`_0=A`66Q*m2+0j8dyhtYSIm+sL))kLPvQr_ z_iU$kD)fgd*&}qJr~1|K-u79FV545>4_2bJ{hG^i?>UOGp>v1f|AEXJtXNVbI&rHt zqUe@RhQd`gb5|z1E(&&d9X5KX(m4v9iP2|@I};DcxWHr$8ZDSd`S%*c=qn{l#Fl@z zlBHTX?0iJAGjw~U+GN#MQ8oTYWn3aNd2op!aq-lZLA(%c6ma4_-f1waMaf>$EPH#1 z_DN_#+q42~yTZ1POUxxZriif0p8Q*FvS-GM8i|tU!jnAcx|2URGdt&^n>!yq>EcxwmC>TK)Fk_A*K@aR zdGfUGqsHC2WW(~L7Z%o^x#j)Sjyq9%eA)h;U->lcV}^^o<2lS-G)K5yma9Y0Oq^S>_* zFD`uN)dTma#eSc_(Xol)FTLdEmBkBclJ~p5?vnR%Z@l{JH6@o7rzMwHoqP24=@%Y) zJl@J0LUN~gFWU6U>%S~?eRpR|*R`izXiuv=w)BR7ANKL6H}W3dnD-4{(qOpAJ0lDk zO7f!H9q~wDf8X^W`j0;SzUzVUnN4HY17**Q)NxC4bH>kWaCbI)7W-0X;Uih|GScUj ziO*(bq)$wrn3 ztRcR@>ihkxOYZRBsKwR>{E`1}V2_6WE?RJ%w+#=Tf9+d8P#*w){56mA(ep6`dm6v# zRTc9$m;C5Q(F+^HwI$+;eyK;lZeXnBJ-j;I){@d`AC*HT3P>?yh0kL>?f?EiD@ z|7$HNp8HADgDok);Lr16Van9?PirZ;k3OD~`xt>d_ope&cF_y5x<_`G8%rw-Jhk1ucW?|hHr2O3Lbj{ z*1W{HiKH&2K{z1yu`d`8q3d2GwWWWmu`ydy8h!xhgOrB%LAak&b(3M_qw6`3V{;$d zoYL?$Wc)<2<~kpJL?MYdCh3IdQyN|cn3R5)(g4>{{2u!yg(4%O$*}k1&T|M_$Mi}1 zSMVV2{D3=L54!`yO#Vzl2KnU~B~jd&7JXZH=JW@Mmn6aS?_g6#?(n z(<1IYfqDz)xhTf`=rzW@n4!*a(9~^3ce~$>?gn4xX}}f0Ic2uKc(c-Df-c(mU$LOZ4*?d=}nWe;(TDUF@Kj=J`wQ!YaHFt-s{16G%T_ z?&YCXIqbe$yi%oUTz}8O#JA@c@OSI~h94AL+Fpdj{emlcn-(9+NgNJw9A1>cZeEPw z73}7$MA|jrV#I`A%ht4IiF;_X5=R+?bVsdyb`fL!g!}aJH?|8&Bo#kN)(o~a0asB` zTau19@a>~70dNt6Kc8TSfClYT?Z$+I*u6^;eh7=u^$A&6xpEe^;vAch1l#SSFT=e% z81G)NhG~AhT~0<`D%CAZ9IVY}i6B*GF$-6Lwv17$nT4w)WoOmG45o=J{D{FnO*l<^ zOFIS@P{hc(<5+kH(@Yk9#;k3_8|{M_=5mC2SlEdSbBR>Nt)qPkj3hFg_%nECG1)oH z#GfT^Z!{=6rzo8%p+vovfj>?l7my(bvfoc9o~3=9K>1L*Ad^v66MbH8GllvLa#s{Y(fHG}W z0?)Mi9tJk%CEUb8q&iFu7??{{vz!?|~?_BoMJO1Nv zJ{adLoJ(+?jB_2%Q*ds?c`D8=IOpMf0?u}vPs6zw=ao2v)B9(fvCz2pFF0cdir&>Y zWBZKWt8uQvnckknt{1(x4^8M{i^Wy4MsLM(+=Vji3K@2d40}L^JtD)NlVLB(u&-p; zw=#@&O5i$n6IaO^?Uca7;9Yi=Onwt#1u_gi5n=F#z;(;89vQY=hOLlcSIMyJWY`)R z_Mi-VU50ItVPDIz?_}8S@GZA_jJQhH4whku$gpA=HdBVpmtl=EtW$=0Wf*-*hU++0 zhMgzFE|g(+$uLTJVkB$pWZ083>_Zv0QHFgh!+w-ud!bF_diN1m$=V-e*hCrjcNuoG z3@csw>2)xGbuQ5|kH=0o_}`qCj;>z<{>nxfeM(jt@jfNHY)R=_^DpXnzA}b-e@~+e zFg4}5VYr^U}%6f_T^PSOq@ym)f(!r?uEZb>aXT%&+8pl&qM6@>+Jt~?EiZ7 zg+8VG51_xg7Cn!Yjf09(av#5+BD5o2J)M%f9{ti^J_g?NFfQ&7zK@R56Q4rTH-vcv z7)YC%^0i44!ZtH$Kn*725%6GuAk(dfLfnF$Z@`2Zo)<$x*1t~LUl;@+8TKO1h>qvg z5Cj6hIS8?QAAg?%j85+p=p#}jJU4Q`^ zJV2$g0DpsMw?3_yU7d~ptbNv~o6^d{{*M21*cEkOJJ{7STvf5F%W*ZIUEPnXW7ySK zxGHB?nW)X`+0_DEHM6UWaOGoH^iDnX4hCtPaaF^v4nfUw6uYX!m6Khai!18Y7~_S9 z(AlU87%$LEnlxV61oV-IN{pfK-8Zq3)2(&Gh zP6$6@NE<}=c~7y9b+wRgm<1<_S0TNtY$=BEod54o^A&;pWbH zQL)-Nf0J=H$+E%=0o(ozbRbK58o4AO&r&y>55=&v z2)lm`8_;dRbqV`@SJEBYHHeHZl#I`m#vjg-;RfbPZVZNa%*gfF6Ed0MD0!Y_vW6tQ zjZl4zb{vcN```{j1bFh$KynSkX0YTBh>S6+8Oe;_of%JtQ<2BJwn;{M)>Tw9^^~4_ zv%Bp{S88h$Nj>?Ux?uRe54`Y}mY8s^@FiyKnE9m$x3Mu3ng25jOTZ>9FEWjkvuNUr zss%lV(@+8BAz^pz>;!V@D*UQpVLLL;YWz-RoE?N+MpP+J(FSrdK3YHgDV7W#vjHX@}PQ*##aX+WSR)S7UKu1+it;`9C<6w`{R5k z&eL$d8)rMt_ux!<=3bm@amHAscP`FrabAP-V>nZF@eIzC!C%Fh^2NJ2W2~ZmfHTHk z+J`tFj`K%2(-`1Ooaf=Z3FmWhMh)M4AhV4tlt0N{0q*o zMN3T7dZ|x82br}$Ad>cMXsXVDAie4IsB$y&Dz>k(JU+W9i&VY?vT zaPA)B3VZv>un973nhdkauxc4by%nyvO@_70us_K#>dSE4r7~=_4EwJPyHAEaCBvSR zVIRt{jWX;<8MZ}+rJye1aobs3C2RZ2umfaRmJFLL!wO_ri43ciVGT0ubs4rnh9&Gd zSlbiz;%E%>2i=e2fP?BI{n!;3d>=f1H4MM0e#5?jdkxd}LKktD(=m^?1bZU2vA(lp zQ*1bA4|z3KvPlQ!0R6DivoCJ){Rs)BTLsgFT(X7pM&OEDMKWpLOFyjS9*CRRM{v(! z+MbUlX*=IJNE>3TQ(@!0b#(umzk$f|-JwSw>P*)&wV2fduArCu~d z+w1h9+Ad3mX~Wuf0LGA%ifhhKlUL(##U(Z4igzq=fx}8?2Eq+b5Q7f#gkcxIB2RF+ zB$HYw{jicd88?%(lpRNo7@oYtu%SZ+4@yc*&_;~hF=f~e$-@T?#$uU-#3Tx%dxRk@ zh0#625O&Xx&U+?p$X{PvK556VyH*`D>Z{=!9xgfe+82&!S~sM1{PjcX>wI11F5AzjegeDKl?)xw2~AB}aYbnb_u;@bRHHEc4HN{ra2dy?Xlhi#|X3 zY`>@J>Lt4@d34#Z#7EAo^Ci3fn|#coiI3gCbom7Dc}Lwpd&;KKn~uEdah)bVh}b&npLbn_!89eJPskN0|i`PZAh*A998V*jR#*Z#2O-g7p#S6}t*mEYgH zdC9_uSATTh6|-9Qx~^;GtoyG#qWzJJ4m%_N+``EVpZaml?N`5c`^V(u?QNIHtJ<%1 zo;`BMoe!G$y7$9>-nK_+`5#_->ZsX29&*kfx(__)kowA<-<@^re-6ET!IC46`^Oa{ z{&&ma?<6fav|+!MUdQHjS3h~og_q8~cy(>Zg9hK1bMJ8%b{F2Z z$#>L!S3G$3(&4Vn?@pZg_2sTDf4TdfjLMM(bvHcj8@k)U&Q*Kd-+K1igD-vYqqA2( z^x<2V@6>Vk5ntYP<|(($KehV&>DQg~cv;6szMKA&bl+X?+D>2AJG5f@Mc&r-e@vWl z(^X&Y_V?_6fA{6Eqt@;5>3erfa6k9iLHo=&2U4STOaeM&XY_tiEDSbt6@eFWuB6$N+mBnl=fd8rs-t@4&CG zf6ZX+Pj11%Fp92ZgeE1V(trHzc0=Re3|5z5F^r;XIN{lzl*Gz<`%tXC)Gb^iSPY}+ zqMH2w*n1QBD2lXyyk~kcNoEF;03sqnFhKzklT0q~Vq``K1yMmog^f88ML-VGRg@5} z&;$>>&vn&B*Hzc`V%2pM!i{oz;fXhjBIv4s?(+YBtExLalkUL2Ki_?SzxQu{GU=+P zpQ?JUdaAm+`l*&EjBC38tD>b;CRK<-;3Txw4$zji&V6aw(JiGeR;2_^LR;-cDUR4Y z{IC3w*P^dKt5O0dp{)$ywzL&_;sNXuW%A`At2hKsLR-Q*J+xDzToC`FTT7|4RVit~ zc70_L-;&`sH48VjlzLE=5;zHM(L!5f_;~aOTNK9cRVjg!z*onFwobipNn=Y}oMG`0 zI0^lf(rdB9qh?+78`;x{eWxl#9P~QF#hD17hHX-Bq{YOfSWoWxR`y|t9;@@{;3OQ|ANia3d-#B9u> zaN={9k8UY7T9qPBVyUhPZLJ&i5hf@mUv;V!aS}@%o>1!Oi?4p6rPLo)DdHrS;#{vO{x@e5=-%(zNOUj=PiG?rPLl(ia3d-x+j#HyY!=%T1xexOT$5P7Z zYsv7bqaK~qQtDJyia3d-vH@wKaPP&D2U|*Au1XOnu~g55QloAReA-g#7FCKkiKSpb zwzje!eRV@isTWl#;v|;JNhoz&WKm;FsgG1C;v|;JO(<3M@x8xoDV5Fv2M2KyOZ5Vz zMH(HeZrRdODo>RnPGYH}5=yN+=HkUIrOsESh?7|A=!8;R-^ttDQtCQYia01`3$w*L zfdfTv?IUpP&z=Cl@i1yV=;*CjZDWg}GiXrw>{FtrXeYP1IA@T#h-c6s84h&_La+`g zJLCL9D~ipa{6UP`ifY<=W`EEXS)o>c8M@41o4-(PR!G%fs6H_x$wkoBU#LDSEbA{+ zpQI0gTYsVY%y_A&?w7F^N#HMMeNuqMg5h71!e6pRNn^<`PUA0FV_Df%mtQ_8FE1}Y zuOKg+SD06nSDaUpSDH54+Kwfb{VO9Qsg6h)z0VY~u z!GMAR#i*mQyf|ExUsY6IG9bUOq_Vg=FR!8|tk4Py^D4{pD=YJAD)R?a;bKiibzwv=e3WZit zQ#7EYrn00WFE3nBQdwGF8qTjQF0L9-8m=zNFDg)IkbOl>ehFk=RSET$K#0{9`8Cxg z1r^mrRV8MlmBl6bC8ae0)(j{Q*OZ`HsJFUeKpr49HRWb)P)$*OdAPEmu%c85KEJ%U zxUizUprWR_wA|Eb^?-_^s*3WWiXv#gqOztWKU`8+2pcIVEiZsbwc`rH1=+UaK(U+i z^I?|xEWp^!e-^Qur(mxeZfL_JId(JlhS6@}{MLRr#BP2FGnP9sH$5>b5qUE*$RT#~ zjkqyNiP8pocELnJO|Zcee5mx8{u(>1MesKn#Vf>Z2f+{0*p9)_if z`0)T4j`iWyl9qlZminG0(8S{or}{`=6L9vNE%7)5bE5Ah5Ps4*cqKMU;uYZJRNo1J z@4OJ(I9(+1+~~_gyK&%LHCp2Ffq+|m?*gaGn6~TVhF`_NnS~ol9&YvZ#I?_WlUgRw zG>FNOU%sk5960A+Eb*u}C;BLd#lTsCACI=`+j=n`#a9S4@le94KHf4n0OxlK&#k^s zfcFe=?x>XY`EYWpuMs#~6rNjs+fe><;H;{W^||qT3NGu_Sp9<^4;?=zd(j}jO5jx1 z2sAv7a;A^<-4C1(6`ostnW%3+a564AaD8V0r$OPl)%P>1c?>v9#bPW-aIi{@ivAN+WPdOZo|b}fj7;N zSZ@5XzNZw9#B|p0HeBqv5dEz|V!72<0ftXhIBnJUOn>;b2k}C7v&8xgCnx#Q9}Is7 zA7J3egY7!;+X?zu3!L}g6=>q6hEshd?NG;ipz%wIm+4Ypzaup5J>aCLp<*0g;pbEz zAGk%bJX#rkJlypA60S`F&T(9ekHc*|Y6d~)1E*__#B-zXVl?~$aJrr%@kpif`)nK5*_boB}k0s+J)kpcQQ8-A7!%e@NfcM@3 z>ZAOAI>`DmF7jxHvoZvb$HCF42pdl_)1C*vj6NBP|foQIR~9O`QZ&W2>X zr1~houN4lG;&7AS_rUXT-7*e0epz1+g(DF0&#k_rffqhNeZv18WPRg+H|+rRk-o(T zS>N5jTXKN!ppPGcqmOA@e$;PI;N&OcIn*~CI2R@3CF!>t>bqLuASn(v zecTGX2M$ml<@fi4tZxl7X-Kz)sJ(N{~md`|H? zaP}%ZtKFpfh}Z67*gbwc+N$q(;FKx6w(6S#oZA&%TlGBvoE6FSCD{S{U$V2ak2^IoWayAn zhYcBlExiWE2Oe2IVZubl@F<%yb@I3gV^7RGvJIRot1G8Yoa~5GHf+S;vh!l+oR~i# z{GAtPhwL`Dujrz{#f<=oTChQ`i|4Rx&PoM{MMdwKQHaTSxxCtrQyFziBh^@Q@v z$5ozFJ-!+{f`Gti?9|A)Lq`rBa>~FXFQ0N{<)q0|9mp;le9p+S5hJ5RhL;T)F}&=5 z+n#pEm5)b2wF%H2q*FZ*L3^i^mz7^xK5l$@#rWzIlk#O%)ivb^VwBC!up7T8@SCK0 zvKH-$KL3k`A-k%$PzIA6Kdxf5(%ERlChI@3;!h_4SP)^a_nJP#XJ zIeFrgi8WKRd!N%Md-x>Sz_{PSBC`iiynNEQ@d$4u>3#;i;{e;>9i_=_@bD!qqd87I z>#TtThYlGza%e1ZC%j*`%R8P6km3+Qy9m)A$cltY+tp|VI=?^}wjqvE^9(up-^yj{V<*z&axfqa&|Np;cr@vpf z{rGR+?bWtf3Kv|T^#7lol78LWBw^Pi7ng!PP`JC)uUnV>XEt9>?2g=IP3*(-U*Fa1 z*FCHLBb#O?=?%MU{kor8TOP&Q)AQGjd|Nq|*1I?z-1d_F4mdAPv{LMieA2HQ`O2qE zw#~;}HcB+LfaryS8|)oXKq`-=7=R+@hSMzZw-ZwJWOgxPw> z_b=J-&HDW(thxS4%d@;7|{(%LmU*9R`Y^e->n@%BUb0PSXhci`;+KNEP718xV% zm~`3tfwu#^Mc^HHJHQ_W-hsCRyZ|q%vJYZAz^4S>fwu!Z1TRIi^#gAQc#Xj8UsZ7N z&s&~9eCWgd8?U{pfZSZ?&`a18)a-v%ov> zc7R_ByaR6sI1*n49?W)tKY+%W&^3?WVkLNQoKL~;8kLSCeXUAgfOM@&&qDehq|d_n zT>S1;>AR5rrW4|I;=B9+J4w)9Y2dYCPJ zrY$|(mOjgtKHHW)$Ce&pOLJpw@h6urL3GZ?U&v= zZc^nX{eST-^?u#yaw^tn{I_n$ch$71em5j{U&Ko^W?L2C0;oK?J zlc$WXz`B!Y^_0t|PMkD)?6|3yOsl}+rfD@bT!d0})`-Hg$<@;*A7~%PUw67Zkc60M&?WfG(YBcnDzlLpi5g++P z?>8xfSF69tVI1P)jvw|FV-dgfPJJ!o5tlw2|Bf;_Y-7rEjC*|d@WY;D?Bg!Am%q*U z$ESGp2PvbMCr*kn&ho;)d~zmZEr0aP{?{3Ad1C!F-%@5z-PZYd#zijbu&NhhBj0k= zxDAYty!rIq_fdu)_ZnWxxX#bMzR+N7=jwa@G@bFCr+JULfHJN7M8Qo;j9rm{0Ec(;bY({7L(7US>SzWj8!>B4yrdNnkPKNKc%l zZ(}U!NfX)!7*G1=<2Ij49UQghsL_lY{dM2v7czGA2T$L6FXKnQU-_g#ojmfF=_fD_ z^k+|eeHvpyA73=96XQWw>AQzgN1nV>USeG5n{MB;k+GfgULNUZeCICbeDel%micJ) zxr}SwH~Wh78QXg4rWXqs-+J}N%}c4n5syXAW*qA~cP#pVv8*47-~A!uSyx`TW(9S+ zZb9T@#;u<6apiQzu6}UoU*2H+>YxAe%^2$V;^Ph-%(&H)AKUc+V^@DQpsFk5SNHB- znM0j_@wZv;GY<73SFijFV^JS7V)Dm~M}1HEQD3e<>FBko%Nl#GS~_=A_Z{0_ePhPk zUtYCo!p`f5&-ng@iHA=9{$cA57qAA7{$=T13k-OI177~1!`>YwlFbNvNh z?R#V3V-wev9Xjf?(-$5V9gj_M)36ViHx^zq)Yvp^PGiRG!{Jh};g~mL)(-U5x)a%9 zy%`JN$0^=$%Fm}a_+}1ii0>cL5Lz(w_>I%k}gg8j>ac|n~l+f}84+`v@9NV{ye*n*vE!Pr4$**zBQXA1_`*gM`3IXZrP z)0MsB#_H{86FzQrd`{!ktax4H(eb)%+v4@{J@5#InzHGoQD~W9F2pRRag&Y5(|%mHaa0^709|KOBE`nf&~u ztbDw9w|as^i^}gB09EKyCzp?#I^`s>Ia+Qe`*9il$Q04>TD-(SSb8t)Tyjztk??jw zEQ2qbGVZt40+TUoWsfOoTil7tyf07x!?xSXK!{ z;W}7XFL5~?-#fH)T|Qs+dqcr?0qsK30bf0o^Vu`A%=}G2VAt&}3b*O)CoBp?oncBuMNoRuc~5OM&Fi+IUS@;F;8;u{2`I_vw3vi}v z44gTH-GDRMzY%A|u+eV9nf%_2b03`Vz?n_*dJ)bGab^d57C+g+n3DU_O4x1cYCwC* z!fUi(Us$lOEf|B*$g&}o3W%MTIg$spDS$B*&~CNxXpypA2BMK=pRr)^`q8;*@%r(( zneqCmxn1J**XCwN&OB9K(@w%TfrXMoYXpYxkkhvWIEjqvO_%9am5`cB9 zGvdduys}SxDKFueDLSIrIngtVhBiz(dPv=8+lJJix@X7ne`Ozv8@ten;~A&yjyIg? ziP!Fhp=*;nn4Npnj+a&Mjn7##HBGcS)Yt_ghSrzFjo0J#Wtl^a_3`@YUBtD>N?&)> zIXX8lZmfzM*XG9K#`xUQxG^<%5PU&)C2;YzRJLyCGnR-Y3+WRwf-QQmK1$zPN z^QY-4ey`ruuj_}y({#=V`MU&D{T=jn{w&~S;@1wp5HN!{2XOX=Qd0aQLMb`^lR_ze z(-Zvx{-v{;#lTsfSv|e1vV2l`C7{n#ZW$y#gI@V z1pIxxhU$TB+pAQ0#JLghH07wxd=2JDBLvP+%!b;byas1{luZPDwc`(k4xf3aKV9$Z zPYZSMh5VgD?NUQ2!#jdzT2Y!-c53;A%B#yJDW7~ED*Hw>csv>$oHapI%x}whTq~wu z6V&ue5_TVy6@YK^XxX;L`7X)dfsKbc^tYO|WAF`=-bK6_#>6%xNfO=%yz`5x+pUtD%#PMKv_0&Aij( z!yFqqK00E4?u1Ef^Viu{KVKh0U|p{dWfXO{!TI_S9p?IAUtDeP^|udY^vP@)`iGTI zxvaWMSTdQPD>$ja$lF6Z6a2`YU>eq8kbBEu&zGGrgN&K@g3*~Kz8dvshxAKBDPq!o zgsrrBZRR&2c2}6TKw(vOw)h4XRix&J(ldDNP+Jvzs~Xa~hEn|@Um(|Zfv->fGyi~V z{+Ua3Ka)P4W|f*{!{W=-ke+QPo>P--Ap-d?%}QtEuHsVMRU8HgRrwHp594<>nj(!? z;YXGzlvnX1ZS-W@@S|$}fgj1*iyu|O#@Wq}!;d|VeTu#2T>RJ@5~n^TdFZNg>O*Hd z+#{SZL8YLF&K9#F>1+pNy`zXW=R)5iPc-x3ICB*;9FsU{;jtTc2=w9K;!Kb99nQz# z%sg>;rz0meOa-v)-Gs5PN!T_E_K5}4QHLzc`xJ@S(SjXn!Je~VFIcdZ7Hq8rd*6b6 zWWj#0VEZhXANTaKT|U;7?RK?b-7VNy3&!mgCEhg_?0O4!g9Te`!6x9bsBB}hN(Ho8 z7HqBsd(478X~DQvp)A{M!QQuEA6c-S7VKLK_6QUw%l=8F0%C(230rQ#iZDvN3rz&I z0V);H#v>*1IEFBVhr||az6BdJf)m5Iu{CZii#Ld;I+!BH8%AIT8H_i?(=xKWVwMzd zNI@l9yj~X*yye*!HFF~PBsAd@w+Qzm=M#4Jtbl<$@pzo~sV67RgigRUkRWchZb9dg zhdC3flD9;h)2O8I$LN^$*~t*pn=T3#2=CQ0TS*spP%(jCRyOsLa`_m9ZZ9MX93cv{ z%vC}dGh5sp*O!D+L&1T;T)2`DHZ7L7ICbh4rw!i`zX@WNPb652*_BDT>dL&aVIL)R z=*p5haU;Xtw*)`g`@6a}v!L)2X zej;+`wxR9CPTHP4x%}#~37D9Tubwb=>Lp6?Nl;+}=l^>)F#3PM1_s>(>$-$b6U9m; znzv~Oq&~?GNMWKKNMHRpic3piDxm!q|0V1?l?sSW+$499!7A)XKy84t&eP*rdW*iQB#}?*feE(%3vQ{$!~A`=;qA9wL#Nn zA}gK}pfZhl&dQ-4F}PAWQmITyrAio;Dq+06l(00F3TOx4ZF%qQ=9*21{3F^*cE|;Q z(IJx)dM0i>n&n3B#} z!Y)Bx!swhOjLuoY=$s{t&RN3foF$CTS;F}AN5UBPTf%I8vaTuZ3*ZV;<*3W?_jmZU zbj&xAJ1@!mn%ZoSYje$vW*cjh{OrJi*NJgA3GC#4TY6@DJSJ}$L9azKL3YD*Ov>8q zf*3GOXURf!__=jKn&zMIlPX{;AeJ>s*!Aja058APM8y+77?J%R1qZbuGLj{aR=wf6 zHoJpeIHoo8QEM9x3DPjRw^_4vK(t(1s(Fws<~h!EQ@{&gseI~rp|V)=CdI{6K&!@o z2^*(U0d1)Td&z={Cy3{ZiJ=lE9un4jjJGM#?LgChX!cBP_X4=V1GWtUVm)Ys|0!#3 zhbz)ZyCd~G{NyusK3Z!r*YA)!CrS3F07f1P@tc(-duu*8aNxyLD$B>0PtLAFXr-wP zwo_G&I8f6V<>_dr*!bOm*cE4*a<(WY|D{=J z`)Fb}WqO-IE#tm5)q4bRsT-yO+I0MvuxnH*pv|*jh6Vdi>4qHgH`PS1XpSPS27bC7KK7BiVhT5Z7HqCc$u|HJ?=}nepVAedTD8@W zu1nID<+lz(K}m!Be?&p%JrosWDkj+>QZEnTC-uUV>_Za9J|to6LlVY5Bw=Dcl{fQ5 z0O-Kpo|dwmDHG6uM>mA8o0b}vX>nQJ_vT&1Zvn)Dt`y8XHEkt+KKKw!ZoGU8-;;Ty zeDExq_BOhaPfRnO5qLiQ-;Lj1{7y^iUihX)Ou`1>e5vWvHQTBJ2B;V~FfxAZM63e6 z)ay>eU?CR2QIcQx**ZIiJUJsqkhV;($v=8=UqqFIBGvfuRbg8)3^OZ5lo_)@&4 z<6DmTD;=Mi=X(o|VD?EA<)IFEI#YS9k;)r{OC(Os&1}=@v&>RBlXrfEkcx9u!GD5E zI4S)n&Kyvf&s2F1EB`{CFBk9vQasb@fHTd4Lz*-TrtmDpf=yDX03MT@crz^+r(Lpa zCzVoD@Bdj-=?P+z7ogZpWsHldAb5hCu}p$){!L@)W*a2=#fUPNV1IvqJS_QlOzGb< zCv$p8b7H%uNs)!tCN&7kG!N6HI346{g2!%{2uo2*g+jrVL4kK=*FD}}Bk>;#qif5L<+-At&c*v*7qh5Y{?HzBg{@0-v?x-_BD zIMalfrwK7n6B>gvP3R^3qzN%4O-RCMLJ~$3k}#T(gwcc~j3y*ua=^k!rN$$SO^HKN z2*u@4!%1!8Q1ccb$^N4!VC)Bn<9Bv9{1ZpwP=oLYZpz<-A<9wt9j(E|zFLG|mHBf+ z8R_;>#GFp&nXTjOJd&`u+3ne~O=r9-vR6R9IE>iu=Lh+;ndyK>a3;T};7kRrz)vcO zDXAa{qk<&tD+_Oz1^aJR#`!MFzz6?s${0EDe@Yo_`QKDVOey13rHs>*GMXV?sSKv1 zG9--3kT5Dk!l(=h;}jc9T&Ct`i~ChIg&Sh*VP`RRC(i7q9ve3ntw!0%U(vO+pU4{Wo*65I44? zlGvOdre;N!4ibP@Ro{GFwI;K5%~*Bv4SxFvO?h=FTER*bG>OWS+r{0YnqMA?l$>Ao zMoP{v2P3r#KcB`MjkO~6F#fL*DRX{_0SynbPGeQp@fuQmX0#l?aV~a-`6VM-3`4-( zag)YZs|c%{U|w^Ai<$Kh%O1EqqK9beNv#B4fD28{m8+Am7L!XT_=Hfl`?yvFb2*oJZk&8qU~EX6ETQ&&7E(&RB{zlf7{& z&XnVHoLT1#obSTl!~KK8eeS#;z=L44f%Bf#-6tuzqPz18?Fpo#uC-5>{JR=?R z-v!3;qQnrZL<;IOmk&?IQe-kf?D+!wkXG1EH-eeMuVU$rdXa8EQ?M`bVW0xPPajJM z+zPQX3R0;TK=`BZqZ2*}=UyO^;!N9PJM8C;_(|W-6c#$;KT}xf ztWp8(dJ9%(!5*|=ODx#a7VLQo)@;E@Wg~t8u^TB45gmtlC z#TIO!1>=_q5|0xXS+>f8U1Gs7PAa^sELa!lOP1x{^0I861uL{*&sne+EZ9m5M$ab8 zZnI#YSg>EmoW#NL|E4jg!fnjqlNOgTX9GOSuVc=yV~+cnLkszz8*}c$Siw2f{Wx>X zVLn^sIp#coJja~hmS9K^9P(c<~)is$DBXn%rR#j&Kz@I!MPFV4LH-Azm7A< zoHuahn6njUjyZ4R%rWO(oH^#ahcm|lU62>t{!Z_wg7{?q5F-O8U=13UF90}u?BVinKB#dK@gmKJ~FpfDA#xY02IOa$g#~cY; zK}Xcn^lptf4%#{9jhXtD@PV&Vu{(V4>vbAo73{!A&}(tM>&A;I1;~{ zBSaGa5~t;OG%*B`RYq{rC(Jv|&uFKpynKuxi{^-VoLNoM8TaSB=}rT9nxFkf)*$Ym zzXk9t8$Rjc6e|_ysDdAY+gK($~q?6|7XNrTf?h=hif$?b*VRr*Yx;Y2u z-JAOg7(P33(oK6UBw7*`V5Vq$iI^v0;y-z$wsf3x75oQCpUHhVllPyLHeN@t-K@GC(DyTO9pZ^0h4V3apC5Y#?Zserb}!u#36bJt|R(xglstR{2aG|B12 z|1wSfOKH;Um73IXrh9(@KdDKkq$VYdnv^hVQo^W738N+@jGB}%YLXg|nq*39QsPmQ z5-+~=t@~1%#@zejI;@L|FHL>@+Ty-_?y3;WXqO)P-lV(>Jr~@BTxNXffD79H_|{j) z9fDk!_|p7fvB?&2fL27W*MVdS8TO|w3G{Q7g+pN$-J(PR8c z$1J=g4GV#3kjnxB#gR{uxBh-ynbkI+K6+{J3lfqa&F|j2w%#?jlOYXU(`sC7)?P>CFt9Vr-2WYa>k` zcaH|<O^7iJY|&eN`;HHd4Ec)kgKzQGK29cGH($lmt#hUydTdw~Z~4@Rmrl-8bX0Q=K<%Xaw7ThRGtN>A<2gHC9&;SC^I-8C(eSvz{#)4ZFfyVGoU^HiK6e8;v z0U3fYJ27i0oCK02J?D1`ud5%Kn+tJ)lJGi{s!hf^J6$9QVgqSW)k`R?mPRVppNGNEWp9@-YR)e%OL6^SCB~4f7I>VQ_=5*fa=f z3Nd3nthYxjyd@f39nIN{9uf_|5!@H8UzqzlR1Uj|7;mx(y{YNT9#I_zw*fs2HJu#X z7(=Jlx72sa1w{6=2>Oii7V!0DkWW-!k7lBHnbBL3Xh@ok4UzCFau<%GgP`Yzmy_74 z+(Kic-iU^R8zVVu!y904a3f8%s~*^~bpmVMhzbN<;pO@!6wZz4=)x;v#@kW6Zq0_6 zEFnd}3#Amz?TwP`ZV=zc-3?!EEcmu4vxyxH-6#@XQ`^iI*pXqLvEZhtz6w-lQgf?d zf+Q22%vjAjzJLm#KXxeEX(kvoqPZbh0?=R_H8+ixfphPO zu^JVyZg%*7=v9&iXuWosAO@TnE5oyejl_(%!YhTqAT}@o1BnIS0=uBFh2t>nm<*>G z%VcFFQEvownW%@x0`9`AV)`!i2~ zCvYd#*#(tJawTs*$QsgbqE0cKfIkBq>>*ne%{NdNGLkU_%;+7(fFZO8tHm&(SjT8V zMXrQyG9%%Yf-RV(;7e&yS*AgS!RZR$B!&~1Wi+=-cqL3ys>`%WXlOh2Mczou*FDHr za61_p4_kr7`;-KzDx*1~uZV>)%rsdH(osO&X)r0NLTZmJws0s|1E0Y?F=*3h1e3X_ z4jk!lGQx`*Ye8W*XbR$id8$q%8!>5?X4hi0id_gPyjpoLsFRx97%?y!_REEQV6GNr zQne9djZh`*ildD%Qn)R>5spi^c3-aW#!w#nn!XIYh+YVN!S>*O6VRXCUQ_uKx)~)gp)esz3`cvR zGK?PN$@r7-EJ|q{X)JxwRJU`Wp?3(cF-IB_4iN?SDypElb*McW-jG6B3R6RomEje1 zGb?3hL{DUOvKI;pTT=I{b#Hw9b{#8g&LwgyJr21_hh+YB}gb zsJ4kto)(xF(N|N2(S}*96v;072KpOFldjWP3yDUch2UOP56cX0Ajfi;U}fm+3x%w6 zR)JJHV@{CNaM7@Um9k^5h+q_hM+N(26ka2UQ4KRu4j$m1EO#OQg}Fimg7=&a!PT{^ zScN$pjGb*u0;X#cY z!4w4n6NDUs5Xw&2&aSAw%-9gcAkZxmL|2aFEQ{o<3$BhC6hW7WzFzq=unxsHt$|`_ z)+8BHAp7tOn0->D8|5embAS<0`JHl=?qTGTJS7A%6u>88ki*1ac~sxbq3$iZVd;W} zPl6*3Zl|LPuA?6&t4)y{OqQ2H>FhAC%4+ouG-qgx9Mckvy=MR217=$cJGhs;!tW;V zs)(Z((Kjg1CA5LDl(tTeqsBI=>PXX9!V#>F2Dech5JI$`Gop1+G|0+n%-H}}NdjTS z`YSYZp;O5@`4a;(l|*Agtt1&97|hdP)`06AjHkiv;FBg!FO$>6HE^&YAx8aGY4S91 z4mz}QOn|^OEY?}g&?l+Ij4p_20w*{*>!h|#%|wjlC?2wFoMtZUotE<@Er;q}O?7kn z5L}nD0aamg0>`*12b8Wo90s^TUk|25XU42jPLIJJD(@y`fK)blep0hZIkHRVm=wsUj=PKzvwh@upBtqJAN}vW=C>K62o&zM%EMWno_aX?GZR@C#EOt6+{09cb?oG4?52g>6!h zv;twA5Ce=;xDniQuRA>WDlN2k&U*N`99Z0!UKr9!5={FH?qk;`TZtFp-b5Pq$!r2>`-{5u=qFMvJQw)%2B={EeFT@MGm<2M5legUum?L-d*Dee`7y6n0V!dcE~9oSMcbYYhLgukS=EDMqbga;hW7H3LxEu0xE;J%$XpSg}`{A{UCVLMNQzh^N)hmgRAZdu zgtHb}>n*hg%HSNgOJg*B7$-r{9n?mN(;iJ*gggF-gHbN|QuiK$H4vE4$uJC4)UY|! z65K007_A%nleS~*Qi_u{h?_ZOgldXOPYPcKnZs$Yl3l72bTIZV*bVzcNRc6|kK=AM zJT1YmwtRUgLw<4QDNy%pt$e}xuPZ_U@Ti64OgL`<9P_qo%mpd3G{Zj^pCsO zu3|qD{cuebgBnM3`07`Bh>;gQ1MbP#Dokgmu+^pyMc;srfvd$-3gX@x{*xG5FwGjz zDN$p%UoIcJz$ltt?E!;`82eSvgVarf0?TMt@*KqdAG8Ul)QB#H+i=v)sY7#2e=SC5 zgYIoj`$?G~3u0OkUIv#yyZKP2XTod)20Y|x355hj1*1{icjCw|-(TtbrO;OK9nFuyiw>%yxi~J@sCNjG0H)Afc z-h^D-2kQZ~Q{_8Fw8f(WF97+D?`)j8NLwDZx5yWlPnbC2>dPlio02`D{POB42m@Gs z^uU4quCk1aZ)7CZ!J|ewzF+3L$M)hqs*LK_@{MJo#&0UgGFQsWW$#>hE|y2OtY$Zt zW17o0FF|Y}yv7z}R^i2`T&6fv0cr?*6h@D?UvN_`oy5Fm4|-xjBVdvw8Lc@ z^H~^yo_pdoE!*jW+{$#qj`I8QhW-@K4t+q1j(75rEG{ru$V=MK9V@iwz4z;vc^~y} z(FX)eeJ^C}()$8u9B{708#64A?0AiKjCZvDpq`SNs-2Zu@0$^t>Yb6H`5x)$M*ze~ z)}_GZLTm&=>KMTL+S%I0zI{GjdnBcszarGme|3j6tv~QC175zsyP?By?F#QYudYqi zZ`6aS?X-7N|EfO>zG_2}lvnV9YKtr@#X4G=##5qfp}(CrSU*qS&e{&s zwNt!}c%gW;ey{$w)NTP&rdZR7Z5~u{p6eSIYiJntdkF`4{p{j_AK!3_RfPoPV%4Z&u@3N=c)EVZBa(P?-bxu zPFRnC<3-@}YxEzzPw9T`bYH4A!gs%}r|H^~w0HG;L#f)dcF%Yo&DiE$+#yxFwBsXM z=S~?m*;QDw+ra9yQR#7~6=wwnYk zwH@oU4?JG|O?_JGvA%wxo4qL+-{_`{j}~d@X%&D0R9_s?GR|oubcK+C159Km1%Rlem!05uCMUk;y*S(IwHru(x} zJNRA-?(mZ?+U#FN`L!ACAfFqwPAN-LQnji6xt>3z4fKWEJ@47sJ_IdGS&DD4v`0Hp zmN#gn`W8J^tM}cl_k%3=rM;!U5ejIZwJY%Fbkc1yEw}6wYt(U!NYBtl`LFc9?lt9k z28RIc4U7aMh5Xsy`6eIn^gGmI{l}5|YW=#@!z`OM#I+|gXtVRR!@Q59zhAFkr>CX* zwWic`-|Mj5XG6K(PumBCU2+6ik-_>H(UxKNW#8`X(BT^G8t>!!An%R-CHjwne!fRCuJW2ba;_-9q9f%wTYJ!VJo^7f zDgFH$Lhq-%fc|UB@(wnmrFKjO-Z*WIcc89oJN4h|_onLF=(II@en{8;6*@L$Xoo;T zXix6zhxo0&+XnD+O#6a-?*4}>`fVp7W+yM&BZ6`(L2)tHbh;iynluG*i%`H~kWvPb zo|$F;CO|c)-?}T5dNiV}B-gB(O}+Jl*MqY14OWB)QG;P|RCm0KFVbuu4Un_Nb>;oAHo-NXU0aNKbcdc|HQ8CSO$C z`fi;aN<)x!IZH5wJQ0oGDH?y-gHMdygzUd{c*u8{L*=G!Z;gczH91KjR?FQ&X#R&$l;=DIsKN`Lpu6e3(x%MgkE&DXt}eiuy2_Y z(t9GNu(DXY4VWz7as$3Yaba1%<+f0Is#C+WM8nduoV0ukc5CZgB+p6kdBYfoDKUHTyK|r(P}u;h2y>Snp(DN!;8NXt)@Dt z(G>OKXF@)NVs-Q!nTua`V)rr8>Y;9Cr7yk*L8U`FKCg4;b@3D>WV=n8ye|GNgd9q7 zw5)NW;ltb;zL3F(+i1A2GAqZ15z`o9j}yAFY0^iChNWfM%bNaUaXZm)D+QWDzIl)8 z!uG<7WADxHv#`&x;SHR6;FBnd(#fQ6ZVdU-L%u^pIyTU8miEo}Ie0az?T16D2%pv3 zq;C`rcXJi>%`*kZBKEbtuUH(P)rP2VK3|C1QOBo>hP%2qT++6VZw^8tl!c?HJGhG) z10xRihHu&>th!a$Ym?)fR;XU)(6D~fYGKtGPNM!Zou=x<_Oi;jQg8Ylx=R~9_@?XN zOx-xXX|@!XQ^S{whI_ag*G=WZd!R?P^2HX@{X)L>E^X^Kl?XLEGTmFW-Nm)-8@FJf z5BW}R!&l$<8AdO+wr||!?nXY!q`>6>(eH<`Y1F$ZjKU$*Tq-^#r4 z9w%wf7p=Cz@!*i25%OWWB_?tX4f}7z#Z%oqiGJg7GM(nwuS!Mp?#jO53&w8ubq5j2 zGF5#0Z+Ii5hgI`-XJoqW8@>x+djK7q130Su12G%VbyfKd%cydMp4Y_;&q)9`{57Qa z3HdsaLPrYj3}J5qJuQ@y=A?q_1Ox`L!Eng;FzJn;#VN`a`K1 zp%mN{wf3ofMDtPwcJ9nk8qk8$vaiu;hUHI#xUC9TbViFn3S;%amTMjD9K&FARG zc#eg70r_?q;IoWrPOY9HT9pE~OVd=gQPHNU>juVNf5(|ruKXT+=c92040cV%&Fn}?Jh$8yLj2tUo>pzMX9!Z{oBcUQ(WrxPpHmgw+N+F zZ~dL_1NQZzN!LNsTR#_!@K0|3X=lf3yG9AZp>4f>n4Bm&$$6k?JI776di`M0cg29= z(6F~28yvNoKUz$uiTgjt3G$C=>_YAj7wX|?;j6`cwp|aVP0jx*Sr4k!^!ab&CdrA{ zr$m#-y7B6r|1yP~(t#B_HhHH@lcD(yF4iPnBelMX*F#tI7hX}onE-8K9H=$HVkv8)iV0_$`Tu}8E@4PjkH0(E&SgUEY^OmTa zFZ*o4w4Hf3wmH=QRx~UHYqxpR`_F4=8S0(vcHU4toFrimZR_)juwR?FvvPb`(^ItV zKFgd}AZ}>Ijk=SZ=iw!0qC`y7ou|3XY(D2V)#@p}y-LMyVD1mB(tgG4Cv#un6}yO3 zWBT03#q$D3kAIhF&;5DS+&>CaavN>Db1~Yqnq*oHU*SH9JXzoa| zRgwPB$$;nl$>A=-l<=Iz?h?LIG%RmTog_SG276AM5}tFK!vj!L!gB_OeA!O!H(N9; zyN#VA(^t&t8%h&;b28&OLiYAzs=d%01jllmF0J*k&zvYU>cr^mjpWjYw-m0U+w5l? zE}9L`e#oWa2GOwljnM3S@JuD->*!Fo=^AHW<^B{oeRhqD4G$F!OQ-0_ac{gs3i%Fq z=pRZ{JR$yb*kXeZgMbRB+u)m`zB(5RN^$yO_<_ zeed49udX?i+JO`6){ory3a(VNeyEs@*iA?^-@a~@ORL_xMeZ{5oM4{#j*&K9c( z+;95o3PUKVlEjh16x1vTO59M{yM*F2b=FRGw`H$Wl}wrS zx8yplV$UIHIWIaC^Uqr3QY>XwJ)Q@-7Q=_`i5yt1ovrRx99m16H88nCQ;W02^vuq+ zDU#aV4tA}IrPO|fhm^^6s*?U%SCQ00Bw~XY8*jCBZAh|K%=zpbSVWF&Lz1<} zyR;Upg(qp{9u;rincq5i5>p2=cZ5=1@7iXrbZIbUW>Xtu;mqH&n0>;bTGMAP#G^OW zpnaE9lhn!TR-%V3s=iq^H{?TKg6F}FknkQ373fEV^kO#7SSoSh4dlN;Eol);MecM$ zug0d?1mml4rJ_Cd4Wnyw35g6sD^@Nt#LBk-4H83{td;948O`BgWD6C%31ND;_Tp8X zvvFRHbFRvBb=4Z=`>H$%U61?-mH$BHcc?tuI6RsbNGx76OzEI`QRQV|?KSSlqG3aatehtnn ze~rr5s{CA)zenZoSNT7y{4*-gMXW5pO656xGykf}FNAEjAb%syZ0`w`e@5kBQ27li zzggwCs{DH@|B1@)Q29$S@p}#RO~9G;zoqg&s64|Q@%lELU&r}#l@H-=i}_wS^LlTU zKSt$`Q~7+AFID+4?zrCo{$QM0{#2D8qVmI3{w$S0U*$*QiO8G4ufUn*t5klh%3rSX zlT?1P%HM_OWN!g~Db6haqRKB*`4uX^TIF9+`OPZ7Rpoc$@#0pL{|C;j?+2Cl;gK`* zSbQq3r>lHBmCsapEY}j(yQzE+mCtLBU}Y#@f-~zMpz`Oa{JAQBzRF*u@?%u~VwJB{ z`5KkK7O#KaL4C7uX8m(i{$`cGQ|0eb`QNMj7QDH87x-`B%<^xk{JSdufy#f9g`jG< zz6)pK|5N3C9b`TgXI{tRN$q`{+u_W7SC!9J`5g0lCrv}&pP7j>@v~JvN96~oJXgQ) z`XH5$s{Cmx{~6BPaJ?HG5bMjvnfYESA5r<3%EwinD+Gx@M&&P7`72Z&8&hi^;rgLC zv%aHo{upQOs_#?_hNs2~R%5{~wP5#I zFbu*9?=KeYISaPlf^D{7Us|x87OX3LyriYON(Hn_Ef}|e=2f}zv&5Tg!S1v05aLkb zZMI+tSEyjz>LYrodug^!Je~VFIce67VHfR z_L&9y(t`OhPDok;DizQQELgDx`;7&wuwb(+*jx*Cp9TB91zT&u)?2Uu#vj>kdzA`k zM_RC>ELgDx8)(7Kv0&#}u(=j&fd%7Z9@)ly7VHTN_7@Ab)`G3KU^^|?w-&5(s##xG zl?rGNS}=yhV`~BJP>hAL-NRK1apf%74Hhgd-NXy26l~3c&9z`ZTQF3v+Q3UA)yCBp zY^MeL)`E@2__hXA1+~jmDxke*!9KKL=V82)co(WvK-*x!wpg$@#x;pIRHXu1lLcF0 z!3JWSl6WVnR6u*$f<14+`e9s>czG%n&>ps6k6N&v7?&hoFO>>t_gb(AELca3Qxfk` zmBN=17VI_))(PX6#OtC`0qr&mc9#V^1ml;)J4~el+D#VhRtttt85ADwFGVV#)myLz z3zmlQM%EWnDeU=Z!3+zQj&VfdwNt5pHphb1Td-7oP9gDvDizSUYq^BYvtTJ*Ojx=~ zVK*xaHp_zj!-DOxV3Q6r%T84(tkSn&Us|xTt|nfkN(Hpd7VHfRcE;f*-f)!)XfIo^ zWfp8;Hxut9m4Xdfu;(opqpnGQ`>IqxyVHW*Yr*{8O}v0g1+=Rz*bEEytp)qRf=%dQ zmYu9p0qsKz_NfIsJKMxNSET~lS_`(`f(`Cz;+>{a;LUrcwcIkp;Wif~Dq~ctMp4Xmc&t0t=SX%fw4psepEs1-sUQP3>diU8Pb1xp#HT z26|hQ_Nn+!?6vr3t@U0wCj$mwt_{GC+setq_NgGg2`nfoE^EEnqWyNCasPjTT@&Mp zyC#~q-e;L);Y@mY>y2?miz@gQj|@QjI?nL58uRdd8uPGK?G2p!;`}wv`8e;yxgXB2 z;3ub|Oa-*%7HqXjao>{BxtSuGpFNmg!}#2-@!GE%ftHauBy%W2w1vOUIKMF?D|V<6 z%ZVDX9`&&&jo9J!u_Z?A(E8Z@xRPqbI!28#!TQ+kMl7Q~c7qX1t&cs1D?b`By*~D! z5!;W<=TW12M@FV6YE1jQK6bYe`>8&**ogg@ku_|CF>OoKn6bea^JabQdL#B7(Eo1C zz~`#x{=Ggn-H3ftAA6oLtvW^P$2^_U0|JU+*OHQm@fyC^Z(5zoI9h8uHm&Ut#&@pE zo3`sbBQ{qS;xpmAJ%DqAuOowz?cSlsjQpW;-{Xk!Mg&1Cj8#pmgHhvyrZtDf!f&$- z0RAw;I3NbhDtueN+K8wDmm+rS?qR6_EwUOIFQ5YVn#FKoz;(d9)vS^kBxL60tHCgK?Fi4 z*oYrC541=1l?ZaR8}vedrHDonf)!+jeC|0IxqJxm1T z3M(P?lynDSB95frPtw7(-n0YJSt21wFcb0BjBdG<-E_8^DEj7btWJnthmqK+AIk5- zml>O4h;wAjm+~kcoWohiH0}X8Gs3ffe#iC+N9B#wm72LNK;yv0XDV>HV|7X z%UG|tKUoR=&q*LL`e2Y+iDbMq@(o&BmxP6455e zOeFjP#Bg_g%&-~Oo9G0x=L!l^X-uo!I&TMj)wjET+Ty6OQm}-$X<%tFVz#7#qZDIR z3qP{=%5ZGpCuf!MFY=YZ%rHY(SF8?w(i58})q&7WV2EiiggneJjcUCy?Me2EIuai- zhCL`c^7TYKh>qOg>&$LUh1_i_q>G^bZez?m5buX*3(Q;Do{-kO!!OPH0$Ncw^26cp|6)%{&H&gh-8G<3#k1#WVuy z0Pc=HRQVxS9e@ub_Mqw<-Do4AK2@;tptAx(;n+OLe+CUJWamIf7%O-*asl$w=oUIF zC6Id1orADql73^%)21u!LeftL>3369%6cd+7!OV^j=z&B|Hn-EBjyCG=P?oA2t1@g z1dbhI9_U6G(^X(2iF*15gq4GLH4uSE4hB$16frRnB|@@7MnZ_fhhQ@}hnE>M5EG|S zc&JWfBrHscs_V$Hik7!M0B1laC3J#rEtH`~FC9KLVqB0b-4dKCM#I)V6%>Q&G~t%g zNq++6=gvcE1gHezuzg8*)Yyui84Y8rMT>B<2d~sAk|XShxs5QO+f7Y~LG46i*ki&W z*cqS`kZzV{B}Y@~nx@k=>3i#E+z?fc386cnhZ|u3&_cl3hSIB#w1Ah(Q8uy7du7}~bZ$idvW?x03&zNw&`HdIOu++Uy&!5{GuRN+BN+>SKxO2h%Lo>b zkLquMh*jhxB24Rz77r!HXb#m*9*RCy%=9)fx?d**VcC(6mP_S~*Ep9iC5Yi#J@9S(EXv)!$`Y zf5xtO-FDBkPZ-`N&4Yrq%Xuec3s2MR1sIRpG@tgKmAVU!NZ2UdOdaDhQ+uq`^C>3m zYTTL15+%6bld0WS>hE}FC}Dg)C{w55BvXt+AX6V(sR!}IPQuWb*cx#Oo|jyd6g{T| z_mFthpz*C0ch{4L?UvX*dJgZD4=#SrXCMXJ6o|k$eC;5QMiD#UbVPJ$6o8@FE94jv zQwLiVXl=&S=`E_l7N%NnQ8Yt*?Rq_)Nu(kELuYJ1g2#N~xCheGvpg&TwRYxY0m_?jS1KN@Yn|}B9;V5mUUC6#S|}s4|G-a64qDX z4fh|d73){&Pa;0WU=bsR*B&N1cHcJXgGyB#pKge~ljS$*BYZrKRJ%$)N;^(B>md9l z{?mGiHpwF;8x}Nn_h)G_&jp@F#F>$N^4hcFTG-!H>!)9?-!JIFqexMXZ@>|81~Ew_ z|HOYB_QS1)31fU2!nO-OFA^}ygRq-mw;J|OAs%JQM-ati68qN@hR2Qq_KJWpCW@3L z@opuWHa7IO_a1$vzdFU_n{-tQnnw8hY5x*%)l;M4KaooJkvT9}@CB)!#?^Ct}(R<|A4GzXNA%UKQw#h%P6m9F}78%`&5e?MxE& zux`R83i{@1gR~Q@`q8bl?YNG`c>dnnH-c{B68=}w?h~oEcs7cmIl*#{9*@p+d zLsPK5LLY~s50J)2{AeYls}o?Xw~-+21Oc0f`Uv}8(8ahUv8>{05rOefp(EWdVNC)i zyWi7zi7W6tE$vPZbrvv>*pR(ZU{4Qy<~7TEJTyIQ--W}3)p}?PrwE(;8oaR1CIP!# z$m4a@c0||$Rw3cI+b7#;60k;swCSOLdMvnyeAkNp+1uCEXYwTZX7Z%da{vg#E&r9R;`wcTq8k%{Z+pUeM-xI!_>)4OC6+&->}TT#4ImoQ@xCac&#-@*{qSCa-^o)3jj zC%?RQm9XhdPpVCJguf>I%s@+a{Qw(|AL0t7rD}d}hWAU@yOcGr-7Wm_i5BgI4G{cf zc>Ffm0Z%MISwyu1Bt(tV;F^}y?V1F31Z!7h4QvMU6HkDf7NA+pq+`hB_w zi#=rfyp~HN6r1VFF@mtwqMpv4c4(jSVEv_l^HIBoC`8w3Uk4@yI|&(btmU;!g}w)- z=BLUswEq+EE5Z+>8lskU58?A{VP~{IUdtCcnr+F0uxn5s@RdD!L?0O^?A>p{XzND_ z+fB7#wA;Z#w?P5B48D}QZNyL0&b9EUBdoy2(NdN?R|q-CetrqclBY)eH0%N`<>e7H z|3%Qp_)zpYwL05m^O{ z=+=&9hkGI(+Cd_$$x9t4!fHLFJrU;7NqZu!$wS#D!Xo-06NDL~Y}ezBwt_Y3@m8>i zcW5hEt!>}EZtduQX9CAuTn`Ho^E{3v$B452cJ^hZr}ITjW+x>k#we zHOZ?yRWa{8d=Dztayu29_ds&7xTvmD?fCF9xtJ-5 z1PLsNa=brzx^I7bRaY>6kq$`HCsb*^79^NjtNzYePG;v6L;bm}<&f_o8x3_Bz!? zU%k)4>`YSXdnOZU`mFj^p9UzFQ|iS>f_8&cwWZXpb*ar?_hj-FQ-F2P@`_z4CgHO_ zaaM{+dtEC}Y`T?Mn7TSjN}qp`gL^Y8oG(0!U52JG=Hu%wR|h^H-%YwY+gUqZNb$|; z74nPVRSuH$&l-|kOp&6`>Z88Ww9`3EjU@~Js7SG29BN*C&f&9~Gt>~Za7D5jPL)^u z3oAn2LmW!R%#wKSkm$Lh=9PwICKR2zu}^)0Vdq`Z>0j8&;VB~h3)?3*rHD*1UP!)T zl4l6}vbSTBX9yqeASvA_P+wHoFDfE*1A#7EQE1Y!;CnYZ7PN99CLIfYb`#TrF(JK` ziI`$qFg>{`Q%nnl=dpJwMPBNH4vbUNI+~^_tOdeZI|*w+KQ|)lZ$;3ZWKtB7DfN#g z7gI!f>z{HkRa1=h2!hxlxlWVFdhz{~6Or}R$*q|kWBz7`524JCG5;-x-fhx3A6`hP z+d-cC{6z@y;J}9>)jR)IhxwwZ_xTUFQp?Z=$?TgVo!=$7m_=$2hj3)3>gWB9A1X37 zb)si9Nu9Ucp-q$2d0Uc;nS$j<6``dZASX7(_59jEa7OMGPIN=@Cr+Ms5(=ot=f#5?B$B?0?Ir7V5U zT!bA-=EJoAIX5L=G1WBZ-eh^3YN~_0TTOsX!Tf*JeG8mbQ~Up(IdiL~nr<3NrWzU~ zQ!`zp%S_GWOwH7Em5Q0EnVRUPrWB$3ZMq>uA>JZ{5TY<8Bq1avmqD*L^b$e{|L=FL zwbwrToW1us-rwu}eEzHUnZ2L=eZJ50tlM7uvi6=kE0|DaOzhl++~ZJ2@pI3?>y|uv zlDX}JIZY?$b`N&atbz;rd$g7Xmj@H7*kTu~2;O4`wg3~l?6uv@k2yF{h72D}wK*>a z6Po!k=N0a8$d9-=WBESW*pNYj8QYwR?zJR#&W&z<&PVSOGTGAfbG~>_USL%>{hWV> z3!$$P^PL4@V6`)IW%dbGqJcY=wdmQW99p_*aE=%)I%Ul4ClaIaqFvG018L2SnZ4Da zB+R-pdslEAs)a<)Lx=9liD~SirE7A|`!JYO1rfdAE{EfQ${XM8ZVm;g@+NL}KXN*h zMBMBV!PZm+akJ6Og%qI5mAKg*q+%< zo22F>Q{K7@o@AN;S->RII)DuYEpONLiyDMWJoUt7A6|0r7j-G#XV9;n_@?-z0MB@z zl8?gj_Ef2oZ-_ExHOKl!{B4K7kKu0>{%*qGJ8`Y=5&Yd0XBdy-?=D=QO=X7>>O zK99fL{uqC8eQp--e?Eu5t)c%q7Wt?w*J>KGwQRmx!wdi|!f9TrH8DOg<4juWu;nHp=HyxY>}2N)iTb)mVE29 zj5DyMY^#>-)v|qBR;^`6wCseI@tF--UlMQ+Lh>c5HN>lBsaodOvV1KYp=HHdHc87W zv}~T1Ez+{pTDDfpHftH@iA(?XY1w`)JE~>Jv@8aFql^QeC{emiwJb%;(zPs8%ks6X zP|HfStX#{cYuQXKTcu^IwQQr7vB#EiRB72REvweDBU*M+%T8%oL)>eVu_ddunns$I zwbrsMEz8leL0UFc%f@NhBrRK{WlObeotCZFvMpM+Rm=8i*?uiMqGd<5?39-Ama)v2 zrfRL0k)mapTE=*7_bAJVvmaG#T9%?^=~|YlWjR{r*D^k@A^ApV**Gnmq-C?TY@U{_(z4ZBwpq)z zXc@;5(gyE%N}msE*@s$oOv{dI86U@zx-n`E-(}IVWGze6vesJGMa#0ZtWeAN?gZ%z z-X9MadS@%EXGZ%^qldsGPSAhuH<(LA8HX~I*F)w=-ed&U~$@tq9 ze>qBg6N?-ra;>KLQks;lRC_%pRIS8>Dh|SeCsY;tD|5^9D|3tei*r|E!c!r(3-c=n z5B1}L)9DaoLEz^`Iaac`G8EEuY;=OkYOJSVJuScT@)WEe&#%1xq`z|Najau@SMDtQ zO~U?UOu3>i%_Ts#xo%Q6^e*3uc~@2NDLucktSTSRonmEhdOoIwO#)*Qko)|V*B{KU zoVw4yczzY)1c3pi>iorn7XiCDfAL+rAqKh{_SWUYNGCo!nv+-geqQCP{I zE9OLkzw-6GjJZBpAo5r zEX6DqSC z>k;>KGwx6G7Ymw#%3WXA$*asxR;?z#vMRr_G&KtkLi^}^LSE&5W=CG-E|nc}O%^(W ziAl|Cxr-`E{*0GGvIE)$K9t3tR{3}$ypSy;W3Rs@sskzjCUoL^uX!10ExQUTQJNL0 z#RVBKC-MS9(x%G{*~u2++d&OKGsK@)`EH)bHx&JwsLf{43!y6dSInYkZD7&oEsJT$ zCMz=&d|$^PcJwd#si=)r$OC4wtfDS8ASTt1$JVoCRgYo(_Mpk-M@7($rA0o!K#J+B zdA^hWj6Km4duUsaO50x7-wF~JzR%iXFevQb+Up^W6*<%Mt`U3|9{ZDkpcCQ z0r|e~^6^>d;sVT0OGFN&F<*{+6Pi`(S^=F* z6HNhm!!9Ey6>avrfG(|5e#XzXCXd!4iy4}12BO`wl~i88Qnh_Cxv)R_wppqvm>G=D z`Y&{E%VHXf3XqdJ$t?bKmQE*x9Ve;)_n=*hx@C2AY?o#Zq%i1Ye@oPU=0r&F2_ksr z6uJ{k7envDzNCe}@{k{smeR~B04WL^n=JS@<$8v$=rLm6TVF(s!T` zP}nK?8Q+;1AUjjk5AY`@~V*i(oOOSE&d zgGY-;TNtKpG?W%QjF;uG<^FZ1ee;3yAiwdZ$*1u!X7uXgDmmJl{du#FlLH z`7K3GVOzuxCowoY&I;d;88B21IZ&;4+1fj|-P=14GsS8|E^<*F+{IB1<$-K{38kJ0 z_v*`WmmI+cR(laJ8okJ86i*I1XIsQ zMvB36H6#TYU*xwe#lRPp9qTgad|x#K?yu_j`vC!SfT51zVa~a56qE5{oR0BP0p}hT zRAx^SXLC5qW3YAnm0ghgB39MM1$A)Zz@3~|`2l*kyo?W7(1@Ekq)R(5;{%?#AecOi z#dzw1CavNw{3Hgbi6#TlP8y0 zGfyrTnN=C*ajGUym&fas2(hj?IICnfo?C$Oz!4w`4hinZsLg`$0?h+A3d6jhs|bWCpKRf)jKjf1gW3l78>Ww2uC>7pIl0yfuL_fEP3xL#oVy}r z=4GU9c*#@njl8-PI=QhWLW?q{RFqVdi6_%}zpXdO4P%Db z?u~7k;xIcayB;Su#tGSFxboEr*R*o#ZN@eyH_pVAhA2b4c9-7;?W0wLCpWGUUog1% z9A3a0BqkQ*DQqlqix0_j5{+rPKFR^p2V>eBK1{UgS#N;CeowJ+q)tO)PaRH9pzA0U zV*s-ec}W?0DSMnEOn@+XDdQz%OeFEOHfD(liGvh2g$1A{Uyzfzk&lw)1w2!qvIeL# zm;w{i);JxL&wAFQKIP9-Y~%^-5GCU!Y>2pRpBvRUw3Owgf{!P_@@iXQ zL-aGqA8Cv7heiH86ECqcM$`U2u!^hb19x$ZaDYk8DEK>oCEgYqLPn)2-;7A^A?LdKWC8phptyC}L^ ztZ_0?Ys_XdCv)bDd@+p0gc+TZSl2IwjPB1DvP>Z}`?4>D>_=z$|8C%~C~)&`+}QO&NH$UVjPl9&)!2z{2(PN8#&FVA>J)nzH)A@b%D&65Hw z=D{Kz#@kwBpj)MRxbGQ(@9!I=c-T%Ue+vtyq-&luY~3MbS$MnmgxKq1cZxog{&3$D zqR!`vxXk`zwaDXZqBw=#j4K^jpTO=G{xmTj7CdI3u}%2eT;v(KiQmKw#&ksHx7m+e zPm$4AO!j1cvA)a@vL1Dkjgt5q;$w`P;~x>RntjJMQJ-r1nj3HGV?!2njtTy)!k z@!s66QB_gzB#@i&a^G6fZ}--DN!e}U_%b4DU_f3Dh5S;%b8oF!OjF+!eO&O+F8A?u z=7w>h;2}3<_lQ2Dv#-FoFPal&>3cEcy|5ssaX0lr-&4LX64oWk$)40J#-25TtBr4f zakIz=>Xk$OiRh!*Ze`w3)*FjqjIKM~xW5kNJYG}&kf;ysYqYK*>jSwbLEf2gV{y`6 z`Bx_&p6uHNs$qiR2`ogdpeGoa$i(@CrHiyZhEXg;brVo{Uhp< zc%?WHpVn1g zje?)X94PnuW`E)E@S{@pE#}ucgP-tJnsJNw26GOOobikASDz*id@!`Xx$}`=LS-#} z1s+VZKTK+xS}~D(0>e|LVpoj9gb4>HO=~L_yJ*JD#&hUrcxcWMk4XnUxohUiY<%%J z$<5W-AyakCT$$Z4SjTj7HX4IHa5GDmiwC3wv(e0wfS-OZuO+cZA9 zH@@W@oINJzJmIH9jr7gif$xR~tC``=3wiqA3~%n{#P|?3)7o4-YU>=q+-DMF@D#CQ zgNt2qXCl6qKGg7d}< zGIWZos>QxJI9Lg_KvynRhq;wb$G{=xPJ9hJV;2U(oe)cnW zhRmhuYwkH5OlUf}qP>G3%E|Z@c&OXn2u%-H^bOu)dbnKFh`@GYy0`pa!8)dU%fAbD z&&;OfepQ@-8LXV}Eyp*_L-Nq{V;LU!w)<}SvFx|tJ=%|uSuSQaEz3=e3CVXeo0g3X zCN#5Y*`(mWlzRzFzeVU@b8-vr=ScpdV&&S5CsT zFLDO<3#OAxeii*f$me# zTpSXWnOXBo-JF;|AD=)C4p}*I+We3`rW5m92J4tk%)h|R)WW$Q^=Dxs%O$jpn+6xA zxEWm7CfJ}^f98$xXpi&og=jHu4=ho$3eCe&OjPy2on}>^cLu(O9qf(i=e+dbJ!Zzt z3;Cv{sk11A&D2@c)Gf9}BRuNdq6xuHs4R(}J3n}jSw-e94c=pRqH}Kx-lKA&{@jo` zeP&2=n+NNdAcDAc#vFVb(SC?B zt<72PW^K-D2Wu)nYRzfwQG@4n47O%w$(-C^Yl_gf0Hc(Uk*1l)@@+GLorg)dK%86# z=CPSsi>9j=7zFM#Gix?JOdQfpn^`jZ@nHAO`Y~G!76S>D`*E``bLd=5_h%Oc6PoVN z7G0)O@4fK1#G2?O#Bey!pc%o!vc#Ci!L()s3k9u{+WZnVR^}t|lW--;OuP!EQow{y z`pGC5CWp2hjdHBY!7MX{2I&zed~OCCZ;SSelD9?qRZ-rg=IzaXQR?<4V6ehlnC65} zUiRT-dE10f>l%__yp$v##pf-YdCEmhsG8Lr>;3ST6Fx7+UtU8Sgul1oy5wN|U4y^e z-k`R5y^`C!SHS(Z;F{kM{Jk01`KaFnb_U?@S@_HCp7=Wqe|gV%B>uLB9bQM5kNR^> zP6(B<`D(A65GrMy5Grx^sSp{)v~=>wol8dwd{zNozSwAT9%0G)-tb>)LKm=MaxpPjGw2KI8GOpdGFV1 zGENtjxC$+su4PNLY^9d1)3WtiwnfXfYS~^b<8)DJqgu;2T~x|WXc?!AN?8KhAJ=Lb zxGAAzO|^_q5lCFRmT|hMl;vodU(1GS8J|IsxN%xGNy}zw**q=dJuT_WS}oh8Wt+9E zO3QX>*?uiMsAb2r?6{WU9iqwx@7ziMlC`Xb$DwI-*8CS2;D zdn{#ER~!!Ua6#n<{>op1zL3bNF>h6zmYeZf?y~GG`55`!T`5IhN)0|$t~YtZ`cI6b zct2h~(-32%U@Zz`jacy_=U1^6gXb*dhZ?P^w--UHd(hO|0YIT}jGkCpz-yW8Q*YaL z?mTF6$%HARCr%!Z=N`M&;~QTBpNr(f8ZtG;NkTRrzA_A)4GM1Tnw+W zJ?iREm%56tl>C2ETQ5WX<0n}Dp4!Uie~Yo0$*Hd5975F9GW=y-<#uEIc;82n{j zy&Zp9SGmo)%5B!w+whm?%iFNXy2`bh_)Lf?yGpIq6dz8Ixa+j+PK~=;%O2ITC$x-p zRqC>?N*khQ#FprAtuF3;NP?>kMz1QZg+{C9A*34Zw7>f~gH=K4T)EV4kpm4FYS zvv{?6`wBWEc0lZ&f-k91CE${Zen(bX00ZM<_rtCaFJ=&F3@%}CEubJ3vk$rGy*%v=eK5V|V4<_dd`Ko#1XjwLWt zYSfUKf-f0}OnDOfWu|bgrZEM-9|##E;hKD5hQzJJw#4}>`zNT+z53_B67mX3@`L{AG9f4=ggX zxK>kqw?xWDsl7Fg^%}QP%c5{CJFZ=HIs`^L{;2d0{`!z#h9TGJ?zch~RWrt@nHgu) zY!^2P0;30iRC*VGrIuWy){jCKXs3%p^Ur>c#qlrGKe0$JBNO*Z96M>bmV`B_LDa8U%;dz~ zPjV}W$;(z`*|#i6UUKr{znPqPIZ;owA&1iZ0;)1fxyCq#ON|Kf=wDh}u2H*0#^I7j z630A}Ys@355u8U(++!p+beID3$g*!)ki5Zp>F+*xJs$n#mQ}1})>e~BiRn?f3P#j+3rrRI4sh(|*lR({l4j|FLAsGTB)+9?=n zr>LQ}1A`W^a%{rl6QAPRAp-a5y`d|_zba77s5itKtLwXBEg0XXd-f2g(SH^Ods$fm z&6|$+ACUe;;%0JyjH@)wo0UGX=Mij$I;sth8#i%Oh?Rh1H@vLu(N-RCwW7;6#0pe& z^0Kl|Te%l_pCL~HQYt1+Oc^&3=K?*?KR+mEG_7rg*)O>mU$tOuh&9$xD~GV56E!}! z?KO9O5h67s$TA@Tf2|0l)j%5oFxx6^%lxIcyuIub7ZceMEN@k3Dm1C_t!=Lm2mE|5 z_OgCh{zD{^m;Y8dOFv8%c$#vvnO z6SE>R^TaD6t9?k%@bbmJdB(xJV|T>AH?u?Ik0zyGbXlFB+t#Z3vtFa2HK5A4L1&`(|>7s?3#xU%{}Y%H>!vG@Y&?}xY(FlHESf) zty7zKg~f%wH2giss9o=iHdqlU_$01)+USask>ko*i896nSDZbuU30CbXwlzc%Y{eu z9Bjy)JKK4l(mY(Vcrw7%Hq;-d9w?Af__kGZa!qnBFd8-5_~&~!UAy3;K6ei2F}TC4 z)lXdj8$COZ7(AtH@{|!H$BrD4Q#R$Qiiwj(j2T-|K6NBcHmN}1d@ zZtTc5lS)S#KYah)#>4#|{k`pl4;}pTyHy(|r%p|KXXhV}e%9uNi#OKpdGlTWeyGvq zpPci^$2+z*O1br$bq`Pe>V>pz=T8`V;k5bRl|FpU&Yvpsu2`K}oe{Tj;p2zP8clk7 z=+I|#UvGNWz=zH4n?GA{U*FvR1s!4%cbE42q3Myf$+vg^@w%!$#|j%(`qS=j@m1|s znU{asXxXRVWZ%Ag*WC7l9!UHnC;DM?d*TIqIwU`KX`7v&eln+C`)-YAzBFshf%}(r zHMg5KdTUzui~Aomx0_tNYVOw4e!gt`ux{tByYiEt3SRrO&)plpc*xw|I{fI0^JcyK znYsP#Ex%m*V0r4=tLyAJYwsVg{SrOn-wB`A*f`PLzU;#L1|DhhQ}y1HzwDd&?8d}B zGX@razGZgypXH}7|9ak4%SY^6ae92q+9S;E&1VlUost%P77lreoB*bzT|$bK11aC;Jj_+;RBkL)UalyXm{#y+1t> zbw$?8tIDDj%da~yZc?2F_s%+f(gW4~CQs=5%iuG5M}Icr%d~FY z-k9;}*9&`JaOsdv6Ej-h_xM$Yw>+|C~?FX#;*L}$g_FS-N%<;4z?*1`hjsNsk?|pXL^u%qO&RF*2p_I?& zcK>y4>>P9df}0yG-}w1t!?bsJ_OVZQU0U|o@5f7Py}0gu~+sBzbx3*UHWO|ZTHRDV>bTVMbA`wk6EK686k*Od)s_Whwz$EWHJNJx%) z?ZG>`y!y;V<%hpKzrjo2e%7M@mxofX`{LmZ>2FOb>Tq_CMUA_?*WlW$yE=@%@cUNV z?|ZlC=}lFyb*caR^Qm1v{^+85DIZKT`OW+>w^t?K@?_3cZCdB=e&~~xJ1=}~QDK|m zN6%ha|E`tG-+KCqAs;szx8{*S_xisvx6Qx4;)xgE_@#ew=Z}7C*!2C^cI}C-)udov zhg&Wg^Yi2-U31^~==$vQXC^-M==2bN|YL zd&kb{fAhhW*DgHg;C-j9sJFe|i0E_Lt!;6v^Ct_lKi|^m*mcLBif^~2+m5$-w%;7n z#N2=OuwjQ%-+XBQ$CteJ#0^{DHCkNp#$E@tqsj8lK??2^YzMIvP#?)$`7Z~ps{ZRg(i)7!7l7`v>` zf!mHQ|0(vm^NwcU+u>-MvFiOXaV!2M=R89rYt+Q?liG|eoj5x-ieposku|!kq@qoF z`pT%NSxPc(;U>vqSsr`K`sT1g7EcW=K_)wiWHjlv_V#5gJp|&rISHWoG%rm=Hh4RD; zOfq=r9aCHg563>zAEL8c-?=uFr-s1r5hC-NYC;H4O@ZmcUo34lJO|gA7lCor5}0&x z+{Y?X%@7`r`+QN}JUjvRMdb(ZB!=+R5t!!qr5BwKoZJ)YPhElOqRIjrya$5cz^-uT=9(vD|6v9&cL+uAM_pw0X+*Wuf_tyMrHDx7Q(|C8jk05fnj?vd6GkT znnb{JhQOS{ugTLSgr}*%@Tx5_yEcE*UiJ!saq$MHFRB>+u=X=G4dLMx5MPux52^w% z(*t;#h47?Az|%a0CnbcZg}@NWQd)m@4P0J_VOx2jO2MC|5S#haB7`SZV7z(G4&g}+ z;WJQINd{Ke*uyqIzPt|;Q<%cYl8z zE)tlA$Y--(?G(b(Szvf=l|BBT@^co4@`$5tRBLn}$ADq#9Ks`xTv6;j*iLV`wJwN* z%e^c1_@cJs*Yu}L2v0YG;T2T+Gjq-JDCA%s_D<->U@U>Vkh+ENWI^hS8h~FO*?N4` z6RrpIWDCq@h|PMK6~faa0-l~BJUv2qas-CH(2GYm>_TS~>`$)1u)NIvIVXgtm%ya( z7fVU+>T5!eUzZ5XF8rGHxmO5}Uto9yXL-%Pal=cYJb41M1-~YbKZK{Z!0-spXqK&g z7skmLc--kDFlL{L4ZKo_Il)vS|KK-8=*iavNuep3r7@BlSJ1V@#Jmt9IiMs-n)zoX zX{aUQX+KDNYYFdbGBweXLM5SxW24q%pB4xte+N|LN4m=viJZ9R&0MPrKbceTRw(ppskT5|OhCGl&_ zNhL|pk{nhKXvr)kN!OD5m86H3>{F5yExA}# zt@E^GqLQ@H5NlFr7p^ODoHoZ!$;6% zVhtZ(Hh$Ek8G#Z!I>p1ENbI@e3`p9hD+x!rLc&9vNTib(9(|cOX0U6qSC$eUHJLb` z5)z@5f~{Vrga>Gmv_xRo!}+lYEsfEVj`WacrOYOQ>1c+bC2gt3V<3xG`eTM+Nz6#I zG{!W>k-5-nXEL8-N_778&=MZknNqL_tqhKGm^jjt)=dnLwsuUKDQRnJrG`jan34?B zLpCAFY)WWBNX$SD9^d1PHq)(Z1^JNpqL@oe|JZowggpD>R%2CL1jfL1=8}pM%JC30 z7GD%gR@C7^M_;wHvXqv<*lhLHT39j8e&e#UdqP57*xa65H zx1Lj40%NmvDfZgqvb2sVErGGw8Y;BRxNdsv%Dd%ghqlgSMMDx8o2|YR0%NmPthKNr>V_P3bL-4H{56bXEIykpb{|$;+fMizTUrH5OJHoa zMhY#nyylLogAdl39?n!+0%Nl^%4X~B?0=82wEnHM1jc5oRA`yyHGXdDzs}LNF6SjT zB!RKnDudLD>x=1^&at#^S6TvNvo%_4k(KRBo^fz%pVAT-o2@a}YuRERT3XRb)Ww7R zSdjAp{d_qkx}Rqrrs%jbl$OBQY>gFKX5C;OT3YujErGGwx>9I0#4l6pE<5Aol?rYp z*W)i=$}Kz$IHp`hi9V)GtlpVwX$?|Z0%Nl^PH52l&LamY1b< zo6-^(o2}_WE3mxeRY!=8ca@gF*lcm|ZRO$aksr3Vw0bq7u6%*Ay)9o0sl6@BE2Ttl zRaydLvvr->Sn3Sz70xMqR@Y7+YL3A@$)|KACbxKJlcyipA}_l$OBQY+aANR$T4s zRNZE2eXO(u#%AjVp=IV_y)8vI#^`$3tT8R(_2XFV^$?fd0&Fe*VsW&k)n91|jLp_8 zp~Zq>TV6RT$7gBHRaydLi)*&fGV^dz`Gf5(t!I>$z}Rff5n5(FEKB@&o2B)&(h?Y( zt+_T^Pc9oCWoezI3PfORw&n?~rubzVzNgQv@+u#<1}ZIqvDuoBy;gaxzxb1HEUnv= zmcZC-Ef88}dGVMcuT0X`L8T=yHd_mAw%A8mT6w2a*DwUeW@{0o_Bt=GIuiY?(h?Y( zt;IsiEU(jBwjFC}o!5lA^2PD?_O%33+=&o-ab7uRe}=p=Nx_{;OJHoaDutG5tI3By z-(qQfqO=6Y2)tLjRA@1?SPx~2Q-52YA{=^@mgU3-vHwi7~ zyot5eUQt@a*tKrfT8!)aExXUPw2mq*VxYxS*i;_NaCIAtFX}@4Mqz2PeAvsDRxMTd z#Mo`E5?ZN3j;YOeH`#7!r7JCB?6z*zTD0}W6-~NYTJx0_F?L(GX)Wf)k$$-kSX%ce zEn@7pZr570_5I-OgDkC&l@>8}TdTDeZQ0{GskDfZ<{@pTEw*lI$z{|cOTA^_bP+G*;wblzQGp^6$SD=eBeVwYbh_P#J5L&Fbv?Y_N zb(_*6#;$cgBvyI(pZn}{%hoeWix|oDsgjUgN@C99x=d2i%q9tJDQL{FW%l)TqnD$C zn;v#lTEv(hO4f}+D@AS?Uu-PFA!`O_)7d0zZYy|v7 zr{JXLPPcc<$|zFizEx+Dle z&zN5(z2|O8A2bs^z>=YA<8_pD4UH3AL1(-Uov4T6lN4n!;_H{C!4wogZ^GD$f&8{#7Mfk#fF?IkG#^nL^m}hyFsQQv zmpyLGL_DNlKE81B#A#zo%O(fo2j}+4#zdz7QYwn@@i*8|IIVrZuhz3|BO)X8O20y0!}bL<1e zCqV73s|fPGd3HFukUZJGF3s#QqoSi`I=lcEg9~P0ZaWbI z$3=g;AIvKnvVA1hyF^4MEUJ1@&*{^}Yix4OSCbg2Qzu+Ac0y@t*nw24xCaseP7`_# zpER8}N|S{dO=-GtI8Ep|`qFgXC`}gm5K1%u1r=>3($SYT60w45BErF#X&_R#rVn^O zkU0?I;7;?o?KcU!|Mv!Srp^B*rFQdg7$<6f{|;``aodsHVJxZ!U#2gS!cF?n?h)Nt zpqc;Df!6fze`e1NF!XpEW>{=``qvdrleRLjk4e=DgjbXP{#zq_$0UIg|2MmdE1%P+3}T_kXecA1a$!?OdO1XCnWT`t-M0 zG=p@hPd1x>tv-3GhO1AW%Hishr*gRZ(k$IPHDFI|Di?CApe%r zRL>y)9*bs>91i@Ia~pB~i&IF`<^NdUbf9}`q-U+B$-kf>TS_`kqW-Ftzow)6g1>AB zhm^mdV`dt19mlKxW4ZmO3_(tWw#@(Xl>oEcRnULGy?_A!Czluk0{q|D3kr}2&Im69 zS(i3~oc@nEaL1=(&@G(~J+gQssApDDdXJu2x&8X(WasDRXQ>yXb#HIM3F{bi$3|&O zvE!YPK>l7?ee(MD%*pNBI}1GB+lzOfb#ITCpLK69Z+&DLMT7D(yx&7s)N@dF7zjKa zknYKn)yV))Bsg3*a=*va-*zvqT_*F$vTWUjbTAjV)3jm9T#2pnkT+XwafIv)chO6F z+_7TDq%z#N96d2BE3mw>vwHXHo7XQtyALj9@Quga+v9y_C@Z}1OxK!>9=-fM^KyFO z`e*mlp7~tFz5$s*-YDh)8A0++BGcMAO50{;VY!!3{a4XnLm(@(Md%x|}m{Lg2;ejH15TM)xsAzR-snCht9#q-_Ir2s`!@RST~?;Nb?&6$d>c$@ z;BNVplA@AnC1c0&y<@luZrd&@mG>DTpFVzkR{E&)()6-ADNz+-afrU zddKwi^tS2k(ld;j7q;urHYFgn?U>%NeMUycMV$hKSZ$l0-l0PW{B4`rQK}TzEL~7k zYsisT${y}t%NWu^K35Rlw z1iJyRjv;Ov-rf5f{@4w-)l;ujR&wWY5#)k z_P~zEf%yTS3TEP?C{A`8*1%(dqrf*#;yM85X7?q`&V5VG(6!sO`*#SKe@1}&7MR~6 zz{O6CHtJzv^0IpdFs&SM@>M?6XTG!rX38Y*eA$#m{E>6D_@Qy#__;he!Yx?4{15o7k*Rk4qysqOB^3J zv+9eTuWU}VF?g;w-$wA=1k6PXz4>OsPJevp@C|7_h4unqSLB2D$M;m@DOgjI9_)@TY z05FqZ@aAg*fm~ecL1NZ5H@O)>!FEL(xDe$j3aM=gL z^Ifkn;rM0)ckdx@zI2d$1WfG@Bo1ykmd7USXbj9thb7LfKez|Deji2~-+Ux-7^XP# z?W%>B3w<1IM1Li5<-l3>#j5vdkk|hP^&Sfoe?|QZ8c*^#&=;7?70xY=RO}c7Oy#$h zf0kXV-m~91tT0#=$*JBS!Jf~6d*!&~bF24P!fy0;(Z;y%ExS&9i8wB72WIzg5|FIDkvw_dp)JWnu4s+t;*I9R+<}N94Z z@6E@FAypUnjLX|doZI*+27D`kxuw0taejf7e^x!^IPS#`KI3&POemg!dTQa=&%OuD zKO?|>3(TJp;A(XA8K+}m^0M0!n2a#E2H@xlOrayrDv!o6Gz^%lJ4w54<8gl1_Yq)T z>n?HjahS!&SH=7@+h;WGDREG9tS@|N=ty9i^_IAHz**&C@%;k6`uKErt-ccH);^Y^ z;3fj|+c1e6=EBzsd^cX|Qn5WAn&hNrE4e|w7p*~|_0=;9rTT$=h z#`%mFCP`*xNGEVLC6y)y#^Y$dkhp-&;`Ja$C zzuITSO_n&feCAiDuLS1J=@NI2jn8TyY)8GX^%+C3Fxlg<wB z^DLinHx@6uEZ>d5yryt&b~zsU2$Q zU9r?>tici*hdtg6z&!4Vv+{W?NVWl!x=ix9_2ULIVhAupR!E#z`F;k>HwuUF1Nw2x zZV$*$0@GQ&)0wPJ?Wig24h5#-=J0lnTktg(EKF{88SiPp+^BGF@$!?3j|21Ut>NwF z-sUsI54{u&do0C^H0DuQSYkr%IEumc|zgb;$=Q>2j&ljqnA$kJQQ}D-idr( z8$Mp+F61*7uXt~UL#F|=@otH0;$k-+4QJCmKI7yA64wSe>v&|<=L;a;^`OuA4hxe# zUJJ+m?>AuLAM(cWI9(5z)Ch2GfXR*k*9Vv@BEXdcb6o_u`M|7>0CyiSPlds;Uwjdm zw<5qD0_ICcoYj8Wj(z}U#KSV5-Rd*1*DVKT!6OpqRiEoWig5`RCVTl>c3Gd(fVooP zh<2*a4N;#L0kd{2M zuS?uW;H)_8?XA^Y7#Cwj6yP z2yjDzDRsnI`ONzr6M%V0;h5V_^@`)?-N2lzE%VQ<+{ibgPK>b{3zHjPKKPynCOXNR zuQ@nI1G7-!-0D>q@T~#n{d$rQ%`~7MSn=}wxk3FHBNq#k7vE*T+}c3mSTC%4W$`h- z+6^U!d`wRHmjM5gfJ<)V?O!_d2PupobK&a(!}EZv;*Dw~xAJI>eW|C1_b&z+Q3%|i zGbGk6Ui!CJVQ81hDc<$qI|bajX5M_vzvQ#R`{zggodMja6p3{!-vQveM`7q2laqh! z9=`+b?NrH^44hN>vVY%kc8u{aEKF|oWgT|>2F#i?iQ}&mUrWee0_F>a^Wyszm^;t+ z=A(Z*fjO#hZhWh-;}kF}+j#TQzpcO=Rya4l)!6YZFbmsy^Rav%Qy8p@+A zZzc>a2d?Ht-u{uVm%@1QEdpO2aBp`G&sY0miSgnq1z!?y6j2GVt@Qns;SXOwx+Z4u&kLNvi0C!UlZ$7rSH-Py;;oRCsF?PiFj4{UKN&QMEy>S;d8V&7 zAN~6QnA7`7oEsl*sTmglQ)7TPAN|V(rd;9N`1WGQOkn(jz4_SQ<|zzTMRMw|c;2`W zxT}VS=X*e5y!d!q`XS)19Uh+VX@&9PI|#mKfxGF7@O*D5j2GW-@a+R`bxC->{R-p7 z$MMGdz#SeHp09DK#CY)?Mf+_6T=ZyfKGwf(z?3Q++;Hsg2Vuu_VD^?vKK{D3-xI(z z9xHKfe7s(FJ}`5y^5*09`-g$4IW7zzDrz%ercIPMxBHU3&OKlf`bjKI$R@{lld+=| zn3-2gTpVyt@$$arR)xW;NKWk|4Sf57J2hGIxm|B(d&{39F^bO7zYnpqA8_Yac>71b zF$&|wcLY1H1g`H?Z$4hfTmsB93g?!8G1##Kn3tzXKDT%mg0ImvF~(XfOm6r6N>N`v z1E$xt5?3Est30gpTArW(3QW!GBu@JmbRUfQ(okWrDw0#Voy4BTz}1~8`P}LOugmlS zrcmLu-Js{7wgWc|nA5J8eEhZIu+F2%*A1AS3g^XF08EV=y!jY!TZO@@NKWw{#GXvx z67iy6CbxL;_=e#JW}w2k`F9k!%Yn(A<;}-pY0v*^}tmC^PR%E zT{lZc##0vN`ud4 z#y20BB?{-3f5(Aa1q1!tYzN*G2Tmn$yYcxzJ0(A0p^_L-h8itpf50uS4te~w^R96!|;4y%5Iam z7Qi{>AItaI+a(68B02G$z@F{EZC)+0ZtZOsaL0hze22vG*NJZx3?Bq$++7lv44jjH zjBmu<7>{FNa?3v+XRZdO;2w!{^N;1R7?|Y>=f=nKT@6hBI?2ahC;!SJuK?ylg=2m? z#k&s2g_Dqa%0Tw2=_Qw9NBQWt>C62#N`N#g?LSQ;8oEzUk z;BtUz`mDEqERUfIgH@57>I;u=!+{(4TzI|}3Zv*8+b{WU25!kVZ$3W%_X;qhwo4p; zo&2jp|56D|pBE+0KJK)RZ-b%#CoqGmBo1nhe8-Wo<-iQxDRExM%Ok*isc>%Pu^V=N z0A|}ul8?Vm<;(K;Tw$;(l2g2FZ(jiS%`VC3R{zL%-pdlB=p5rE-vz+6eZ+DRUU0$ z56{Q^%LFcMZ+QPo6~@ay@{Iv*_#5H*ZdVvDK6Yex0(a+|-hAx;4ghml;oRECe&GHI z%(HJvKK?qj55DvIQ)2c>oLl=n0$f92PAZ&RdGPt1%(r8VORz9`@eK#2`#TcHUnl>_ zHwKt%70!*X8o1@aOn6uFx%t-+8TJq`FYK2%xAX2q5X8KPwuZ3a9(`NfjRJ5c)qWI`9a~___DC$cVN063D4Ibm|+U% z#a9Z<`hSM!+X~DMg>&P}!H(B~sr#?+d@X@#t#Dp^9e}y^Xn4Nmz}&8IZhT8o_V)sF z!I$CrvVrNXa9(_afT@mv?*uTvhv8cZ|Kh(w99Wp#+6UX^!@xYFaBlvQZwD~_zxL*1 zdn*HGg2H+6O$R37m^UB&YYI%7!g=wv17>F!KKge6m`}p+EduUKV6OhRw}0fD56p6f zbMtQ=aI1l7`b~JgbYL!0I4{1Qz`Pm(-(g^mgyCbn-vBf1TW|l^zb^sig#et>IPn;8 z?+|xf^0^&n$oDHSZN9VYI`MIw*aMi}-+S{-1>XW-ep5J(L!J1N(I8I$A;xI?qvUfN zXE%rb^T2$paI!o?->1Oyile|(|K#l-Kk?M`=NRKbEKF|4X-tVRo(JZ~UnS1%x?_KE zy!{)VmpUbJZt-${UKTLNe)sl|d})8g7&EXidGXy2OiwZM-2FV1d^ZBKPvPA7*2BMV zfVnxEBR6lpH-S0JCvk3k8^PBVn19B2^RfOlkBv13V_|YDkAv7Z7MSd~@O;+;^SHvf z@$tIZ%fQ?lAD-_cVCp4!`&SLVvw?}N5uPs_n5hcq<{$YM12eW}c)kt598x$pzP;f4 zH!#oE3eWc=Fy|(E$D73R1*V{Oc)rEJJg;zW{;@pX2Ii4E;rYG<=FGa@{xSdB0#h$3 zJYNAYvlY(GKc45^3e5a^-h4fP+X0NPzQnn;4_=pQ4or;(-h6Byxxma&I5+?H1GfyA zl7`-V&4IfMm=_cd#pu{S^Zwv&VD>ih<~twy38%#x8CaOy{A2lE0!+)s-h7O=2$)+G z&WrB>VCE)!^D*8RfvHwFw|LpVdge3NY85<;}9Oy3sXeBFUt0?ca)=hlA7_b*^xYU$0# z_e}f=%(PUAbK~RlC98m0eU8Mrjfa?jsjXs-p;(yQ;^p{n9C2yh{&Ak`Dqw1!D{*f1 zr6C+|2uxaQiE|qd(Z84rVvSB%nB4qh{mTa?tBtpRERUJMY*RS5{9}DN1kBqPdh_)F zu6BB?(GLrg8=rxU7!S<&w&D361m>tcv8s$K&rWzod?`cox}6ByEr^w75F*= z_j8xLKC^X&p(C*V$X3(wc7dw9O>;Oh$9FInDve1Agw?C^XnkAcAT>>;r%N2|VA z<V%*Thr5n-9~4j5ig=i;vHFd&$tm8U zaQql>In!hu_IhCPjRS5wFlo~zt}z&$_&5)!&Wu>2!*$+#FF^lMV8+dqIQHvKeCz-| z0Oo@mB+l))!0W)HZ;Uk#V_{NHHxnEOfEln*;@s}9^11rez#Lob&DR>ZbxUx)WU0iR4t}S26R`W0WwFMaH%nX! za8B*x7L;$DRk%KRt7X@TkGF>h--hdTYrOe*9x-;U#9&nm_@twrZmw|i!9?9o6?qq*bdtIz?8Wtwq9|ZM(yw9Ej zOy<4e`Q`z$OyMM7=zZ*^uys2yE$@?js1}ap%jX3;0@GXJ-27{e9fN?G^$&0V$hQxe z&lS#%FAY2X4NRjA-h3B=uMC(~3WsXuSf8sP-ww>o`z4=SeQ5-{TY-7w0n4sa{i}eX zGdIQ>H*J!*H1J#P!|KP`FE)QP*0=x*la4p&I5-#kIs)^Y!nw9{R_MoKjX_UHKKpw$ z>~@DfiQ@+rCO5mZGeKbl5I;`w^18rO;O1|Ud~V|s=IfUVS@X6Rvrv@ zl)`xNRb%I9;Cemd&DR0AISS*&w-5ep1#Z!^lF#ir(r(m)(&u80)-Ot28<0BXUojpG zI$4G5T-6fy2XJonCFd*jYgm}<=zGE`~*xnrLDR#UC%!NNl+wUNZRl?UTE1k6tg=f;=J9jC<^$&DqS+xVV#$`uByA~}_BQ}9g&Zh3Ne zzK<0q9N$skVw!mK@%&>DFqbQwTf98~7z508XN2c_9hm(JC;6PuKRyQL%BGUf>-^&e zU~W=4H~)D4u?Cn|&-C_>=O2xm#Tn;eVRGZ+`9~%&BhK>Xfva8`e6wGX!I&aL8%URap4e?jec1@;vJ^NGT_oiDK8Jv%MV*l?cYv-i7p zyO*6GXOv;_vdg2!M1>JR{5Zwi1&&t$x4E_C>H{u#4$P99mjkDE~b;@ zv)3!DeA)kPRTx3$!pHN=oxr_wk>qphpE(Zc&{<-<__Dy41Khlez4>_k>nJc$T_jHD zOVIJ70y}B}b7NPDv*)uFFRw@btT0~wG5?~w#TgU2d-HV$$rlRa#g`Ahlq`(HvL&Cr zeOUgD21#O%IAbyvCic5d<+}?5*#*G#?j>;zfpe=@^)HDtnqgtm`4`k*(QX$#dIy+-t0ZoQi`}i4V*bLUIOD}v zC5{iuxRu+B|BS<25huI$e)2tFJ`IE8`RdoeH2fkwUo&9NivX7iOjZQA-oOlr09Opm zxCn65fSD5kZYeOUBf#AU%%c(DwgR&&0^FOxd=LTd2r$PZ!2JqL+`qz?TM{r$Bfy;l zOuGnhU4ZdNfExhJ6%pXdfvJc9cLOj>BEYQzW?clhhk$uH0$dd^dn3Rd0Oqp@aL0f- z838W(DEdDvO!of8-p-SONsR#42AIxaaOcBT4lonL;5crW0nGdea4UdW69&iYFB^c_ z9|p(qz{kLR69MidFbQ9V&%gS>G>ZV2225rc9OLK)%=j=k#&HcW3nReY1kAmTIP3U! z1Na^W=G?Djyga{gI==BW=EH%h`;El$c`>)+Osj9>j0`MH_WEbp<#}RPV0zhbq36jf zfhz>2TH!d3u+!vpUdoDi88K4a^$~ z=f+oo9iIX-*vBgo?tE-t8x%$W@#9oqb|c=0fSVjE`53j6f8={qVZ8XN!1p9@Q{uz( zJ*F^Te0=V83vknGgy-9$FkXDy!S^h1Q)_wiH3P}x3gg9h3_ITfZd;<{b1Pr=W3_5a zOgO$)z%{7j&BychQNWB>IE3X`z6R>cHNaex&OOi5;&3^J4w*e7^w` z+d$&n_)cL*U0`Z83eR^5F#Q$Ijqe0@3DUSRV1hO!ScNYxEqth^KDZY zMdw%^X=V|)8rVZ8YEW9M<;b~W+lW4y*0663{p3Of^ki{XdhklgwM9zU`a zMgZ~Slz+z|?+IMSncjT#Z=%9@@qLJ$*8n%LS$Mt`3KNd+cHpL*6`t=gh4JD$f}PI* zwjM{k zL3q9a3ggAc@yiv!^|;WRuP#V#Rv0h7qu{$2xW#S5^BqzcFTQH<9R+T8hBqI}H#t*c zy!hBZrvsPT!JCieQK2wie2jM%aOIu6`B-1JDvTE&uk*hP+>4#P`B)xxFAg6s%eNVD z(OtdyvVa=^%+1{-j@R{^`crpjVH$dGfv^$_;|dW2Fysm~9n$A9&D#~T-7VRG}Y8v8B+=JY<^{xSas15=`KZhVE9FG9^D==}}!slNSFij)CodZm}2yk71@kf9g0L&E;;L3ri zhyZs3FiRr9tpa9U1h|KQc{&1I6)<}vz#RbQvj}jsQ3p%7_K^%sY6Q48 zz;uoPmjg^;1h`?qj1Gh2b=FD1%!&ZF1eiM=aaKRX@xXe85gCIYr+z349m*5HegC}7 zKey)qc%C=p1&Q(E<8{KzfGc=WV%?6@F95d~m`kc8j=xU+HN^?YGGHEjS>jTGbL%JT zy&C`j$U778D2navH;bAC6e7z-K#d6Eg6twh2!td+fGj3q6&*q{B#|T&val;CJEDLa ziijvED2jl%qoSfHE})>IBBG!oDvN@kfPC-iKAD;7uBvXmSD*X8Up-F`!}PD;I_K1> z>gwvAiE%DAD!Os9Ihb}*E)+lVw+l0-AYNql(RFP%aIN36>Q(vM7F;1SI=#g(d=a>~ zO_m;=pF;kI>?6Hrn9=FYh2CCpW8T&4k-rC-(dq5N&R@W7eNXQ%>D7AQVsv_YvGZ(j zzcZ_fUp}}Fo6j&7VWUF&vi4Yt`OrErLqD`Qab7IWUw#C0j5#r1LUE>gs%~}nV+sUL z12=P<#p?RePt1@XRAhe4fZjoHV?NgFk$*dwF~t;mEugm#T>b5OJ-RP64$Py>(ftOQ zePf{a0hr{^^m-J(Cz!!ov&i(?LvIzhJ)c{8be$s0`w#JX`yDu+e_?U7J|WZF4#PWw zsr|LZ>BfyQyU#GDV50&vEIrA5_ckyKTsV48VJVpRq+BSks9%4=4BnbW=Eub_Xg9bT z-&ppk@`~bGPqJFq@gv z+4m`!k$c_kn+j$gbHR4AJ$FOTx!nh5#rKw;DzEy&!{cCj?z1==hh+ZJeVoZ)PW@d$8wgRxN& z>kZj=5%%SRnI+{ydDtUc*L3v@cZe``Gs`m<81=PF3&4sCOlpkI!(gw`ydB zaTYdRy%hfj%$OivWd0g3s1dkEH7q^VJcpuo2QxZ7TF+hpZq%8Uo@$&Vz0a7@>AefR zufRP~ORq=gpXk~VMty8lg6&}&hjw9K3^CCbr<&)GeVv)XTeHaGN6()ofSYr+-o7)T z@C!36CvA^A$?!T6#+`Nbdh~tHV_;g=vp7{=4TWBJFb~zYI92<0gkHmcMHm^_sHpTN zKyNshuN&y~5}`5poCsqPHY%#|fPVjA9hg0hEKVG+LgOUaJ*9DkF&7&Z3X|C$wsD;D zU;#74QIWM9T`xQUZqB)uo+=MW?;S8(mnEAFjJdYocNr%7?(~LMi@!hs08h^#bp)trGYucoNB&?pJX@MG>tH#FR}ER;yBg# zH}+E4hmDF@uV~*KF!xEh&^Sqd7w=&(A2O%Pzip`KTQD!Qu<8}_IaDv*e`|Yrgpr1g zifCV`-sadh2+SnrRP{E7z@1=LwY2o;H58YS9{FLkiZCw6Mn$F96mgCR<8Nnis=OyZ zPHP`wG{HtiSJ(a)od5x|XqtlClebM0Bbkply1d$?Ubb9Nd zcL%u4?v|c-y&viyr1vE=Iz4*M=(L0gY0nD4s!3;~!Ha^ola|@XLcFuO5*#+(x znC*Q+_Nnr;ZeNSRA!d>JaSVPm0#_%^V#WD*sNJZaf6ffcN#n8|4(#B-+*Z| z(Bf2iPzb||zVM-+!c*G3p8u~AXw0o8lPb?8UfsHp0tKQlH5OwSyP z(_N>O=AG+hg*88enfh=Go#a^^{XerHP6@UQCw~T z^9ggRxX}IhIt39%s}YtS#a-1N%fLLvoGLCC;rN%p?6z~Zeo1lp2~0(iRj+FN%K%rU z80{OdIBGXpoEO5ui6yu$8*On-G=2oeL>S|-QBnCp^-cxz$yj~8vr%ug@t7Ci8x@^>UBP_9 zoX)-$kBCWseVoXa5)3vT5cOHUjRLU~2!pNr;Nj81PT^ezQAYo5i@ zt1K>bzWj_ConB|?eF5&AJM?;FcLA6R=7MptjYE|86TvLI(_QZl8&0ub0PNhfJq4$7Ud%s?f+N1iS2;)p_I{T=f{|ij>2lRTw zAu<}w7tGQ4BI|GTJ?2ATo?l|=iStRZpWn1J!nhTiV4tm@Q@!)SoMcW_@8hU9`r!!U zrRDDRPJI;DW!QA}Qvbb=856{d%-_BEd=a>5k6C&&{>jDznh(6j4BnbWrbqLaE#Q89 z+|m=r$qFcoaGqUMuIu#DT`}@<3jd{?NPKg!WfH@m9=N4oR!O-~TxfiGff>^gyvW*@o)>rt z-1k*1e zR75{SuIe?BMjLE8t_5~p1t!k}HxkVKE*#mn49v$KxLsgs4bj_2dgp-Y<-)ZGmjPy) z2W~Ey4Ia4n!Bo9gZy(iL6HGS`TyHQpx^QivHv`P`9=O-R9CqQzzCXaUy-x23)!P|N zkq2%xnB^`U)w>4Fw^A%tb$c4ot6M7AM}%3+Z)%-U(*#)-1CA zOZS~S^Yrr+nvsj#t!}@PXkNSVLe0RO3@V5`R z!1Wf}K%qAWpZi8c8vC(PQO#q2#0e>;Fw&@5VsYYnXUM)7XmlKj`2jX6bRLt%Zv#Fb z1tzxC;#B7?Oec*|V5Tz%x1@S&@%epV(#qWRZUM89IhEcX=&b^CXSrT)F1RgVhE`ad zN^b^sl!G}j+Tv8}lL^q9F(%S@2OAZY9zEarC78+MElynb4z{-F8FH`BmjqoO*05O*BR8PjE4$Uf>f(O@oMPUY`5a94ndoMGvy z@}(aPN&>TBrp3{^qb&bsz~4W>Oq*wM-NC8+ZFpy-aS=8uI)7V(>Fj~)0VYGrh2qj0 zbq!(0tQapcKWH494Q~5gmVK(cs)gfo@3t77-cab3f!jLYVpZ$5=I`_06KV9uMkN>* z+j9|?$)wI-#ut;b=@ECg zN4Yt#TPmvf)dd&Btg1ced>iLcuRpk9 zE_yV+Px7d@5ZrPPdT)Bv`x@MS7d>jG6X zGQKmos;PO0Ve8x_x^h^GmtimD*sx8>+GUO_6-JeJ#%zkRq5Rb zW|oT{S-%|2YC*4dx0bfJ(EQ>JFz+%)=LMWs9UQg$$IRfZS!5iw+o#}uVpiuzl|_+Q zZ`a3}_Fe|2J#&_x(?0T}7nn5WbbbtC#&iNNGCwGvhd4O-`7Iw@IkT$%LG61xn1`6t z#pM|=ues<^Ty}x^UeJ@r|T&R7c!8K!6=SL?nNzAF@LRRH~ zDHQbNeoO*0ojIK!^O&)`P`B@$4o=>_i@`n4tjZ6H%O)^8nbXDPXE1-b=uuo6FGifP zQPJgnCotWZ)5WDXGo~P3WbI3NpW@);aTx^8&#Wpgl=qXt+`*hKF3Z3?<)TN?_yEjj zf}T8I_JcXXoGvb>n1QreWO1SPt@wLHha!z8*r=%Tp4JIF zfbla&s+^yz zc+@)zuG&(4oT;B*0Oktjba74w)6YeZYAXXXLC}-Oc`lgw%<1C%ATy9Qiz?2KI5>Hn zSAu(iSyh~=-L`ww+Xe1N7d<*JL_KV^h2;hHU%7n^!Cl0x%09}2M2~vu;D)&9k$vMl z>dgXow~HRxx7MTHdT{T$=#hQen zU}BlG^yGe|g6YSc$`7i?#|+g=MK&H#dkh0Nidmf>v%uWVoX(H6U|tgRA}Ceq73on;)&fB`~Y=V*r>O=5&7C1ZI|?C--9!n1`9u`SBz(IzMRsvev=1 zmfo*e2ktFqReq4(w;uKOgZtfsUV{}@+lKs*+ZO|_1+zN)dVAE%0C$~>9*vU|z|3V% zmj_G1ta8yKPu~agiJ&LXgCD^B%$zO{PB0USpHq+gsPcHEQ4bpxogbHgxq>-WoJl1U z%n(7(Sub6mmVg<}oX(G%m?8V9sK&`@;1)2e^J68L7nsxeu^r4;f}YclGhxpWFjb!j zkDrqxf9o?tK2VYQLH+1l2iIEKFPnjD!>q~=njfTj)Vl^;o{JvM|E7Yui#e;^Id$qyBamm`9n@ z<>^ac-geO=FTVqGP|$PcALVKFCnJq$Y*egzogC#~GiFQ>FRDDf+`-B7;0kc@%&Ou{ zdFu11Hv-&f7d>jXyFBVW3~sfHUJUd$gE?U5B=^hCToq}YgN=&HU$XB?Fg@*@M9&Xq zq@AqTU_P~THa*INqs-u~Syb1*r@+-%t@oGm{t_@W>tPrK92=6lQ~`c-Vf$c7d?u` zMlf3hJ!kvU^Ei9J>|;(Bm&4595VOeQV&=VrlgH&0xEfDc?WT$g>0QDMSBv(L>$L&b z#e?289`$m-1w828>QV15a1VOWd&Q&PMsQnQ^r*ib0(08h@cto>-#K8KF{f$|Qb_>Q zSJ0E^)le|QnN#Hztw)qF6KY?l9{EuLZYHzZ{sHDu=5&5+1hYlZbJk1!au1lpf}WG3 zxSaj86=R(rl+TSETx;q4^g?j0m{s{fdMO_D`hm;#pf}N@-gIzxc+gwzQSW(hZ@B1D z9_$8llsR1<)OaS+_!l-Rs`$~~E5O7tr#gSo_uVqU6flRcRY}ha^t=1>n891K$i_+X zVqwIzRSR~{lFD4tMlUqFf*Cc z`LPVlDnZZb2c3U6fZ5{0(RqIlGj4wT0Pd8aC-0Yao{Kcj$3{ixM;9^ikH)J*9`$|$ciQv%IFr8@ zf@#N`F8_Lh$#l`9^U+8!qnJ~jwXHP0Z>1cmT|DLC@(2<^4J^ zuQR7>kN23dypZ<~%I7T(PToIufZNNg$`6Xm=`Z5@m)NN2;?fdKEORP7QW*#)ThMdH zh0Ze-U?#b66u&!}!CSM)+LxYJz7O0}f}T7s8^LU4PUpuVFux0WPCw}SV%0xOQ#9O&)Z_7qOO1a7R09_7n? zFw298-)dP14vpPSzfJtUf z)ox@}9+(nA&*=w!KW_?{y97NaM|w{&gSTdp`9br8bq-G6KQ@5dBGe1cwhl*e*$<}b zD^{F!aj6fc33Ix*bOVzt=sEqRxLgaSSkQBFWYuhD@YXDOBB% zg^M1Yf8Pf46?3{gJp!i6tNQrS-t)m+%$%j?%s+~AXE427IMN%!4BnbWmZ#L;{NTn4 zdh$HI70kWNsq%p8eHP4mK~L_-HZZ$fIMO@JjOhekWPVUwPC7WbACa%&{x3EvDnCfC z9Wy3~7gauY1=q(#kMgg;quxkxH@N7T^FJ_8F{jJFjbOIA=utEdf%#p~legPhuVem< zjfyHyX>UtrOb{=!cBA~e5?miaPu^}mFe8{#wHwtt6U^;`p4^W|z^rlMNbgN%@YXCU zKQ@EgE$GSpI0~lP1}lC#KP~`sDRZhg)Ad3em?Y*@^AegDr!ixBp>B^XaQV#Y@@fK@ z8O-VYcm&Lof}XQI$dA{-Y+_F5$2Ml%{P+~yPt5B4sPYERZ`i2l{J0EEd**cQ(F;r( zb2>i;G2`aPb>K>w)%h_E%H_m+%*Nxby=;D$D=4$3tdZZEnGe*#J#)YnbXM?$&IaOSUTgVLFnng8kJOu6; zW_5mS0`oC*IzJABIVtEl{h;$(^hP{4f{ltQpJ{I!W=s$-GCyMQc`UfWf}Xs6i@}Uz zPUpuxU>+3o6&yfur=4?0ipbZ~M%z6JL)vnoGGul8G3jICNJesaAA z;F>b4)9db0uQ#~cxH!yvfQ^lETydF%Mpy#ZY`q6YScerq*w~QIQHH#|$RyjC%zB~tR1G6eW zDF43psJ9Q?uO9U3ZnC$B+`h)(E@oC|Uk{IZso(~C&>Q1XZxXoK9`qjbsJ8~(%O3Q0 zc+}ei?w|*~v)=L69`(UBVOG~3-8|~`0+;2YNByJJqu!0+X1VB5J}>vEw+h@k4|<<@ z)cYFTeh+#z-}TlWb-~3jt7;FLH^qTTWllG)4Fgl`qDPj^26LC7Cm+`y1@p8EN7of^ zGlREgk&SDV2k$#L`MB{JxNn(N#f9>q`g`8uToYUaW_5ZUJnF@P>+Pb~6!ztVna!N8 z-4=s++(nN(-2`TuJk)-0-d?7iR~_MrE=N4qxAK>|HY*bYKQu|)Xj0xgJ)xKT9^>NW7e+xY7jRiN=MUVVl0_IseC-L_q zFkjg@Tl~nrQ($U+Xp4(P?{YAm?3_)H&Tj*l!CSMa;+F$1;6d+Jk9zlld)R~C>mKzs zgZtb?kMiX=k9t+MVtox86CNn%cS-X8?U@1jSwO$IYt&~u*mX&rbmm}ShV z&illzW(IG~B0KL>KYtF~Tg>YG*a2oQbE-TgKTiJ$;|4Y=mY&>?3&C8yho-;1#;NAk$;8QCu=5w%;->JL++yZ9s)-1BP zP=9;T!O7$DI=Icus^UU=KY7$U0tIk7d@)&CNQ%EJ!hO> z1Gfmw(9bRV=p2jyQ3 zGbV@^nIAFu{9$2lbD2;C3;q^W!iv zUt00g`EeeY=FC}oPCsryy;p&GjyXC{$l@H2&nNA&>cm^K$T(`ZR~=ky>G#Xt2KN!O zDnBSLzkvDIS61D+xLgM2O6F90q|y(}b%LHVE-S&6f{FRss`mo?U*_*Xe183IZ*h6e z!O7#Y3Eaobs{EihANHts0$ju%%SN5vMa)3jEUNiSOK`Cs^ags=8w#$_gWfEUdbfjH zu-HM>Sci&>Ot>Dk9yO<-R?nel}Ekj zz-{oL_q9j8ec*oepjY=hZ|%_-+{MhQ+T&t$vL0ZHnbVzTZU%Fkiym3_IGCpeJ?D9* zIVKKogE_d@@`Zi}SazPd2cN&W&+e~NkIoC%{b1+hc{&_iDYL4$kltL6diQ`^>Ot={ zk9wQHee6N+ut&WU;39ssVx#hx))_8h25-%xIuEu57w4i!^Qj>o^-91^@SwK<%u42T zdHNcd_g(ZT8b5+LBIr5u>I!g?KfzyYRQT`mNWbs$5Hlu-7g;`2UOnUBE4(2--J&Ma|2k`se*r=%D(hU2Wfa%E`UBAlwrSB=- z$_(C`MaEISEOK!2xI6-G4YR7aklq%LdfUP6@t{}rpcNC#3-VWPUlh3d%&P38>+|+t z`ZA|$x1nGPUG&JZSzzuE^ql!j_eqw4d7U|0my@*ztydjk25-$G<0#Hm4|$9Wxcbbh z;zIqrJ(yn1>Ebd3OumaASvC#K96`?+7xH%rm{l$u<@p9?@YXD{xR4+3fcsL=ljqAX zU`{coiVOL1?$7vLacopn{gVD}S}d3p<}5v@zoasP8PcO7^Ml&A+`-BHm;i2uP%k*! zeP_zQN5H(soUVO82J^Lxo*9i_@O%U|Dyq0pz2}1I#GESc>3i=Zm?1qXs<@1DaPqj^ z2yPa$s`jNgFZZao3fwvuJzB^7%%k2uaKF0fQ9jo_jCnRTDnUOa&mZ&vlVRsouNYsjQPH(;BA9eLC($cr#uUVh%HJEo&GMkP z+@s!e;5NAE(RlDRm_L})jYDT2jWo`~MkN>*o4>TTGngdiRO3){aD%{1VvgpGvhjt+ z@pa7LtyyFo<-ulfyP4JbaTH9oWA1)j0OnHWRDRI!JjH?O$6R&%UuGYjS8rejZ_Og( z$d6gz7BQ>yV-1*>nbWn$4lv&cdd~A8#s4=jrle~PT)o62aRhr!8K)8 z=SN2{iOlKz7zSp9peOfZBABVn>HL_(jLr}0AGd>B$*j(g*TB5boX(FQ!5k6voPL~( zdLw_wIE0Og>O4(HXUdPq zn891KsPf=R2Pe;iXTiPBtST;)2VZ&A`ySj84|;V@*vA*SeT~31XI5ull1IH1aD!a* zC=W(^)SC|O4i`O&-)fI~&x3ozgWhhBdOv_W>OrsGNpJ0OF1SmW)wM@Yk9uj~u5r<$ z_81FhCUd%ec|Vv(UG&J)jbOG2dh&j`2h2X^bp7%$Gmtims$c%*;N*E<Ot>Xk9vM^BVF{U-R5}IdjQ-D7d`4nZ+q1H0NfWYdbFN+9L)Kr ztT^lPsvVfF%&FRgRIUXxT+nmoRTFUIz$|1=b>64=z0VBZnnjgYI~|-nuf7HMGqWl` zD9*LbRdKEq|ETh+0l22j>h!vM)awndzX!c?k9rfp&G4Z2h)2DZ;9l^cx80-OE^t4( z=usX-RiV2Sp`vP!hTtw@R@WYh9`*Wy8|XoAlt;ZA!OilZx7?%NDsbyO=zZoa9KMf{S5R*B)^m^?HEIaM7cDDeQP25Y*bYKQd}-%#su*q^MlTVEx@GZbW zji>X#-0z}CP-SS z+eMGYgU7(UY3C&4-ySdr?VM!%JF8}taUM1*K|dsVox$|7b2dG)Z#bBn?VLn!F__2g zoJ4OEm~WZW<<;+CPCwJ;hfR<2pedNknN#&6noq`qNpaz*zhyInw`P&eCn+xZ;HC(A z^1QkS%u?op?P2qS?yJ29X0yOK`v)EW6Emi9c#+vh^SXoJjxnnmH^|?rXW=}Ejf#q+ zIM-pu1o5J(x3Pnh$E7K_*31UuVjHi>o>ZHjY`miJISpJMv%0(*4`w=Z!Fp}&LH<4r zW~HF#Y!9>Dz-)Hms6BQwgSTdp#gF{>0bI3OR(t6D_!pQ9nbY|Z52m-EC->tzFe6+z z@?#=1mKX9opn2kS2Pe;i`@k(@R^Nv>YY(L%BX{lipoCnw+%BU zh!@qoGYQ<)9`piWCNrnYgZW^Vxad(nzY1oPpy$j38V`1Y`Gz^wctGp92bjTIv#9d< zFu0o0?)e-8rUi4VIFlc}!DI@0PCsbgkO!uSIh`M)nX$Z(=QHKs1P3S2=NaJcWH#tW zX>N9Tc4ZBQLH&FUm`wuLty@bQcQ&}a%v2uTt+taRz2Cu|eRg=B%DL8Hdbx1*pf{Wu zpknp}2fZm^mV3}!2WFQCy?tQLsvDm7&i0`BWD{oa)-0;_Z40h9 zv%&b;@`dssAIu~V+#)c~c;L2y`OyOxRWHhDf{lvKzHVR!x^UEt&oI@81FU9kanawQ*GMaWLoCx8heF|2Ol%me1Yrc~3CY znX~#wy0m}H1M@U6x=2Z{eM_>*y7tBA2UabaE#%0*31pSb3UBO(#Tu{#zzn0J#3uYN}I)7J#`G~n- zy|#Rgf!_Db;H_C?;{naXBG0jWV9d%Fn;zv+w1dNW%f@v8SI@yY`w@*VeZb`~8;px2 zem8-+pShsFHjeUsHJFc>Q{{aexRYS6YH0bai*pi~0_KAC+S;uR^lkvN(u3Y}V0PH` zZ1HOky@Sl)tyyI4)){-6Hga#btHBL*aOsYA>jZAKgLAf97jXMLaMZrd8{<9`HY&mP zwfSrQy&`5z5HB)+Nv{~(G`pTH52&9n1+$*HV7u8k%9m|mjxndomuzq`=SCSfVWVQ@ zi+r5C1+YuVCGh+(kMK(TX;Pd0)QqHs0Ys){nPd5O}^#X@+*Q_@*AtHav z!Q8`~*d8H{u0Nguvq{wBds<6GE)&2kW=`kF zS}@z~oRu$SkTDCLSAPUk?}G5Wa^?&9aXy%KA}5V=7cf^dr?bxwW~QC9*>^GOy&udQ z%yIl2`Aqh02D4k_9QIM3{siVXJ7=qx&Rf-*U>zMB6Ia_$dAcjmNBRE z<3%uEGNNP|DVWXn+BL&Pz=5+SW0kecToqbP$dD}&g?E4N(jf>pvJ0DB}b2|I7!BjA(vu`4p z`&{(MzURSw!JICBhrrZpZut?k&(@D-k#poJ^`n_!?sDPCj|afK z&YaGVPrw{!F6f8tyifh(oQrW^0~-}poT=U`!Cb>!b^Kp7UQGtGjJcqFw)nNh@h^h; zi8)>Tj)JLiiQYasU)BTDhB=kL7_~<$FbN{($QR;Lz+^M0^P>XHy&kwHzoh z9=L^I*4sIozwJ=(HZW&gF2q@yFVSF{iJa8mR$%%tr}MV}%&p7?{k7Rg{r5pITba|f z#}{A@iJZeeit}+W=eM-{)#Xc1Fe8{#*+=o42xbj)I{Vgv*&=dM`#uBn2Xi|6E^3AK zQ*2aJ_R)ISbzp8~PG{eIFe^mPVIQ48o(A)(3rBH&2h0KHRQ9z1SFJVXP1vaD?CS(3 zMdTdzwTH$4Ft;#gJ#SIDejv_wH-h7tcmT*^sxyH^(@;LzJLFRP+ zt^o6j$T|F__IMl2M=l(-$CqHLwYB+SvyZOJ{spERb2|HagSk%R9QILr&<|UCT#9|y zf|<^o&c1nI9u_%=eU#5nf_c$}BR}2%^F4Da`<4| zrt(uWuWakZG@pDB+)K;`>y>aHfcc5JV7<2Sh4Q(^RZ&JyY*d2%*QQ5txf)CbbHRFT z{+5873FbHE&cgpg{R98uvJ3xC?HpzJyIA#-Uowv3cS9VmSFuqE`eCa#2K$}@vz0lq z-RMZG(0$J1%v63RtCz-&)4N)A3Y;x2WcOv@dNLb~i-fxd%xLCbl*}{ zm7smLdP|_!q<55YdmoFV^(U3ybtzHCjo5U0>Dc)Qm|vMATBbJ?pASyO_j<8Wp>avY zwM~P4*mNAlFDgCCXo!u9D$YZ(uO*n;==Szg~~xvYr{dHH$1R#J%N#qyDhP!8ykl8c(-@`;l4I zcuHK<0L*u>QBiS=v9BALUChyZU*-q3@A84T{=h~>)xOkjy$3}ZrP!#b+HDo~Ed`S` z*y8Hr|EhXhUxRT78x>u>AAij|e{tPDeTK9VI1hbAgUA_Ck z^tjHw-nC#(FsJjkzYpUdHY%!mufo1n%$OivWO1f(`v(sk&F>oywdxe~Z08v|Z}kUP z%51Q|**MC#X;xK$~2OAYty%dLo%$OivWY299_p?Xtum_IjFTZ-=Xq-IZ z;1Cy^zcin$nS8|xM}j>c1a znN+*AgNv|3`2VEZcy7d|_m91I$5@bF9D6 zIP^Q1`hLp~@jMvPYYMJCn1Rd%$17XC#1(>>>w#Me<}EvC^Y>En1I+2eW&J2*ANgAw zOjD6__)GS+1e3v>*lr;`;>Lkl#9Yu{n|+ioYryPeF4%6ixR8B&!JH5|hkfnAot}sD zDmE&*b;40#7BHu>kH-6zV0JU7v+pM`Rq};6JM5#l)Bw|pIbHk)fEmwR&^}vSNN*09 zr}AgKL%#0)Gnmsy=<~(wmtdMQ zr?amkm?3t~W?usAD*^Kqb2|H80`q~uRnA{R{ha1GpM&|%g`<2q1g2i0tvzh^4FJ~; z%q-?~_T33)xxhK?qxh`>^Cok;_5EU zMb44W6z8YFyyC)9oZklX6LUI$s}$q;2y9e>e%QtrieCbl0nD)<4*O`_$OdzRiyql` zADCB|)7iHb%u&0ZEzVt`S1*9;JZw~SalQ^rsmM9}Ab%%-naiBczNKK^vU4{3XnwT= z%-JRG_B966TI3w|Q69vC>EXgroYTRSGZ*y3W?wA08DL%$_14So)4dC3m&iHnqxkIu z^9OUmdTn_{_MJTv{RkVCAZN3$HTLxeGmbf3`%VFKkH|Ufqda{G%*)KF@}BJ5K}@OM zzIbqT!SrL!vQIwV`@ob5oO8UQ_PqhjOc##qy93O#%&Fo>hFr)08t$n*gZx)z$nbXDZV=(&!P9DF*#FPvEI{cvcMS*F_T+k1j zeUyLQ!IX-6>t+380+_iX=cqRedJDkpXO67wRvYUKviMaXe%Po4?UQh`z^t@$Ha{MQ z#%o~mMuo>ko~I+hOcgk1ocls=4w%oGv(}O1eq1pc&$VEq67<7n-yrNO0`n$wx;)qd zW{+q4^8tK?#^UnN!(E7m&-rG#cw3zh+=M37peD>gNey z(p)&QZxEOpm{ZwDc{&fwtD>GXPu~IarN}w*kMi_;FkQx3{?e-|Pag#H26I9CBzgKN zn3HzSmIt&R7Ck=7cpe)ST^_s+<`aQ)#+mZ;D=?Q&u=I3!Ivvak=7N6M?4vw=1x$k* z-0f=urh~va?V~*H24(_tx;%Xi%(u*`>>CBW-@%mJ=x*OQFt-Vu(>}`6d%!Gp;V4g6 zg87g+m3{Hxz6H~KqPu-lA#y3>%f8A2$0YVBcsk zzc8m8Cr^Tjo*M3l(?06wjleW_;iw%r8V z=AH+`!OUVVXrCkx7J+%q&e`Jp0Q~qEOvUu@_{sBNBA7b_&KYOQgZsgJ#hfk=+RQ+l zu~7;7VY6=p_7#BH#+)t>c7pj?;GFhR9-IIZF*Dp>Cr5d3Hkb~~sqCZc-`-#*iF(pJ zm<48$$T{+W>{||ItqVu?y$t4S=7RP~^59o64QE;Y2CoNgalRCK9l;D^PB*RoHfZj?lpE0L9pVzz%>rL3G1nrabk3=x}%mv#+ z!c7D7n4PovOXr2Rz#L^x*KSqjV7(X{73Li6M)T+M!Cb?fZvOlrm^YZy`THrDlXlML zM<3K1Js0ck*r@2*Z8(^50_SWu%D*XKo?}jze}};|nCISZEx@FE;Bvvt@W3quv)%)@ z4a_m-boo;McHF1KMn%UB1T(?T+1i7~mjz&6W=@w^Z-Ln%a*n*}3%zf_w7tW!PdD$J z4Q3T{y1d!|X0M&I`7sCeo&a;po$h&c7nnx{&Y4$<(0dBZQRZ~>jh=Vm`-9l11pTnt zw*mVmf=RgB-M$ns*#hUZkNWQjFw2bta^3*@;Wd#GpCB*4bZzAOr3k(<99BYHUj6gkH-6}z~nKf8}IK0^Ad9^`{=pr z55Qcwz}>#f!Nd!k(?05#eZT~mtB(Jx*5T%Zd6Bu`cwo!Fo;dzfFfsSJ+jl9LIDvE8 z*BE-ez~nL)tXFb=yBW+Q%mw2o;a&i<)2?Up;}X<+0!*`o;eN=k<6D7A5IM(qMf1rN zFxkxM?5hBCuLtf4Fdr}%jEl{WB-DEVO#A!8{g7WD#evBXIA?oMz6=2~i8)=qEC=&0 zb2@)_fvLX8vMCS^y7vuK{u~E_a5ew!zJ7;STdLE<{ z%o65wemnu@RgrV}kqEtaz|?xsvQKv&^nsboTrkd(_IMD?8+Oj-2erp;F!dgCZ;$iA zv=ce0A6>xQ#GKBL55OE@PS+lhORzqUjY^QS`9bXw52lnkU3*LbGgssse$aV;0ho`O z)1CJlFU9vZbW**6``eIn-Fd&>!?@prjf%>?H0(F6JaBh{d5$?< zoIeKhy9chpqftg@Y*bWw)Eu4kEP(ofNA`grANo9+G7uxh!yVfYYe8F2QCZD z7!TZRFsnRp8^G-Kz?}dS^SHYo?ZFK6z!id->w#Me<}DB04q~3L>{GQb%@584)7=9% z6wDM4+(TgA^uX-_6S30WzKg*0wsW@g$4BrZA551gEj``%*AvV&0_Pn6%Aw~6^C@#@ zY4X{>3ipMuQPGVr_k(%W&e{Ap1&xouY+LQ_$4)Rm3!KxBLg<|UlfTB&qvz~Z{c<0e zv!1f~VY9Cq0^0;kv$gK_wE~kMa8CPjVNVK})y&bnR%PEMPvd!DY*d1Aw%Ioi`?A6O z%$zO{PJpTXOt>FT`-VWTA(&CjS>LykKZmjhOvJO6p02-L1g5tKE+5QnJ7@Ek^8PU} z6Q2wBLw??$3Fdx*bNWkpzYI*H=Pf;5-Y*054s*fwkemm<1XJw=OE1XT{5XPo{{^Pz zi|&5Z2Xm>wIsKr#Zx3cMbGp25vJUeXY*bYC{f2#m!DPPVZr`1;WbN7moLwO*}+_}JtTR55KP_IExjOT z^W!k;y%$6ccF1F82_elKjhLA zH*8db?IFqgr@(w-=WKrb2#p_zd)M8MufQA;IHwHH`HbCbw9{HP1PTfjWP zoX)uOv;&6m@l>QI-QxyPt9>M*FUTxuW4rGXOz$L!EF`vYIkpG z%Q-g`+sX0_M02N9W&KJMjDgHY!#gIO9y*L@=MbaOvOp2=qU;@9mbCbbLKCI{H{5BuVFD@L7 zLuVYp`aL!(syv|IBO3tbNf(aJZ?A)?^Q%;krWt0Ljo0SP@JB{B1Lx_S{1IgxDC?|p z3=`g`Y@7krx5Cih55&P<8VO6V2aB)hmcP@Y}x_m!2G78K`oY28G_jPmD{ z2TG-kFC{a<*FPzvOPfxuWg5QZtfY+ith5YYVp8{hJ$-$X`X}|3DrHm@mlqWI`xXo< z%`P3=B_+|9IJP*us30f9U+B*+^TWWzq#p78`eyY_?jGBusBBbDNol#nY+ph~mM=3a zF*(hboSEhukerz0%S=y7NbZrGl#xkwU!I(r(6?V=QmoI{t(z}BCqHv+k*{0p*4_FI z&mUEg-*0T`*nXo&<(K3Yj_6ljnpZY_YZYjC>j^Y?>DAk*a#dpqF+wWB08(9eX5p z>X^_bF|obqSxRPqcwlokt#4v#d`ePglbGsg>_gb-+fpS)mFU}!B|e)FJEUKkzqD+~ zu!3Pj68&W($^#`s@(RlHD~6$gD~1mrQkI{co1WR;SLz>KT2Ssc|6fwpeu#fexxchH zyRd9XPU+YZ99A-9Oo#T?e+nVS!5>mumfbQi?0O^C=p0>TDAq-cI>tpt;3mwx_}`R* zoYFv9V0d}V#Tl2xq?MpC3&tU}ViE#HB?X24Qnveaj4tQmZ(~QCjStLHR-PLh>+6v{ z!tcv2EDYor4UIFRFGg>Rnsmx4U6cAIrDXb2;s+WRV&7fo(Zx-IX>fXaY;5=Bp1!2i z#N_x?Us^_DQU?Cg^cm4-G$!%Xv@Bn8N;(ctO3g}2G|u5YRgC1+{_%a26MgX+J^Rs4 zqaN?7Y9z#`(s4cd_RH*LH06)08Hw>(@xElp^vp=k8stmpm6XuOM;!~gjhU(*)HUfI zX&LBnMqS=}x{;RED=EX5l#!8^0qdw8>tU;d{dM4QT_Z8MXHsTXX7XTq$j{s#jel!l z|9RM7+vtw?j4*#$i;g81DOg2q!h&^vC|JY{!AAPe;AaD4!u3h?ReTr}#V@@_cf-Yh zb>nLMcBu8fs*xU_Xx4EaP+5ae9Vh6FVbqB($9t>zl8XzV_LZRt?5CE`wG@tbVX6U-{S)zptQpc)(X0 z2$cJZ1G#>)wl4Ukjc)eZdf~&McngS6Y)(J5XeD7rQf6AejD#eNR`H2_)6l*H()#sH z^ra;v^vf_VXZmzI-7hu1Kk^{Hd*38qR>mM-e9!pgRHGU2Ud_l%UwnB0Bbl$rUxeYn z7bwm3m!c~cW{>gb2C*t~EGJN0R#D^+Vu*uGEjwpqML}r@t0u=#DGjDUwd!&VYGhv! zJ57$2`A7P4%F4|=Z3sUpgX$xLA~=KSeHAl<43j}Knhi4#4cyw^Fbl(5-QsH^uPDEV zp|c1bJ}s?pQhaJ~AG&OCFfcnP#(;DAIGnG8`;t=8)p0sPhi$~WYlrR5OuD*XQffky zQJ;543p=xn^YHoJ1nNg2&4jen%&d%l2_#DWYz_LNG3ivO6DH%srnM<3W{#OdTsF?9 zohypV3i68mxiJOB<#8ARQwoX;iYkhH*=556ER-7xxiwIoKB8L9q z*%gK5S=o80)r|3I{5w=tWytIlKL-9D1%-HxjZN{Fm1XDoGqQ{G{N5}fPg^@Ipt0aK zY_zu*_O=PPk3Jk?|8Us9VQI{z-fT6@xZDi8CZV>ALQRqDA6en=>>(yCY%S;Ekhqv| z>^B-(S*M2;#^-2<}~P>!wUVzh`*=4?giyJfs(PPsTfoA ziX5x5{J*!d>@pgWvdJy8O}n3lC-hO};&yb3A zJRDKQ$V~2;8lTlKBT1~Ab~@^&5AAgayu=Hqyiiuy|0CoCcDkfQ;onrDJRJ)D=Gwwi zfv!lFnQf9DpPA`18>VljIqRX1X>N{>2gE05`O>=gPD;qK8lLu5v-aU?J7Z8*FY2vh zyx8sRpP^PVJEu7ug%6M(x@^VYU9-HQO8=>9!&;0w={GdX4W9rS=2$ufpZ3OX{Zx>` z89s4P&jo2-ybx8%uE}WMs_=cbYeHI~Zvy6&c@bsKH>8&)l}uG@1|cw&7aWyLH3?IB zwL$0RgV-`u{##R?gg|k5c0n<&jY>)bW5#-m16{)1Oc&E(bMn+QUqV`s_yk&aO2Igp zoZdG%!5seDGaY_4k&u>>9-oy=7jKHAI`C2Ab%y(Klkm*Y-$n%$# zC;D>&rRHTr*laPgS9}`;GdH-;NQBZCbR}VyKdn^gFU~8^H za&fso&tID9&oQTJI59;;`(y;xSt6pz`;akwY;0_%d6`sPMGWOK6bFbG=P(2MD&FSggLvTwFILjKG`WhGQ5`5KzWZq zMRBfa)gd{bR^l&C@0m{RlIu?@Ek(bJh(2ax3(7G=#oUrTHhf^jI93KQG==qH#iP7K z`xc={#M9y#U0Dvm%3lJm^NTA=oO~NxBH%(c!c54}!9uW&PT0RDE>hq- zN+7qQFuOD!3y=9l{_=txT(?F{47H;9}ai1iQZxs!74HmKP}UmyXTwmz4U;a3yaZgA;i~bU;W2x^TO?!e8Mxx?o=~ zaUa%k{iTKI1!3NHH$U{}W|d|amkke;7MaR%W-H7V53iJtjUA9(I0BY7LKTYzrf>GR zvFR1%d|I&+4O%d~z`RVj7}yg+f5sqQR!)AzmzHLa4aH>;$PWe5nbYRsYLQTk^WR`}Di3rfojvbJg4@Z5|q%nO)#88o!4JFSn! zf{gY;#>NJZ#BhLB_*^3n$HocA;>3wT$yZWd8rF1*s^g4*;dsArytPha=EQhmhg4XV z6V#-0gu^Xew0LGoc8{IX=6fyv$m%`g4ltx1FK65KF{=-X1Ld8Q0?I zj7p1qybxNsZW<{4>!v{*#+?KC+}e0DfyOi6s6aukuOxs|E_z57c4bx89Q69%t*`}D zn>brXJ~cM_gHEWV;r)MT@eu0+5z%!p8NvvUvyHzv$69? z!6-7gn}`W#pwv8@Z4imzzG$}Amzjf`yR^z_o}OPMJSDpX1EaA7NNUg_x@m}0C5BU9 z35M>!l3>=N?SC#bE!tS8)g*M^P?s@Jyd~L)R5_2*G(Sicn6#2?G!O5lb5NnM+uA{s zw#tz^xwxdF+-MJSh8GfdKxsMFnmEuXf0yDYQ`f?1a{Q2hnHuTYxw)8vWulFX{OD8W zm_f^bA&;dTn;;x+T!uQ<3dd%amW z3luX*Gk01L3zD91KH)zO)Acz zyHBEl(O94f87T0$P7wJkU?8p6dE_hoq9kl19A;ib@f{!2>Sn_3e#OHJEAW&6)_%k0 zC{|Rhk-E3QOJ^SGeSCZ?DLyBsq6o8o3=DDj1NE3O3rCYN+2s|berL-V?LgDIV#s3+ zUFmN!4$ARWKN4<;I*FwgHcA^jX^Rq`40P6_sVF631D8oHq zv);n=(m+Xeo|(2`vCb?g9ua3;i6iGpj_g6LqdSnMZ3l$|(<;g_jNq6tW6epOaYeY@ z=I7jN=$f>Kus74Z?-b5l2&TTkptU)@1C@D2&;@pgb2Nq$P z2fu=*v8HHzaOIqbZ{z+sNmxYJ$t&%m;#BLeN|!=G$B^QsvBYb{yks@6<#x7e) z(wQ<}AVWhkW*mGf#u$zDn&LcMc;^RlO{*Ul4$A6*Npg<)kW8t$`0)UA7ugYO^vE1r zR_-q%Dr{IltwDjX^+@R2K!qb=$GAH{*JeFo-~_=y9M_`&PgC_ZSEj>lO~xpuurc4GW>u19i@Y9TrkkrA}q!UlVNn zGm#Ja8)q)|Y!ih3KD+U3VnlSa9^w6;X7kCpG)*5~fGc|Hr}YH@ZUrZa@{UB8XC!Kl z{^muhFl5GU{qz zm73?5$Lv*F7cLyWdtuZ9I}uDDRro3;!b0E-pnb>;gFVG-C`_ASH_aBWf2$7jn0KW13Of_~;`EVQdH05H8T}^i zr`s(>cxJK;*V@5g2dDGqO{Q8s!+RPO@uWX))07tE@KA)YE_4K~ZPTq}Ys{r5%M${_ zaZ@T#8h#@vP)rZEV>y-ZZ)S$$=8f2pvbY*T*M#pm@HV5`T;Vp-&?3dU;bKKNh6mi;{ty{E?!{hxC(X$0hXrFNlKHiAu-v2=Z+qD%9Yt&p#KNb{*Td zXdld^D7&fHZLV*9IXyg+(&CfS&C4b8G}#(oG6*F?zv2*@_3I}pcyhp!_D$NoF(ES4^!NzW+VTImwz zC;V_vsjm=I6`T7dV3UI$cwLgAs{Y)HjAb14S6WruBV-UJEO<64H*FX#Lh_0*-MZQC zM&ZdU`VOh-@W<{j-ElEb0rYjAP>rqb6}Xg!s_TO;g9&NUCB_37$ptI)pgNg37* zvk)r}u)fsHwz_sElkSV+9%eYyS%C0$!Ai)AgY|?~D?7xsRWfuzl_fB+DAR8~e@E8P z{(ND-Sy6fT@%IY*2VT*-Q+mZP^qfBavE~hgsltAQsg31-3SwT02gbrzH7XCZR>L+5 zN7AgcV>-SDf#XQK6Kq>65PI$4k#Xj2gg5c`QbG-pkr^MH;L|o&5XKGAf!qrOG9EqVRDPQtS8)r$FLBAB7Y{n|3(vfd_fI2A%q%w`peBn zg{;S55(@EHZ&-xG><>FdhkY7n&~k8hK{DR_K1GkxK+#_oHK*EwDC!hl`4#nkBp|pl z>`{Pk^-7lTgV+7Gbus=t?0Vn2$_bAFF_~ga!eT*bMwb*}AK}E@riD3J2?-NMR37AV z2^4k&Y2uuParRUAyp^f;p~BC<#w z5&Mcp`07@e`2Si|Za^2fS%^w-HRDg@$zSW!=z&k5`a)soMS!iYo@qWo^4~Ou#2K%^ z++w@A!Ih)`K8wQ=*BteXGvNS@^wz?waSZ=WoELr`)eroY3y$*C_`fvte-6)E37#YI z{zu$1A~4jQYj;jH_*Xhj17KLb{GT1@gc(&$MB+?!B%Fi(|8z7aBI$qjI@oI>@t24D zT0GuVY8xl;!CIkx^aD`vF0pe2ay@G#sm-Rfldx&2IqM8fI72rX;`DP-&oVUo#M$pl zc>jRlJ$l{$kc&orbiZ5e4yp#CpySSw=>JyRhK-_%xoAVgp`IZnGyOd!F!C*|3fYsG(kEc^foxC8li)Z{|}AO!gP^VO@35I!#OVh&qstt z;}3+0XhvgAH2#yLF%7*mBn7K8uE8f=gl?)|iu?ciH18X#ktv~xyF5{AYZT_kGba+`pW~wVRK&3m4<~W)j!%A zD*lR2OdLJkkPhQY1mpfqQS)1U7uZk3|FQHlzxLT!koUL(Eq@Y5{%PB=fLaSTcOy=B z3vrS)qDNC)n$V+)*?uXoYms1=to^(ynqL+>FgCn1;Cj&cNTO|SVTFjErrIGKYb9r| zKp}3ZIU?Ezcypm4X~{!=3;!-u7 z${!3tWnss9d?-YC^g{AXNSGo#f_Zdp`UpH)EO_)^X{pf{c5W1&kO+^QdBzUE=^y5+ zBogLB)~AGLQRt33zNd#F-(OnZ8MnXhLWS1~&tnCjb#ne50kxO#cuJ5BKIBA?l{kKD z!*QJMxhV4|4CosW!-e(=tIGWO6Qy-f;M3- z@n4r&=1-g~g*PXKi2fJaX?}YtAjI5ryW{lx5qz8@Jn^J%F?uTLuZ~-lk7|XE_c(UB zKF}6s5(Y2WNQt-tZjBe*`g2Y9Pnv5^fl>uy)gzeGFxe>fAl!dQ7!!jz;T!}iCI8AW zB|TO#R544l2DA`;xo^MVbkM|j`n6hruGUf>hu;%Z4ra~3gIFjk!%q4)<= zNk4n|>)n!`#ce6ffBxPo&2OtO?iN1b_jY11XWVB9XJ>U1L&Go3@6HgTk%Pzwob|^D{ z7@>1Wo!(VG#BTncf&CGD^F#ACa&OdCJ@~^%mLtJmRpPJu^QWO-hZlaBAf!d>alZtA zJb;gqKGg12@oXs4uTuHq3rpyiMDSY(MjAdVz-OVh3J!I_AHypPwnK>UCKIr+7VSzwloI$^IkteJf(W;Q^FQ=N{B>Y(Dg)VbR^A~S+dpW}Nr9bTQ z{X0LEq4)v@JuXJSuSRW$W=q05DRr?V9*upHlqwjK8MYqGO!- zEczC^Y6*Uc%b)w#M6F*)SXn9Qh-2kqsLNB=6h#_Qrc?^4qxdHjsa?wKiq05%R-_2h zi1dl2(&6ySlQkWEJF&_2pIIc8oP1+s`U=Ml^es;#*GUI8Qd_2y>}Aa;T?zlS{UK;@Mh-{4N-?e#N1$ zKIQs`W#^0tRFvcA8LbE^17-edGu==N-3pU`rxlCXxQ^5Qo zFZwoi@F00DhH=<1jJ>DRA4V{Ym}*BZO{w-r{mmb@+_vYf>;LurwAuH3_QWqQuU^rp z!y6aAaM@4o4P%(e)ml8^XtfDv9e?!d?*6yxZF=jK6)`=Z>2p=!#PS7G>KdI6;V-D0 zTx!QLcdah#defoPCp=Q)ldZ)c*4e)0;G8u_cC5a9*Qumu-^AZPLd7xFP7Fz#cBEEJ zQKOjsJzw}{%0+|JSI|i;JH3kG-nb zWfvb@*0*n!e>J=>V#bxPlo`fvCKow=@S`=Kedbh;NkwNrHZXGawsY4UyI}fzXAds# zb8|#i)qVI&xmBs&n;v_>A9(*%=eH-`6P5jRL7UA-)@^!w|NBuz*RNT3 z&u2?hP;Ygr_vc;nrZkTGqg8{6-&I?DWZ1jkW^KCp+u7|q+_S3q&58Fd#)^;M6) zo&MFHpRPY`&z9Y{ZW#Q1S>&fPK7HlI_jaFp_2a`E&zy{QGr9X0uDYeih>WNU9?e>~ zr{ju;53ldJs7KSNzG?G@KHB>3%O~J3g`Y37FBO&!&${iBo7zlmn3eqFmhQVtmi<5W zz63CeB747wNro^PNCprhAPf+cOH2qihzXY+m_X!Kkq|;4ELY6I;W;s(D;uIDOv zt=FpSwcZPY93FU|>w)K@c;JEJvGV`Edet?ZkVJ6f?r;BV!=zq+U0q#OU0wCwt5>g% zu5R|CWj(Coz5M;Nzkl?W3r{?A^OV68o{8)_?cP7P9{RhRM~=L3%9+Sp5N$Q& zU7j}RnK{9S-+cO_^$%E2{&3GWZ}s1HcEA0C*GG+P)p^F(H=~|ayi>XyecYd-9}oWU zPmes?^Mmtl{pagbJ661(Kc#tU;Ml#7G?{~XmUt(y;;3)*C9`u)lur@fGo{Uq1DuRU^+XJ0tk)js=~*ef_zAo;~}P{*Qg- zpKMvfn(?_=>k41EXW#a7%1`Wm|MDHHyf2+R<-C0#oO9|K){`r{EdC1L+eIo~uj5Bw zyr)}wi;`YXy>ii`nJs>>b0!aHm41X(d_k`D?K2p}bdxJ-t79PRbp5&S}R?dFSZY5W{aL96MoQ z`56iGhm}3P{i7Ew>qZstq^Vz?Q!(Mm4`*I_`n{L@(0^B9;U~Ahd}rJ8;`>s!CBO7^ zA+~QxWO|-szwNl`w3X9Z%$)G{+K%TR^~Go3c8Vmt`N-nVdnQZ^O`T*}3sk(*EB6## zoBd(gvZLPo?7E}F?Z3UpdsF0=tz9nL^>xWL$De*Wb~IJ-zHEE+#?SA1b;pt)fBL7l z`R1|bbU%LDygRPH@Va+zXxpr3kM`KnG{EQ1`Qv2+ui0?oy0X-c&sHs2wa<6q!`WA? z%wDnT@y@jq%gx-tpFnRoi+$H0-j8?Z;czkml%kaomhB zOZP9}1O&oX2#~c&Rf;jz4xWvxXB*~B_U(<4Bis%aba zX_`JBbcLqR0(}+etq7;!_eV`%0s3~(%Ms4Q?+#7lbGNpE=HbQo)T=eiju7X)HJt|f zNKM1_h;@{v$AV7NG?))-Am~}>2OkDKMAI04tfMuJS7nXR^jDz6n!W+gy-?GaqtAO> z)5oGN0*6R`UPPScntmE|chIO>Dk~EoK}#?p zntmPhbWLx-y~k_%MbI-ey&d1zOie$CzA8`Ce*vAZ=?dhnOw*4eez~ScArH$my%F(O zXnF$5aEhi`&lR9wMIDXp9IAP@HB^UjHj`IWV`AXvv)X82=UynTd+en?40#DTRC&2q?x(Cu61loCS zwx<7pI1@DeEXp!b)0ueIBu(S9v!-f#HRwd}HzBlz2`E=U(-T2A*Yp(7Ei^qHbdsh| z1l<+%bnr$efu7V3Z4~t5OkdLvf}WviKImPSY!qW?0iFgU->k4Z0LG^EMjs%QQU(^qHVp z#($!W=Yw8@@FJXFsp%U~cWYhr^)C8vpn2~LxaTcRpAI_lFiB@5?rpB=e9$d4T@1P% z==%}(NaW!#(Ckl6z;9(od0+Xswo21;K%cAWQ}Dc~roRDwo~FMCeZHoD0)2s|o1n~V zG#v-}LQOXXeUYY{fxcMN0nnFdn*8n`K(9xB`A#p@^ia@iHT^fx>omO?^mUqk0rW$l zFT=fw$p6EdZVCEPO?LqOxTf16&s#M;0Q57O-T?X~O@9vh9ndMbuPxGlSJNq=_h>o` z^f#Iw0eWa>YGK2xzDMKcn$hc-9M``K)$`^NOa|fqp~N?8kP3=Dqx0J^{^q zet=HA@yNrlRCyOy;r*`aChc~B*RqykFyZ^%j5tgC${1RNd+y4RbRNSv_;r8z zX7@I+tZzXVFYZJJ&O`p=-(;#qi%b*H9}1^pLI z=YYOP(~CfF2hF^#MSVV}=~c+XYnr|SI4uDfhxq%h`2TR>U%KM&ap6;j;9lGZ*3`-a z&9?dm+Uji3e0Mu=K1b6XQ8v0XBF;8BPt&g>&U{U?{EI+yT>cz*31}YEa9*nEEYM{x zyxfH^13`w7xI#YIfuj(9`;EJ!O2Wv>5SNp@l)rQmgg@FO)4v&Gk?j9zG;2?&Vb?GqH_4oSutbk z$Qf`dhaKv3CV@=v*C%68pNx$3jIL&9IN z0+*MniM_^cTG&daRO+Sin(N&8#ii-}(i%J2;)0?+1;xdUTmD7!OAG2~7oqOU2My>k zW7>Rd_-PwSJ`r*Gc@ebf7-%_uJ@DVu?v4&k=CEDx=q06Qf& zdYvxGFD!2C3dIf^jh!SqvXUbBz-;Vv(F0;%oBTzMoo?Zx()_-So#fF_6B_UPEG;aU&E3U*)ygsa;;&dcWP!CwR^xt9`6bxQYEfaM4?ZQO z`HjzfEg#TNgdBWFGbX|tBK!s!pbz-H#;qHcp^=j;E}y-iu+fJLm~e2T>R+{$$K<2M zh07YfTEMC|a!u!#E^h237cIe}W{BiS7YEEBET~y5pA`-Upcs7$G*m)XBJ9J3@>^@6 zo4DjqV%KZRZzV$ivtD6In(|v-%m;kkf$^GZ%5UX>+M}@JG=<3lyJ|*i!Zf?`lQcW} zm>qr1j&9A^mmPg}Cmv}fO$Qvu)HB(T;Q-o-lv}vyN?fo79K|*sFq{*amvb<=I!Nc5=g={N$djW zyL>+H;KWp4Lcp8Q#2Sx1M`M>cb>#~LTJ+)t{(`QHoKp%UhT6FxP7fh}ksG~UJSr~E z9i3A|0dL4j$qD_|2|<>YvvwVwJWqyn`|~(i`C|Xqk!XZc=`$+F%!I z%5VMAVCxL_sKFjH*f$3I-e9xP*5w&n6tOR=k=f#qlG&5E|D8W-9X zm+?*XEq=wB;pnmiy9&SPxDs?3ufflVV+$??2A8ColnI*?8%_k$Co@j$o9q@ zl`L77J=fXaoHwHJB1s;Xs~e9ud2NH{HC*j~4n4iPmW^v{gqWMh`G{a9sC1rM=OCl5 z&mNT*Xd5|)-)L(W&Y4kkKJk&WYWD@4iwv|~K-k^ys2iGi3sh&oVt4Dyr@@gxp5%zd zoJR=7teqz3UIXzn3AcA;f>V?}uXlj2iMOTC8}Rwv9Tw+$@vxQy+&zy<$TxxsIX|b@ zc^a>Qy-rBwLH=+aPL4G6I$hA~V8TVsBC|M5jI*#TF|+bEenIpUnTW$?Gr^;p4Iy?Y zY#I|hs%fx~$pyq$KfxofzCEz%!1#K3XRX&O$#M((2_9D1%%Joy@mBG0OvGA)gQwv} z9$gTJ=ab4c6LVA%n5Ulz4*-Hq2mm zg1QJVFVVV3Qy4d@&&@=kKEh8ihZlokinB5&O`T>}d=f%d?5GR~8Jp~?m8r=^BH1cmZdZp>LuzPQgOLHFgC|TRtOt_lEBkU2R<18wY)6OM1>*yD^w?y(AkG6i z!S-&kD>o$D-mP}^;UzPEE6uM(}TRGKZ??%Yt}h#`>@9TkYr*&cnbF zo~LqTXFR1ayJ8cwoHz5tjdrzS#srQ&%S`6VeI{cHEY=_gCjjTAu0ciYAMw1@I}NTQ zKI;H>H5d(46mB-yQ?NU;Ug^xbWN&zss?{-|nu2wUv#tTvQDJw33L&d;%3S4R3?XsW z6Tm9enD`2)Qxx?!C>m(Qsi{Mb{@{F3R-qC=y@YNtPEFhj#x{6?ikAlJM|JgRP#x6M zaJLc&?nXFGsm9p_g2JI7x8A{iJlRCBE5 z5O=uBQwPtLs00p?vElphhKK8}DhZD6T~!jDu;2Frl|+umV_mPX_V`4G2gj?Y7B4d6 zdq`dE;#rICsOESc!ujxEo*HMR)Aw1Uf{gDTxM=)^Df# z_$bhGg_{Ydtr2+o$c2d`z|Q(GVpvJ@{8R z5xPJ=;9!y)5-Y`Yd{7kFoF6R<)d-G^IY){^SZP^7tOFipJ_Ap5@wsJ$dBUJr@Msp0Vh z`wDx2i)^ZH_5hHJJxC&Z0EkTsqdl8eP&E@a9fx1w5TBz9gGFq2!Xi2nXW)JA{n$1Hu&ue?-WJ|4)Q}LiiKH#}Iyx z@C$@|)-4Cm1N{3si5jd#8Y-;jx7gAe9i-t*2<4EY>4C5ts(<|NDtr3>aM}C*50^dT zf4J=Z8m;WT(K)?{r6s*0$`WbAH z!Kmevc+@ONUM?}%Wd{4gV0#Sa!8joI#%s!Ng$$NzFdA-3ynY5734U-AnAb$>SWWq@ zYd}f7>on!J?l2fRNXg$;gFR)i+&J{RO6HiXDZjPXU_Tlx3@PJc6)#s)eq{hE7|jAn zL0$o4vtGpuYszo!HrUq&8wGyi?<$_HDZllJ!FC%gGXdqOVoiQc(C`kVX(^GUa$_HUBEzWTSzUpM1Rxv&BG ztMHe|UoMxtF5e+8bohZtUB{rgY6<1vD0PiiPyJ2mf<*h9)Yatxr7kwrpO?DWw0@D) zW#dLAb%`uA3mvv|{F-vtPCR67qsv{cZs3=74!?@DMLF}op}dVHVg0w1x3Q$E|CaJL zmL&DxQr^aro_gc^z0k-`r2N)>276Fbex=)%c-sv|rdqI14F(;R#-No_l;3I&2}k15 znn0e>(_noJHr!zBoh9D620Pzi|1j7tgMDkT9}LC?fAZXRn(|wR8?2|n27{LiDcR|0 zP5G_glfP5-a=E7b)(r+z+@Hvq2HRxf*^rJpE7>HhDZllh!9F(FAV^1-sCdIP<+olo z*y{%C4(Vuviq~6HervPAo-kMnq@y=fybhYeyENE?21|f+^pT1e(3Ic0(O|b24DwJ2 zFY(_bJ1L7J8Y3htv!lq0&aoM*vZ;17J7p&_V}+xcDdDJ{3|pk^UeDQ;-+M~hWmji= z>?&ZDdy|%W?Wi?(#Fn^(q1LWWqchgqTSldZ&?c;~OfA8ZDXTiyqY{gp8nVg@!qJhK z{@N1mwI%7kmybY%WM{T0`i#zom$PEo(M&TdmhD}y zXT|olQMMM^T59vikjIX~XrrbrR99q4Y@z0W@I3|W>XJelZ`+Uqkw*GM^X-~1;T#ZzH5}Wa|8dX% zbZB_~M@%m`|AQ$2951W6o?}$%kUE$aH7;Uq@sv8J#$Jv#HRf};5EJtlIY)3l=bDx# zf0UM}zd1tPlmqWa&5#~34_xr`xEx3)tG_j)MtU@lQt5SeO|ncU=<^=oi}SWl?4H;o z@mQZP(5ZZ}J z9B2wVx|-%4^mu@0k3`12zGOU!OTzJ_iG`)*3(F3uTr||e?QtWW`5t%Zo*2><+6+^p zF@rHiZh>=jvsQbw?$!7;U_=H>raqVqLi1MUW~@FIAs;`-V2ovb8owR*@sW;c2b-8% zia-*z=WYP8sVFIe^D<8Y;4uQAOG20~sQSzAh%+O%#W*e-;U`q}5uE9Pu*p~+T#$aPnPx6fMn(|v& z=$iy%FD1{NVX#>S`>o$U_c92& z|I@uao7m6y_G~Kq_4b1SnpyZ?yRW~%^!23t);;L21;c2eD8IGIU|S9Lp27ZMFwRoR zy_}_z^k~u`SZhsTw#Z{t@*g}K7YOps9w$osr7%US#ygYZ5ru^1G_D8C` zs%KK=%{AC$O^LNLY>_pOAL6=#s$jS(Dbr-q1y~tS{+~>k^lA1Bd zHPjSPXDTkc5Y!YE&*8GqLfNO)>TOR$EOG)T<3|S-ax`FTPM>S~8uWX-l*z+SUh zw(?S}Yit#Q*gcW8?W&$J4klhcJbHNWaTEd8KTFC>3JMjUNah$Ajy$UeF0luW@xUEm zdlj<*q7w^P=r(N`i1ULr1(z3q(QaE1fwm6Ub}{1IJ-DVV6djWx(jj9UR&QBbep6z- zTiaTfuSXxS)@=dy4lPFcHsj-4!-i%M&RKeVs=D;F?9T+s(oOK_(g}<9CE!{3IS1cC zZQB{}J&~5cJ0YZ?z;o6K&qMm070L4qgdv1u^!a>!PEKu&YRzey@>^#btkPh}w~lwQ z!T6QSz5L2a`IUni!JaZ0XMzR0N>l&&uj5-pl}|Mk!v%+Gy27yWu)4Jm=TL^AJLw^XuU` zzaGdN>g(Y-zaF0R>v_+7J)~fXV6f{n1xo~j-EFWJ4fd+R*q=*!pBU_Zv^l{Z)|4NL zp*OOtPE5|OT9A@mRT`R>H92ca*3>L2lX6E#zr(VcyC+0~O0_N}=L>0vod z(#k?4k~!$%)Chp2Rnu^$?3(T9b~Tu+M3fN(qdq|U)-YN)3awIj==!8{y7T79K2Lc7 z>L*XqD%6p+t5s&?^Cp?!Z27jlSq`5-lalN$kMF|~#$une?C8!gR`U!Ro$)@dm&a#C z-`E9}mJEGZ>Z6iZt9R_^a69?}pL;2|7vupp+V;?`Nvo(A;^0{MUEI=cNu8|7AgjEU zy>FXc#Tfgbi~25Z*~h#543o}bUpcz!@X^stSNv6c<6SN*-Ll^y*7nziWD zU)^FypH!8EY5y6ix!KVZ2W3YWWM)T8?d<4#S$SDAvrfvIk+)IesJ~B5MLLJ6zGgG1 zPD-P7Dk>Kl7)Oj%s2 zcHN3?bfFd%(PlUc(!9r-zgUf#W08^^J=D0$!MBG3Dm+D==4j8ugX`4|%W4hQhpYHg z5&v)%f2F6yBZGAa=N=1dMJMOaQ#Yjm;HQKYH|l)4d8mx|DTuyKU2o-mX}-CwlX~_NoOe>UMLo+r3GUnSm&us)|khSwzL|s+4w8 z?AZk>!>sIGDsmSrr%X^7nU+$8m2!I&mAeqmS@8_%Kb&i%BA^EF)GG7Pdiwcvs%vJK z&qXRDmFZ|QuHC6(#6#sZQVFE2`Sl8G3(h4`rOvuw>a1aUBO~iXCYc{MnLjy?6~nzE zi~c4910w6(cHZd)EiKCH5 zg5OCa1!=eqx9LaHmmKg{EOMi?g!cJ~I?r>$mQc!hQL5FcP+*}M^GD7tmqpb_tZgJ` z2BCB;3S#wvbrW*QoU+8}cq((qlFq=7me|ZmZ42z07S{s?f^`k57spR-f=7LF!Qg77 z&QEHBXBpI+!QdL4hwz)=(VxsA0NG#j1x@gnPk`{+80<80J|hH}Ep37aEv*HB2u?x* zfa?whSw^-PL_mw7Rxk|+kNc4mo)^ifb&o#Zq0jHdxsfBE)gS}*L3Bq6o><9t#7^{D z5%wM@A*6YDKEe|a&PF&J;T(kQo#8$*ay~-1c8{z>xB%fR2p1vz8eus?epO2m#^X85 z5prg21wu-I#M>Y|6=4^IXCP$rJriLj!U#f22s}Rl;aLdT#8)D`8et_ue$z7%Qp@-_ zelri+is5HE+gdgV?0Q|j!T#pn&R31?YaTdFC) zb(X=-HrTZWyU}2G84Q|Wm9pRByOL-8-C&g91!ET{&*eK5><5EEO3@hKoW!HHR^s(F z*zpEC$zUrDw%TB{IF)-ZGuT}QyU$>c8H~;+<+*Pg>^*~hWiZaOO1$=v<>VQiH08IB zHdvOyjx*R4gJA`UzV~#4RT-?>V1GkDHBQaUZq$_DngkW2UJXUB1*fy@xl;8ToV0#SK3g5NFYpW?`UCOrj5q@f(ph|HtnTtA_VtHQnO3{?t4E~{+ciG=*k&+<)`p!a4?1Rq4M; zrdhFv72!oxvMh&6CO2;*g@#u;Q@L_0s1EqR;;gqpg)nTy7KZ2G#nxuuzCtW?rAhU9At(C(0XC-*N z<|=+G%Y!o>2};ot0#$=|i}7k}6+6c%;-bFK5+94fdkJUNsnpbh&qr!MKz`FsQ?HdV}$e3dYV{o{?=Ze!+sxF<6no z*zu*X&nvFk=b@)~9nLJ0=r(2)>>yx~F&zcBNX$wC@nupn`dNm&p7hsvwzs(ukaLsn z1MjSQ!-?peCP6Sigc04kU$w3`oNDjn1^tZfNz=A{m2@T+B`fbVqf)zze;Te*-onXY zK3tsCY-VbcQ@h)hr=?~l*-6Kejy4TPpEQQ-&tNHZ(tWSWqUOr)la}_k_rWPnm=QPF z72l)LTO}Rr%Eyj?naWObA_o?j4GUvHTOH?V5G4%8(PIn0KlT&BG zh$WV!eNagz-G`n&jIP*ONgcf^bqxzwxv4mBBYAe|m5&DXDWv2$YpkKB8fq@6_0X2a zS&Kl4@~;F`q#3a@L5ZQt^X4j-(a%y>*@jL~R98^1cjg^rE9L59bM*{RHAjQ1np)Q4 zTEhGq#G=}kAr)wHxJHBVaO9!H*xda2C8a}#z?fw+T!D!4*rj8yM_*Xa3SN0kZ3iO7 z9(JW4U%;+($?V@@lT0-{#3nU2s`HqxzC#ViK3vNRRr!#LzJd6mZZ8>J*h;~!FP7UL zl^BS}#vC!lyf(UMR?(OJvfE(?_ou+J-J>dw#x3p(+5=1Pk@Mfh5J zD{N$=eKSOf@8ERuC%2{BBWJ;JUam`Yw^8?$Fe&qLC>^cNz3QBz{33N8uZBi+{-~Th z8PhnPvNAGNgudXqJ(gRbQQ4wL^EMIJF;nJCHKeZJ48LKk~M!eQ#P~AuFbZ`(CG}BOljO(~(c> zuIb30gR1F0ERL(Dzf|Y3nua^6~Y zd>`&B-1!Apf|2{(j12c>!CX`1eq0K~vk@MTX5_LFV;g!zl`MdsRb2SQESK0U8DpD@ z(aJOix9cn}Ku7A$mj>dK13k?udm3uFqtQ!MAU<+-VgkOaRA0SryEqnOw6DRAX}4XG zOYodlL3cCPe!C(!K=&@Fln_jZU$cRrv416}Re0 z`R>9MCoy;EHqzoYLdZ|60;dbOp^fOG+)q!(W4v8Zq+#*yj^ssV`Ec(Mi9LJ)Z!=tu z@8(XLp1gdaKsWFX`@150Ugf-t+v$%KrUoRX=;9>cgychuRqe|k@&$6xd%(NUOAW*+ zcTr;J;&>ms9`p_PvB+$L>;l~|#xbqHo*_nbLci7>V zMc%pyWfb1p?Y$sa*3jf#cQ$j~TZH2VawlvmD<9t<*P;FAv-c zwOw;v=VY$g8>Q)c7;sFU1<}+CI#uHfpc3r@dLhDcT*ug;lt=4;oqo{DqknC1uccdJ z)6u!C9XO7O#EAAkp4S6%q9oqII7KUx11Z1S14OV(QAokA(^R7MCxdM=*j9s4N|1Xg zCCI&N@eT!}Dp0UH4R(*g)*Eb-!QL_02L_{&y`xT9$&+VZpzjds^#u@A`gWYGa;ox8Mm2zr? zru^1&P?Fwhn(|w#4R)TvE;AUpV9DQ|2D`^#G}Z5_lv6a-Cj~t;F zBm9&i$}DK^UI+S{l=lCDlqLpD^+{=RwK1f$i_jM5G$5tXNJx%fAf?r?g!%=t+4|pP zGuC}fV)#uq>;0Q-=F$Lgk14S0zsY90kNQnEtKla4H`(kL%Vzwtez9!EaqC}_&7dkr zi~gn38D)jiUrjo559$XmlX0HnKa{@%lEXNELo;%b!bpkZTEVLIRX>&rI`RH!um=tH zsKK5v*mi^c0rHcicZH^~K-XY2GLh$UB46S?Xs}ld_IHDYAZJOuR89HS?w^9uiIk*A z(O$4PP5CW4t`&@qYb9RDV5tVnG8mV8NxX9ncD})`Fxb@wYY&-9p3zBDFeNZpmcec^ z*lh;u2mZ7`NnwLD<+m1tlJrV6<+si-*jWZU-(ci&CC@h*>^6f@q)Js1SDdD>;{vEZ zD2)3plR7vlEOQd($uKQHiu34L27%cip3EX8Zh4h)=ccq1H*$Ks8VxNrk^TT)?UY(f zc`wAmyeC$zVh*`3ro865U)NlT`-4>q*R6`Jb}aH8g)7p<(M3%gWJ0y#@~WPT{K(M- z6R*RAKS9x@J*ZE{hB8Wl&sD8X9BNv%tJ8*U5@+EKPN46CehX_I3iC?}ipF5#rwoq~ zE5=wKC{~O`xWmzKo{DOq8YmV=q+`j3g*6GZqPB6$6348lsa4Ab%2H|v;cWm-2gH(T zho7os)V9q6&e9+ODNPDM=7YJ$8U|OcU6a=CO!3`uB?G<)D-}N;J1i^0_xTP&zSDOR zvhz6)EkQaTQhun}9IQf9el_te@zxq_y`~bCWt!akfx)Ob5UefUlibUxJ;9ze*oy`` z$OgOvnT<8z*N{wk0}YsayUO8`Di5RqAJ~$Cum3-3;42QefwRQ_#~S$Sx`D%7PBrj1 zbOV3eG;mU~<%VGE&?E$VSW}7CdV}pS*!u>fp`_f)87{eZpuvV3Y`4L_Hke+RjIBAs z%A~$(a%!^Pq+?c2^owk4$f5S=$oLc%{UO?4b>E2xTWe@Nz%ye%0P}sC5L7;m)ok0b zunlHhFfve))ve013eM99Dd*|fGiNf4Bn)3WIGm*pG(75U!k9j0G{bR$suGPjsGYALfx=K&Zpj7t}FT zp!(iv*fwcY;oN-qIB<<{HN2A7;lW#y@2)JuXd~NQ0hhx5HCbaG>k@^H!+hhwx`sen z1xQABso~B&Bp!khtN@nA9$M8iYcfo5V2zE6Vtp_b$%y^_x5{qoGCY-|rHmFO;=F-3 zBA#`e%93b*#sHYC&L6?^YdTVNXvf7p#0*X0j8^M(xF zF&x+Bk!zh8?)gY5^8C6=Tyel9K0}w79z$4SX)mi(ds$e2sTb=~(|Cfe1Ld|6>Na-? zOvx+Vs401+Q!a+?_w1B>z7wGh%>Vi6<%ZDT9wtA!pC_Xq!>C4O8|yrsuf(e zMJMgQ#0h&H6P1M4AW0XObtoXVcz!GsJT*QRdR%84uI+JsJTM-d)fDcElCiBY`NO_s z7D`NJYM931Oe)d`^aTh9BV2=!U(ZDd|A6pfglvB>q*n8pJ3*H>hQxdTom4HExt`9$ zagNUFlB4N<-@Oxu_2$I+`DxKF5cNM+-gH>0*4bG)W%>7&w+HHhZH8S{>~L?F^UDUI z8t=F7ftR=I0leR?>N5_-va4nT^{JlrrVw$d;ju{ht*F5`dJA@?!Dx3X*c}GD+hETd z>}7*NSkce;&|u`ix|DjU8q%F13_+9Mj~v6Ai`zQm{7-#+hfqJ~h}E21{<@ zq}N(ge&tqMo-204)_kzLRHrRUx^Fd0JdpT<@_qH(@XRQSrgFZ*%k;4&;{g7aD z4E8LjZc3BzqNe=TSQv^5HeOTEY8b4}B#Hql^q^jv<3X1>|D)n->y3(cGYO-IO%ejFVgs@&lLznNTF z82ZVMRGR*Y~ zFT=B&q=p@VqE9OlJS=x3!g|-l*sgZ~ALo{Kx!lrjI#)5k1b0(r-o_)4fj=r9mf|Nj zWQwy!gSuK_csYt+#Ta3Yti`V`!!?YISeJ+eR_*ae9WH(~Cx1aT6$_p36 z#qHDrt>NEke9&1p7zDGxE&N()rXf=$BYzSMoeb?tOE3-i9IUZ;+MO`#Wnvulrvr11 z`W)J40jjg!OhiTJv7|%Nc{|R9p!hL#t zUkZBSL67fsywn<$F+yU0{D$d|N%<`nU9g3kf^CVxPBR!kLWy^k!EQ3x zZ3cVJU@sZ$9fN&fFz`h>J+^Ym%S{Hm&0wf<>u}X~#A#~(#ZcF%uLj?Kce^_42z%&; zrO7Te8O_U#l3D4*<2anOl`~IWo1N z*5^1BvG}<%q#>OgvV&}1)#wvOHXEG@GZTNT51; zSxNrw1|fPIc-$9N(M1T!o}u|GHlEk}%P$?4mj@>X1N!xrMw=zqixHu4 zj!OYDA!~H5>vWQxmG07%=B8&1$jHk%c1-&4P|x8ZajWwD#j1%<68}O}ImFs{Ttgk3 zeW6mT^F1;Rv=5y|-Q6_HI|zSR-c(gq>|TfWNOBQE;*0fr-DA2*Qhxedv;^aXnqYCL zX~FpB1Ur~Izu-Su=i3^g&Y8w9sq>R{otNo4FV}VcwW)JbQs;uP&IMzg3&uJZ%w6Z7 zAm*9|+Ie+j)p_o?k(1JwruWaAgswclth}T!2j5Blyh62vbpGObIfZ3KOXkE{`QI9$ z#+gRV8vhdIO~cPQ4yKKNY3iGlpT0#c!PsL7hOtLuta-r>roPYnkJa~mjZoiAk+cgz6Bx2;%`j-lJZ+O8SFMqVJ9eqeQhvz z{k{(Lj0WoW{9jtX2i{+(+I_qcYL{u$tX+J;C|~XV0?+}~?^mXNNx@JA_X&23rlfua zWBp1zHNC~fx)9A@r(oUdH9PuTm_8H5#kpM_H8m05RjpV<&fai%#;!+h;+b<$Z z0hUWyAvEg>LLHiW8M&l*Mc$&qMT?d!Ev(^$Db%xfxpvMJ!WV(=S#jCr&`W^JmI?ow z97qQx4(kZvd>91qdQ5zlo!s^HQHAUhl*(0xgf#PlM}% zR)nRw31KUQHzVwf@K%JB3hqG2FVGusxM5N-g)!J!n(|v$8|+$xaeSA1A2Zl?gFSDs z&kgpK!LT4m-&?FHcxZ!ZOA6hSC19IsmwUEQIQlM@hliuh!qM+@dVQC@VP6wF3a6l0 zNWEcilkEHHHVwxy+3>fvlCG=5)kT;}%}&nlwawn}9U?zxKlgEVbiLi{G5SV3ryJs+ z`TBFBd$NZ<9!?s$J7?(bq;pyT9$Ve-UgQ#)DTC!r#ZPPxB|YFf6cXz8q_cP7(oSAi zj^SP=Q9T_p>U)q;NABI#)n4^YSzFBFN*qi9qfEz=P8a_ zSyjGp^wo9KHTfEU5DmGHz8E%WLJ-mW0ag;o3f)XDhN8NB&w~_?dY^* zn;RXx`=hhcJcTRG!_ln0*}bp)vlV5U{?n^B7|eP&HRRq zH#Y3ET|>}TPkicT6jsFTrwzpw1oF{$H`HuUvf`WC0ujqGPol+gTC8u4t=!t{MYk05?R9_xzSRUqo^3sN@$J&UtM@6f>Ep?W9 zWHGLBGDLdOyzzz03i6Bd3+9)tP`9)91&@wHysS;dKIDNtG_m;~meJ#9^i?Ec{@9mM;4U4~Gja zPAuYxZ&>TYmhoqGV_Q`%Ty-ziaw`(LRJGw*?D=DwAl4@PYvj7lnsiSZYwb{c$GN4C`!(_P^cSzmr{30%%KZ{Ta5Sz+s`VNQT2|c9d%g8$Jk>mkuB2m0HIVVdiWYS}s0AJr?_&=$Qd+L!it-AIR5sa#B6%Ds z`aJfmdNZf=lhCC)nd#*Zq#`j7)s@a1W89&1n8e%tXQFU>A~2Y&D1_bz^XvFu0K!}DW}!`BzjFA%?`__1LhieEeY4#Te_ ze#usib@S`=WO$_IFtbKS4+@ zRo^3ooqdFJ>hwkxKuB*>QIE^5gv(fD#8^Ary)EI;dF$|IdKk0OrI)iIPq7u zF55w0R%mg#213A!Pg9Z4?Zo{E9OX>@WJNU%6`$Y=gl*HTQmDuzwm1-I7Y#Z*h!~ zdnsecGx`~9kiiNJHqT(3evx~Z8LZM^=NOEuXCxlfQu-Ne=YlPV6b>pusoxgru^0+20PSX!wrV7TR#`yuf7*=L}Mo#4DMhxR$;JJ z2Frx1K%P5FQ+{iP!Dbn3mBFeE_D6%QGgu<@4w7Dyru?+n(asgqtiO^F?hJcD*H zr2N(?CLY%k33jf*&NmpnH^{yB8*G!owi@hwbTTtrP&IRrru^2spyXak&GL*N4Q65D zTd+4kbqes_9h&l6C!>QFtXxxm>oS8~Ww7m_^3-#m*OcEHfD%exhG@!fT>?tdyG&D< zmvrZ zYIRi?(8`oy&4&oXwG;(Oz<401R)A@#Llgy2tSwxacS>Q&5-Jr-3(IPX{7@p+$0189 zNk-=fC1Z?XCod|8UyTdSS*@^^&X1}*yr>$gJn8|#8aUJB@`zZ6+})KT%SrtndJe5S zz-)LcE5ayIgzSjp)eC1gPD(r&3%1l?7n^vO8tg}dL8R9ARt~n3E?K|Psrt2uGPYLL zqoJw;ABvS&yXvzs`Hae+4T}i%25MBjXjw$%L5+u&M09$P;yK(pXSG69D@}x0mBMkU z1XyWb0&2ZYS`WxDF(Ox2OX1U{|_R;nr4ph+-ta1xJ7^3YVh zjRf?RCnwtvi86BEnOL7UI_bXevU_djrV>LROFFAJs+U%4nRawO6rHD~+Tp4>sku4T zscoRwvn!uSvWLE~YzU0gxVG=PkLW3K=+0%(KF0N+i_D?VVgbmj%HQtMN-x>puC}3< z+?sUuE6CEW7WM-Octo(%=n?8uqaDpDcJ*@TDE|Q+<*|ErwI_+ipJ%OVMIpCPnAS+Lo(%pq8T_jI#Jq( z^aC^H2!-g%Ce1&k5LO`t(1n)D&QP%~t-uquT6*X+nZBbqxw04rhFQUwOXK;TYoQT& z48r0z>-SaxlIG*5BiyDQ-xM0AQEGW4h52G&)N5vy%qw*io5!PC<&do`Xe}fC$FZJ) z(1*IzjAq|cDt4&RY^iRX?iuT80#4Vh`~>5zwVzZFQAI}0AV-e25NpRGzsFfuD!mVN zVWNMvJu`5%!rGwqK_2*I=5aA%A7PENGIh`7;PLLfL01{G+M-T3Tix5)ZpSG=p8CrPbEWV^UVN*l!adBP*inH!l&mqs2Izj3p*q(Fr;k&ibd+O^hT{? z@)sAZ$a4~=PWo|`uqcaj%=EmxEH&TyqpFHAX*b0WMb$ zinDsUa;p`m%b`bUo{*RXUEkqKdD^78Ql9?tNLO4(c^X0FW^vG;Cc@uiD?~RM)O#J_ zi-u@*YfweiN59-WJ^;V)(tdBtY4oB9t;2)pwd&?p=JiVxo(FBlU@Y#ErAW0jsjTTc z)NMZXJaiz{VV+bi`Z4*Q8qAcoczVc37q7N%FMAP-66wIr*gv3g@87$Yg1*igl=GB0l*N zd=xA239;h2fJy3VHsX%1p(3RxL^LD+@7y_ew=?ZNH7>F<(4z&^W^RQWT_{4K)+6!_ zF4UoLi+rOLZV5`^X0|-3L*d3;*8aNKpxM!&DjbtUDds1tm>KGQvS^)ALC6PsrP$}F z6mEWRWFORR2`+V8^9CCkKNqh`EvB574?Y=;Nz)o_yQaF0U4>uWDPHGU7|B=D{Zwsk z@4@54 zYy57*kH@twp?yPmBSH>he?r(7;cW;xaQqoz8Nxdd^2@p#;nN83L-;1bzard$@P343 zr5-@YX3O($^m!*d_aU4!gS<|C$-@YTAl!hEQ{#^zoQd!zgmVz`dA)J}Cy=+qB$kw4 zO}z>Bs=n&C$ZrY897sGW*#+ZVuwWSm1GA{HNd}u{urm!tos8Ujfx)PI6zs1Cd&pq# z8SEbh+h;H@z!Zb%~7Q3lH}*d&8ZGuSBxJHue-8ti<7y!6RN9IcHRZR4f~S|fkh_<6KG|T?4VF1+D$Go#atXqIqFYY%9hc&S_l;tM7WVvwkaY&ol+KMY1l3mv3xT6k2sOwTosH>TvB&MXh zFmf`BA|7fBbr%K|f^^p%oBqv!jmb_F%hKW<=fOq1+h{0ut0KT*#MV?_P$KBDQxidN zq`Au1BzHtWiO6?0sG1_*(apHR;MgFNH%An)sBvQW7KR`>M33~VihKk57Y<18KfADR zem_Wg`Dy(J4k#EraPWY%0dxBe7}zgOL_Tew;xdENcKxDCsaF>4rnt2*3e`=OXs%~E z1Sf}M0UuOz92C~hDg8>%G4Rz-S#Vft-Ll}hp6ig<7W5_Ct-n|+!J#;^;C7WrvXTX7 zfu>BCiJ`Z)EGScvj4ZY_l%qKLMVHYhdA#brt~fLIr4Ls{A`AO>74H)3B=Aw3z~S)L zU19tq?tVCaHzZGr{_r%<0uMI;Y*?OLq0$a|+CuOdk1|iO{;C8Aa%zXFYYRQIP#>$T zcZ@(mwFNBi5WAN(9TK95>KVfY z^O)`;)eu8jEu1TauLsZd)-CG3@vi$C5KBK(w`Hi>C9l~>Jt`NhK$p72(sB_?hf^%w z)1X-Tgi1IjmP*sOs!p+VML-gCbES@0>RhW=EWJWKs7|qT1^8JlmiBaur4Q64mR2CL zODuI6_B`kCygx6Nu2Pwa_awrGtM*HGzQ20K((BaCZA~kZDqDfpJ;EwR%ce|Mhgf=# zx-BM_IyLQ<0E}3=#wp9silu+6E2bj_Fm&7SXtC5g48~A_)aGspN`%vZx|G-)B2)t+ zDoxMAsyN4Z4)uf@5K(OvYlP=Se0gW$i#i)$r6ZzB1(ZRK8(*i0y1-oucbjuW)QY%3 zk7o6Vs1?oY7EvpjAEb!t{?h6dQ4`eX*hjS`im1{P)G4A?v^i)Il|C>iudw21rXpE7 z5D~Srx-%xCIz5!TW=XrX6vtzL^)>ZIKEsFBA_0HmTe_R57E)V8zTu5^TuF$0<|OZa zX*$`8W0d$B-=dB?TT~odUz!!iIB7b~-4SeKV~S;kRBPj(h6G#Yq%nlsnu6`%bT##n zi-*?|Y^MXNSFoLhiyXjXf^88H4#sZ5mI5yaOAfXM$6(8yALN~4NX0!eJ*8G8Jd3E# zLB44>PTJzPNrM!5$x~6}NKu$s=k;R{QWQP`Aw}UbgcOA-f>IP-h0qa& zkHBQ2h{B}&)~9%uU^G+^jD`w=;cL-YPfaDN&qv~s^^$lryb^4o!HNxbnZd3y*i8nz z&0x_vm^G}tEwYYm}Oo|~d6OoAJ1l)+{gY?i^w47S{0=NW8`!R|2F-3Hreuq_6o z04#agWw0L%w$EVP#zEqB(UjlfHV%UIHP|wPVJ};C)o-0+u&BXy80>w6ErI|n>7A@8 zzg1x{nmh2S-@3(Mw;Sw1gFR}ncMSG{!M-rq9)sNpL0O)AkEZ-UO~IhXU>gkfw85S;SbGS?a&IS1`K?|CJIY{F40gQ13Jo^jVD}|pauHK*iPnRf z@>_!;PsuYVS&{NvlMOcAV9Fz8XmeJUrKSi+*mhMGCjZ9f+EwFn?aEVflb0>rJTl8; zSDiSWyU5S8qa#49FPj;Tj>yGgg=&0sR`!M+P3V*^JA3HXlGfbZPfs?AKh)5P8^h5J z8P7YY$f{ew#KN0{66{Pod&@|6oXE{a&N-gA@kE@6_;@lXF+NxZDj!9NvnoO5DGF~@ z86?o|W{9VzAh{0LQ2Wr6V;`V)_@fS&r;jo7mlw{V*fpuJKpBMBm>Tb$KESo`+QiKg zCj(1L=)Z2{!a{f^C~n}s@#PB_nppI8@1wX{bK( zM8~OUd3j|;`DKbNj!jvv!y>aFmV$S+QeEo$uI*tE66Z^7iYc^CU@^M22z2U0y?FNy zu2^Bj!hFeLn6HRy3W+9RA(;TTgOeOdhp;>Oc894O$6~*$cwg&4V!SWtZH-Sv+|%8y$Op6(bYE zXEVhG(&}IC@|tM`O7v<$zIh&po#E=vBdyN*PTKrB&vTfb+8TU(-TEM-(-9hcwrbWY z>x{KB2fsr6SQRwM;H%=>bnP=W2oT>KSPyw~F7AT*=pW1=Ov-QN zp&Wu0XbL;$80! z!Q!-5*->8(EIgvq5|rLrm5&)TQN>{blRN2p|I?9f2*^C#00Vhq? z+vT0KG3mZzLo3&phxvZm)$x8-tIJ0s8wsqB>gEhof_P1B>Ud4K0ne%NjBdE)9cZcI zRPU3DnvH{I30B@1qvDjQ#EoifyA+u04n)I z6^8icT!rfdAT8mebPl-Lm|?=>Oc2}VhViFuV)w)z ziDSr!G;uOP3%0sc;H*({Q51<`38HO2Jl6T@{9`=380JvP);%zvafwsPG<&6`#I97gN2QEvl<} z`8rv>JJi#U$Ey6q8c$row8MczD&km$v=syMrWU=WtH#a`iP{Z1@MB5b9}TO(t@%=~ z1Y72QEp{n&ycDJ|7O8!!a?_?pPMnt!`IhO{{<*DloIPSAj|RMLop<8w6YGAzPQ;3P z8j9t7FlP;QVmTj-oqY89LE;aTUx~F@{r8-WCnJ#m{m&#Yj>dD8C1*N?S ztDbwb($<8ZBflWFHFB}DP(kcFH5bbbAc_F(?;pPyDEmIw1`x{u)wKac1o(a%K(P1N ze**|I#24ZU4`(CRTU0B+(zO-BFsEZUa;__N+?P1JQ!w?H;}$txQ~~-7IsSmbl4IHL z5u(@@&$}SRc&|JiUV-p5oL`Bs0^wB%FG2W6gtsCDHxPLgAtq`g>>;j2_$fl9AK_Y< z8xZ2tq-k7)%BNcpc1DPMBLfls8R0~Pw<9b<$av)QcVNsHWg98KwaZ|iYszo^V6c4# z>x^g0y>#Xv_of@HzriLOY`VdU47Si<%MHdgaFQNXaq^6{2D{T>_ZaLsgS}+1j||3I zlJwf5+>#z`Q3RtcieR)w5$qy^{lQ>28tfK>HGxzi_tNLA+}qM%^f@co2?m>Ku=fo1 z4}*PWux|~PALl%yP*d1(!C>nQ_Gg3r#bBQs>??y^3_eTpe5t1V)^!H^lfmvb7&$X3 z$5RG-)?mNMQyu)j$y5I=@{~v<*P$0{Se}x2|1Nn-o>o(y>fWF{C3iF=Pw|_+s{wh6 zdoRgx!19z!UiyVn)X%4&M4H}f4qA3ycKS_ra@hUfWT!U!%d`L8 zvJ?BxTC&sro97jyANWmn`j=%VZu%&)6Dhy-3aVAGziY~`{6Yyv$x7nUNJ6lnreLdW zFiKVuFVkS73`TiM?xj2>@#Ywel9gbbn~`|u8I1CjV3emM-XjLvU@%Hi67MyGc_H-( z)>KpQFkrAw2BW3E#5>Dil&1uvJVnZH!GcI*UmENugHf`Qcw;n`XpJ@4GX{IXU~e0Y zl9k*`yL)*q?d}Dm9|ggx4R*P~C|OCozZ>jrgV8!(?yc06-@3qHl&s|5YYav%OtAY6 z_OQXk*P^)ieC;lo5y7N*GFLET9;Rv}7AcPm0ZAhQdJuk@IM3DR({Vlv=f(Pbxm{Hm zK{Km8+>It9vwvuQYSYtohi2prcs z&}w1}_@hAsRU32VhN!KI>40x(hghw~P-b$<%aIV@IuE>B*Wun& z>40nhAYPQ?L}(7)c`CPE7#?)JHpe*-UyU4z4S6Uyt0nYc6N1tf|Bse2=A>#h@ojCDkIT)Ra1Uz4n`cosI(^q5BQ+oRPnH%rlR2Z z2TYG(VNGF|X;2@lcxyG~w|Zlc7A#Fuei-p$b9EJOrKYg0Joo{@T5Ae<0o4R!XQEZ4 zDZll#!S))=27_~iN-wM_zxArY-Y^(8DPx!Z5q_9h#gvekBnS!zDhcWe60)jlUFlx$ z6}#RmMfF^%*svN;P#0+=UGD~Gp^WuO)7B>iVcL=fiyCYRp9O=Pk6|~NqAY8A+R>6^ z`)}mLaGYrm{Wj^G^+?d(l9j@Q?aH5$mL=O&CnqN*kG7D`N9PiaZnrD9!SBp7OMBa7 z(|APGzDqUtV(RbSi)q)O2O+rP=I`vGPrxV5_jdIJk6rN{W{a(omdeLiAgvx-M)Iq*v_~+Qepv#6j*&`VGw+cw8f_UDfC;F-X&`=tvk)!;Q~5Rgv+#khsl?jhfg{1C z%fZixmN*?1hTP)lr~bYH|1(`6-L$~^%493#%7FIaf(!&&rkh8*W9TJwwPN&frJ>xl zB&$Mrz3F&~&9KZVQN3I&$BCyK>!Xiy#aAv{;1|0xv6thgCFt#f`|yhW0bf&Jvp{^d z^NJf@9mjXKK^1Wd-jpnfbia>!SI5bVvaIvf&6$|qK0>#Ar*4DlW0|Fdh#H%qU8!!7 zm2vJ@;g+=Y%DBWxrBjZdSs51}d9kjTj{L;1jjIav%D8s(14)D2etxvimih46g5^+6 z;3_()_x>JPoWd8Yl8i#(JDS2v%cT`?td(jnEJ=}d?)62r;En7E zc+se#ZxMmez07YWJBB9SBgEjODf3H(9&9bN6%g}F8?K%zzn@}(a4Y|w>}#ZC*San`2V{51ejN7G(vQ>3I^`P2vE3lSPFcNm^bO6d z$Pu6)L&$DzBf><)<2mE3z-TI5BPqZ2tifK?lsEv9cpS1NUOdteteK`nnJ8FigWX`_ z-E1%#PDnhe{3N}14EBM+Xx1t5Xlf$ys0$J75KZ}EujgRh4A$RZ*vektOVyy`8-BNhtZFl2Gnl20mD@Q#Iwc)_~_ZN^#DYXbO%;KuJ7uL~`%@2HR;cwGU8iuU$I7 z2q~W#q0t%NBq@$G45kvSC<1V#-`QI>k^@cZv=VIuOya(cqXzYBRsOC0C}AAnP2Wm7 z=NVozyy*`~%MRh*LRH5nD{gSq>V88%Vn?s^fm^|#ZeH4>9tIUg(EY>J#YbdUez+sM zYRukULm$BRhdXy;Q&DiIUtsr^{khZWyB>9MrwQt*;plE;B3uO@8sJa!V9dVVu39Gi zDg0V=M4H_1h`R}EzlGpfHK&?Y(_di;av;noRgcFjR`pF#!nE>fg2kahOT6BoglVOd zi<(R;Ei7v@tpgE@ofgA%bUt$Y-(*^AGN|G|p1c_pggAVjkI(~B>qg)IU|OC1OKCqT zhq%j&4Jge$d$8BXeAj^TBB}taYBpI_{95>uz=F1bXZ&tJ>157fS=(d0a9Gxs-sZxp zB5rg10*IN2(2r2@L6ZXUUH4;Oe~vT#y~=ZpGu@)jmuSv(wBk(3?M_noTi{STS!J;5 z70%Y9{p-az)5}%7xrQ^P5i93#xZJi5&a{2xa&V^b0H-YGbO}e! zbg{1U!xTpEfy4xqj9iVE<;PyD9?Q*hYOWLy547wdVxYDt8aiy2THdlKO+>a}r>hNek&y{kZ;~w2jt*QIHiw3z;vb5{e%`vW&Y^K!f zp>=VkbY^+Gx<$BB_iJ$TahfYlh+OWJ<7c?igvdYYis@#C>f%bz3?%ihgDXAL#g+Eh zpDT5?^f_CVWG)1|PH?p#tJ>TZ;4YEjOtGLUW^U}xlf!`iPBWiw-vQ3G$mcLVugRaf zlc2e;FBE8+9%z=t$GEx6=W#9IZ5L?jtB1RUWDD-n*C2Npa%a8)?h^ire+TaJP*f0K zrNdp4vt%A=j_h!iG)ZRO*pt=fEWZQhaF++cS;|fpX?VDcv*eTvxkYxi;4G!H9UT0- zdWSK-l2*lTrjp~#ZeZXv3{&|9m`C>EUm|3W^cBKh2zgGX@)W~Vk`ks;Fn()-?J)7) zH<%Y`NW7++@>{J8M)p?jz0Y6|8f>${o-o*327A|F-x%zBgZaSb$#eah@>}f;*3n?| z492xVl9y8rcBa8DFxbTgTMULzo>8JHzjc2!dgORC}^vG07UOqF} zmj=5DFHYj!rYXO*-e8*y)*rk^x?&awYszme1SR*96Om`EG}vl`)nXQF?BZ98U3`t~ zVs`Y4oal1!S$lJ$`3Q1>WP^!(EW6j13Dv!ag@^7~HU&DyWw}{N$>ar-f?iN|auQZd z|RfW zhkmzgGE(!XSdwzKPWfb{EPB(?tFgykhNLlEafx>2new1xa>xn3VwNK^ZI1Q!Bf{v? z2l(SCN%qi9NoQ@xh3x3#b|snF#}A&F-6_oMM|O42{>~>Ic?>0ky21=OWuR+yhhPfF*ZDyDfB8&hmhTovCl;i&od~>)Edo>-72Z_G`lyuE>4>s{2_0whwAZuFY6d^c zo$E~KIFnFUsCkS#VP+`iBzqbX8>sUC7z)kRZ4GO9xr&414Y>?f&OCL_?c=H8ou_b$ z1j!124_GJYch5Gw+hB#q_-HvVQ+%|`skAC>ESI!!k`;^(dH(Eaf|@bKk(kEOxTBLB zqslZ-agDB}U^P6mO+l);D&EbW%OUBz_(@esCQ;Tp<(?5L@_imIk-P$Gw0)@8!FYXR z@%rx6uaByGd425_kEuP5JK_^%jMr2$N2)rZ-0(CoE?9FjM1vqM2fQ5`V2C>WJVVsQ z%@Da$HyqpV!Oqpa){QS03yyHaL!~u7SjTe1$k`AFyy|`qK{XYPEZ7=?;Ah%dT|I7g z(@``=pz3i9TViTRSveQ*&V(|Pa~X9#!I^N#S5F{^AG_a4{WK?Ww<2{0IwD_MAnpWA zjx-4*1>6eMNxbIsF5>=?0dE3tck{1hyd1!-fq>D!x=W=iwMFFf`s(Y0dP>7a%c%{K zP5z07u%(9L*eOxu1E)ytm#J4RdLyqj_%e5>s*;!Kc24coNaU`>W~xfu)upQ>vc**= z?q@r761gi7XjWI|oR(Ixp~1{;Ri8k;Ev@3NdTNeN(fLVbsKRaboCMkUM(arH3Qq_h z6tDe!E3CN7$#`9Fv*P-C-e$!W_2h|NBNZt_RG$9kxfk#AVx6A@dCL`0cFI>#mm;BJ z@P3MflN(edNM|&?h9UvRU^wR0P$ZnKuu{(^$OQQwpXF8)IEsXd!7fF@$?h1ABB5rC zx)cd0Kz)jYg>@(rDh4;8NLcQO)jzLDC{rzLC5EZx`wd2}jvxKBYfl0;Au1BG)Xg;& z2~w|J>r*6f5JZ2Wo<&81^BUZ3%uys%40g)#bBctD|Hs~yz)4YD?}j~CdPjG`13Ur) ztcZZJ2rA&ka>yVctKhAH6;>f4kljTw8l7b^iYp0;IW(6fG10^vMol7WA_&1VQBmWO zLlToH(IguEt1%}2zpq}^o9f=4VHWUA`uFSUH(ys(SHFH$_3G8Ds!NkXI(gyMU!dO( zW3~1z&SEgoWVxfoz`d!Tb!RbXo#`I#GUk@(OB;ETpFv7zK1W9gUNcJOwA^l>@HF zb(ec{waMRCIx1a;{5{ zjyZyjwJ1oVFTaTEJ~&5Oyt*>Tj==xjab>;I3s)*cd*Di~WKUeF@_Y!_8MyYr^%PvO zp;z|9xc0}j!T!I{{%3)&0sb{y_rdj>xDLeiJGkzL>y5Y$#`Pv#q2FhJjO%DzZ@2${ zh3g^sPj!a)pK!%iWZ8e?dMK_C`rt5J%W!haXkjtn{b_uE7hgraQ!Q;<8XZ$SEfhZ{X#WvkP_pDU^H$B_D2oJ-j-lA zX-GJZzX>)>u@Q<+)Il6pJLE&ZF*&v!ZtLD zeMm9RIhW^hJWbN8Q*5GQG>1sIMT%Xm*jE%=r`XRGqf5TTrAxj%gOivA+tX5EaFAl7 z6`QEoWW{J0k+?LBNP2x><`AsErNsYCF#4ZKxMMJOCfIS73WFOI`+;KgHIs1kHIukB zhX{6sV%I8my<&TJbK%mK3WJe~jZ*9zie0DJPZYadvHKN!P_ge+xMzIdQep5j#qLt< zS;d}L>|ct#rP!X3ba}TvmcnL;iXEWXFBE%Nu|FxcMKSu^9b}A6SXG)$$zV#FpcI=@(kDetU85zMSO78{-Y9+%!zRu07; zWG~T|?$EzieWI0jVW6qJ+xMcoyP%~ev+^WttoF=i%!7FS`LTA`@pZA({4>!h?(B%A zCVUPL#Z#Yn9xicDWmfbt>-H~%CG646ii=2wO(ty4`f`}b zGF!33Ox)+O8A}(Wu4@fOEiD{f8ejsJcKH|V9c~GuK?dWGOv9ZGiiy~Vi+zJncM)nC z)*KRH9%yGeao&YF(+OKFarpT+G>zQKNx5MJNo6ro*_!dE$vm|b-3BrKTxv&Nq? z^tIo*DXM#=e zj^PlswLZ|s!mQDdceDxeTeFATG8ix}wV#?x_Q)d+N7$UvfbK)7t^-mfAs0z6?dI?6 zPJPmNI1PZw1tH8J6xYa3a&g+<>BGGGU1i%7F3bKURna}a&E;jwBS!Z#=sMEbM>)b) zVJr}SCanwPUgt)-hdnXQe1_{DLZgm)K$1}pnCHn>0A!AogR%H(Ip(JwDTuiN*qNdQ`=1x>HPUj_03eS^LMU$jji?lvKx{@`r_ty$Zg+m28?LCKvczv zF=4ov1%_SRlTDVFqSEbaO5sJuf_GBzz?$jN8`$PY`7SHEUt{twij!nW?6f_ zg)6&~sAIFNsIhHE_S5$NYWttXpaeMcQh_UHJD20iaclnn9j@JQ{e%7g7hEw#H2W`H zcfz$F-iPV3>vjPYP;qu7C0#ecn7Uw_HQXN+W7kc>vFj$`4pHn-#n=!^ICkA6T$^H- zD#ks|B-|GiyF;tk@jIMxw(e;YL{sQ z>?astYKN+73Y~a`?Df3hd1rIZoyfL zny{w%IrR-q4d*nrG&VJl!>+_*#^kwSRIptSr2g76Z+^3BHP{I5X%arx{LhV}?rAh^ zR!AWy?S?SJ&WqXza#PFDvB$>^?{v zn?)~}J8Q8?kK+Ur2w{|$k^MARBXX*I4B>b)R$-#>hjXlZq8Wpz2YebMF*9yHHF;p? zQ}2w5o*FjaZ+aKL-{>CF!h-3*JSTBBM(*IZ;VOX;Lfff;m9k5at-=4}a2bMPPii|k9d{ut+?PEX;^^KJ8f^vLvVnJVdtz_w1$W;^hi(6s}kLTugT zuoadHxniOXceP?`6#J=S_bT=a#rA+0$TL101s|rfETNF#<+YCxEe>Ij0 z18&117`Nddg?daUEcV`l2g5BE)9UdyrGad?fQsNb;#wQz)>uHO;L~UTOCeSm^oEG# ziu2!q933mp{eV$iAcw)N)C0`n73XmikDJgqXVKioiA_yo#`ynC!5xkSVg(mZ$03C< zS8%&)!KGKi!6uq6Aur?OCLUxxe-WZ4=!y%UY>SJVSiw|jST|b=NEx9>?5rX|Duj4D ztl3hbnR+JS+7!E9!+lpV^8w&GgZ2RYAF&~`Vgk3j$K1`SHECm%nou)nO&T}l3*q)4 zE`L6%n&Cl=<=|NrC&S{>BiM*JHYVD5EIuxYt|+;CeD5v{zH&-BvvOw5Ad?hU-EjA5 zJi=VcH>%D(2#b?v+Na_f?dvkFZ(tlEXxcl|cGteB`d`lsS%)c}uV>m`?|W`H>lvRQ zH;A6ejF4R$VQQ*B74t~23Iupr8Vms?mZr&|>Wnyj7}R>y{G|cwoAZsZT?A^Q!EOg7 z7O8chPBC}y0VSgNYfx#liaDXY6^%_?DF1{|(BI*jf)!s`d6{FIgpvzzq!FEc5w7l&hK&`fIOf%7?ZsuRd%R9=6xJ*U=iU+MeE!n7q zjWqxB9k0TBLD4q<>B76#{4X=^K?6X;>LZ(HbG(wx=#?hGfoSNuM64WU!|c+M?6sA1 z%lA%Icgx%NbvgNgNvKqF!g9o%kTXfA&&M&)GExIhOocUmOM8f*jte8eAir0(6NwC26p8SXn<0ew2)!S+Y;%;L3^E>n$vyFGFeQCv7bx;XZloA?yba zGjBK|k|}HdV9cBvVr?E#(AYWlPDMf6(+~G?FYWjA{rB{fxAva!C>OwIqH&ilOZyOw zRH-Or=G>K`&5C|2*3R|jE#;>|>Dsy;@Sd30V-OI22xgoj!$Dd%K+EsPFUzvUZ*dsT zV{x)bHQ;0!@ds<&KrM@i?@j$1{AVAZCFEtCuCHILS9KVSF`I`^M|p@1-qwyZZOm-E zh1bSV1*49@!}YNL0Xj{<9;~lsqdtQi7#*4LLn+a#ZUKFAOs`_Q&I5|SclgUx`0Z`9 z^-a*AytdeBP-#t9md>a7bGC=^W9r{1VHcpFPWZOwT^2lfTk_7vKc$U7sW3QCu?sAP zt;Q6i^Fdips&Z@AibooNHJvKy6#H8ymrp zTV51Hs2wpYcqc_U7JpONGJtihW$MuPgQ~#cooJ9cM{z9@sb7 z6q^N>!U{Wz(HO|P+RfX7h^C0R!hmux!!F@x#J(=qHRystZmeUIp4|SBlXSbd9!(u0 z(EEXk3N%F}F3^V{6e18ED(ZyQ?YL=wob91 zD>fUSQsU0FR2W-N>pRm$A*itnT2Ab%!LHTyXcjWpbH{49zf-dxBC8N}a9L z5~Z?AeGZf~2j2rF&B2dAJz(@8R$yYJc^#A(Y2E@Q<)kMBF>0jYwjc2lvo}Jqpzu1L zggM@^5|eD$De2;j9+I7{7(7I%U||WL_#~ z*m= zv7W0&J&21McQ#rjkL}gUPWO5|1z`uM6bbz$Pr-2grL=ub_Lm$s+rx@82)*atSByw+ z%llFb>Ze)|Dfo>mMhmxK9QcrMcPhp?34+lrM8aL8*f$jWfnql+_K;$96_L2~Un8MZ^6~vBRKNzhUBzwNw~vRO~**o>J_0ioLr=Bxiu?wr%F5nGgdR z69aFJVQCybWPPmTF(3D6SmLPK3{;+SMAWEr8y3u;Ti0~fl5-jtwy+}+0Zdn-#&oXL ze@LNYLbk3l#q2^$g#jxL!Jbeoxj!A*H=={l3F~Gcen7*MwK}0BA&uC0JLG+#bPsHfdK_MaEW}|B1r*Uk1%qk@Bx6<(`Eght! zbO^@MAs9=CU@RSieOobha|NTLmV~1TQLxW~y4sYEt1J};FDmwmV);sk@yFYN;}fp@ zY)8{_uj$FVrsXKS!ps6q%dJjAqBbp48%}6wX*h~2lH?kf9AxUi(c9L%9PzF+FBrpc zWsGAOe)Gcjh&3`3(#7gXaZIftuDgV)`vsUpvl3dl&RI=eOz#6sr^0aPeJYg^Kx1 zC{z@$xNj-s$sGB8AUez7NCA_re>`??PXT*Y3m7T!EftK#O0dsas?x0aDH!!N3CCh3 z7#9x{Y?ESFK>jwE0=CLhGA1I}n~LQtV1)(_p~JDQ*d`q=T1pxcN{O$-edp~eB|B25 zI~9$)$HhN=lYsELnoF zWC?b)Vrvwm*S3UXPe{VC!4hmOsGpmXwZT%@xTdSaYAuz2NdB~%v_BQ&pY-U(1A|L8 zwG2~76>Q?-^t#qnxS9KhVdH>N@a!ClVf}VQnUg8ifD=aNlIW)BBm|t45OBIIV+~)J z=^58AyC%y=z@KKUMlVqcKF00iV+rknCr;@-Vv|b%b{i%TdAfV6NlP`UT%wm=#t4ZS z{M2ULatVK`8gH+E#`=F2`+rvZe;&&H;lhlk$z=Fh>-!<$Z$fh`g^y|wTyLl`pf(w$ zxE|C}gUtbTfuRQ+z}nY(v^YBd!4SHW^a{Rz~^ z&}}UZ{tD_!gK_-j^M>k*d|z#-oj`rrP`yB1W2pT>ecez;fRg93^C{FxN;N9gq!hi( zB%D+I|BR=e7E}E{gHY63I4^A=8DoxUpSrQBW&Rlp8oeE~jq=hFHX6%)pUR`L^fdiz zx-s=M54jkNKgp(t1^U6L9QT9?h{DzvpX{yS@X&^}V0WCokX=_v@}X9>5O;pobvNNW zJEofN53C&LzBqG-?@0-(S;sfa^TH7gLT0CUuisIF*tdZ1Nnrgb#RABo@&&QHSKAC% z<}wayhva>@n6L_FzNnoK$@h0U@1nZxn7k*+44MOTr9YP>W1B8jVPW z0T&z-j0=tl_E}I%Ot`Bo6$bxStP2J-c{dE|L4C=Dn`tSy*(!F2Vksy}8%;P4-;)Z1 z7R8n-b`PlEnQ-)@Clv;@&`<>9d~?B;gL>YCyUbEy@PcA5D#qc?f0=L-ECsJe#lEZ9 zo1jW|BL6rMgcLT$v=lbRRP0tz6(-yrmI{M(g~Mtr6$WFE7w6%>v`-w>wz&)T(%H4G zanye@?bB*At?SqoF$d96km<4WbQm@3qdy$)) z{hM~fOFN0RbsZIdjTyhmjzHd<>=@*|$&NyvoBmFpSWD2$YTLTpl-k_JoR}8>-ZJis zn;yi_j2n|j$HX-J`MAd~!Exi0k}NLAENbCq=ZzdRrvGX5zo|Ippbt{i)P(4$@jMgl zU9dvtGwbs`Viri|F=BzFCUq^&(_`8<3aB|yq`bq|q@s+AGcwXw5WUZ1YsdPy7`<;O zazf{2sf|ftjS0ohvs7sIyOeO3D)wCsccWr=D7IFy7Rc0>P3=T`38^snrDB^D+eTX> zp0jPX#;D|vL_Xq@KMqN|@nX80$>H^F3xBXA$={Kd#dl`3*c16A^Wi_hl(gjxFXY*5 zR3~7kjupQgi0$zGR4T64Qb9^eg^jA6&~TitD{(nuEa6sx`idzP z95E&ZrzXYzrdYmG;nr=D?ew?+q_dr2#g&)L>MUHf1?>%2X*sSsGh{|ZX5AZIGcY8M z<_6VV^0HRi=XTs`Keam3eo;kc$Wz=(ul+%}v+iG*30Hazx2&tptT+lmIM=P+tR0DU z0kEUThu80p_nePPuoUyk%mTik=8%F0k(+)01hj!sv6kfugrZGiDbA<+;Kv+Z`IPW5`w-TnCLg;)VkL-1)=% zaYA?HF>s_lBIR}=hHKFHMN1a8z$7Iz+7C1__cCuz4{>g@AgS$&)v$7|9`pLcj?}Yc z4AzyaP7T3=5T}^AaGwP1ucr41gVm-grd6i!+=`vKUd$4xahORzp|QEeya2^(k$G%) zwUC``{_k$@yDU^-mC0Ndx(`6w6(!R!+rPB5lIsLkmbldZ+?}VasC+R z7My$rd3zyFCjKzaO*qNOM{z!eb2HB0U1*&Z;N-9L_@300-g~2(BeN?f}D@Mz(#Qm0HbPf=V<1X@y+Z20Iu~!r;?c%~! zSSmDopGe%Z6+2JEabB@JgEm|V*RI(8ian^<3yQs{m|aQgy`|iin`+4^x2GesXUD3b z`Cyz=ZufE;Z0UTJ+`L2F{0n$hx22dR(`jG(FvNd$M$X0jPVXE)+?d^iE>N|yWuMKSxbe%YQ?DFNVt0y z`-NgpD)w8&*!X`Hjelium8HU{lM+RDgRjD{$-XiQQ_L25t|-HF5e|ds!N{R@9}( zUiQ(NO#36)RO~gQEf{akiH}#Ec<;+q7f*W@o32&$z+bcD+O%gg*l{gmcU&8b9oO0c zwIBa??AK;i4|+XpIw-TUE<`q-&8$5AaV|QPshR|$?MH0SE2sijX{355d&gAr@%R@UR@w8te^CL4WiHir4x*oZgeCd3%_bjnk=yC?NV z^NO+4>FLbMcN2Z2Swv|Xc75x_8cJtYErO*7i;q-Y zJn`9$6CVc;j<52Qd#zK+AZS7d7ca?NJGdg}(t(X0=jzMihOvOLp7P$xqX z7S*oG)T?aHgrZ6;)a9TqGU5IPDrLgG3QCkg+GhkygW4Bgtu&zCChol4U*UWc_sgJU z*5KDc$*jR&EB1TEwt#x7A5$5Ok|HrU#4a(ojHR>yn73CZ(8=?9mue_$; z=C*(%m!t5k=p@2Hs=p1wJ*-XLmEj%&#nq#+fESvQg;?s)Xq(iy_A$ZUf>(x2iO=b> z`UM)Tq{1Q)QzQ7MyB*74s4g2vcRl{E2aP!KsSYSE;Z0>DhUS z2Q0(VKEwPQcEPD3%SuvZLlYL9S{8O{USfz(!+xb>8&;Rbk(-w|%=|AfFR{b~7>?z} z5*M6Wwo9?|61krz1<&PVFPjrzll5tzDa!rpQoE1#7l*RTeYIX^xL-1?vXQ#^PJUd+ z>DC|S;dJXQ$((Mzy;GdN-AGN2)3=)cIZkgj{|j*X77@FAoNnDvET^e=`ka2i=EUc& zPy5_bPS49D=kuJL`>~YAP5F4dBoB`->=chLG;fmQ@%i@6C{tWM?Q7m|kVnAQlN$1814e7^d0hv~HaTPM0MELX_zYYjJRp%nu!(l7L<(%yp5U|ROl?CpM} zVT4OleOhb${rqGLxRTZy#HgzB`^hsHzPzM$gtz~jpI!^^r&3j|SPwJTIrT#fk&MjG z-tO;ac9O|QN%r>211gWg8t?mK<<{NtjPg{v+`aJc5XRdDU^*6ZHA`i?O}VHG2EnP& z9*1jnai_t;2&3%&c)MhuOWj6RAwC?roebkb?mZsG^UCW>MptGkhg43e9EA1%%>E30 z{AoURj(BBV-u3_J#XZ%q>F}gE;*6Plrkx`m1??R1C}`)1SJt^t*opQ3`ao+E{`%$} zGe^8)xW79kd0R5vY)w(>2Nli^cd585twB^r-9g)r99#tOFR%uU#$VPk{vv>@@!wg9 zXeOsDvMrzt^3(W>0kY~~F{g~N*l=;cW}K`t*b?}Q1hRWUMqc?K?Ikzd} z!Lr-%m#UKDh5E9$|0i`~3>v@Pc>GHYKiCZ_^9XUe%61wb-jjg=R%w!M<$o z!Zk$0eOIvu6?;UnXB4B>A?dxW*lUX2iHbm;vEEW)K&4%)EsQcHya zd+UNtQ|x5LPFHNd5*KcNON9Y<^^>@VE5=>@YulVZJK-jV$6WvMXOSFs_AwZJeX;g(t|47gvQVB9Z|R2ZyP zY=dGCDfXyhJ9Tq$dsr$AhAB2eG43HK&)^<{@{Ic`9QI2~g~9!J`j=pXs|+5rRLD(N zY+P)wV&m?j7*Z{?7nUQB;PfiQe;WjWhVR*)4_jV1>3_(RB%^fLJ zhj=H!uCSCefr7CKlyK`b+|LzzSTQPj67CAf;A&HJX(1tn>PE4*6ifEf*q&twF}7Cx zGK5%t5FeSV57ut1J1}w0LDc#f)R=-njoda5@51H|Q<06AOff$}sRpGMD76ffj0$jA zTt)@>S;WRq!-d%R{{Tv=jsF9cMxC3hKyF4&60bnsLa5zv@*2KP6-e@efqymzj@Lzn5phz#qYQQT$F2KLS5}!~9L=f6iR| zl=)x4l=(dqApe4aKP%Rhd9O(*XPDn;bK(pN@vCoxFdlUSE^y`#S~7i0inC;52egi+ zBxCX6eh)Lse3QPh_;A06$eMsd{A4?`Cg2&7484nM0uF(ep2yx3-Q2<0(xT8d?f39? zn0ofbw~U*5d@~PCJaO~Rdu6YO;l@NW8*kvX(X_v?!^Okx_0VBDHtVW1>Tk3*YHt}A zh`r?(z~1>rT-fJirv7ag|q{N>@F#3}S zwpznot5^#@zJ#L_wS?o;7r`!5jQ%8o(Vs-Z{YbGjiv35iuINuoxScIk8T3@_SBgEQ z*yU(fm!qYv3_fY8F!%u|c`jRBNsrT91miRp!K%@l9R@Y3GT?R*q_88FVr`0Dsn{13 zdk)kKCN3wzkO~8Ck|-EANfhjC#TF^nx%K_LV}UQ!(Y?Wx!|x!PluyC_?9@% zj43F&MfLq*vhU#$sq$S@<3hjT^8^~`9r$RU6 znD5QEZ`NSgSj@$AnvJsW9jYo1tLk zmg?xq_a7AA-0Ziub&IzkJ7y!sQd0}iQsXver7xeULbL|KvTozYW>!oZi))77`Eb*p z1mbSlkcP$+uIX56wxfFx0-Ea{^~NjCja4RxBRngUAvlk7V>|vrZpXm;=!Av^OB(AN z;2u6^jG?*9#l$6`GZoB-~dNyGz4uRBV%C9DtDY z#vVW8gcIvds59Q1Pr!R~5O@&r-mIS1{?g?37mWiawoaTl;;l^k(bbt-Z3A?%I8F|z zT6PT@2s%=>eXMuYxoA|na+V<^!R~309)O2h_sFU3cUAqEn>wzXw#v3f?bBAnrSN+7 z#H?&O1fH0c@WfmVPs~-$6LS?jG3#!HOu~-9E;ODfzL*=w!z#LR;wtNl$q*4=%u0P$ z6}>GdK4d*aH;aepL)JBO^VAhf)k74l%d9*G4X$~T$b9=lNJw_0F$qnmS!`3vnw0oo zoK3Uwq}r!t@rsw}EB0y{gIDZ@SIlNso>sHiz9T8VB>f&cyksvxc*OJljK?X1MBcJj zX64kH#U`innm5|at(Dij(dKP!EN_z&U-QOXLKAB0C8en~v+aATzH9_DAkN3% zV^XwUx;JiXf)m$noOmOXyDXBy#oL@-7WrGu1fTQs_s}+{w|V2lhnU>;esZfim7LcA ztvGM&)D`EMHm7}BwR#h`ZeV>@H>>W$vp#(4>Fdq+e}LW_;!xZK>UX9+Y6EqFX`_A$ z>emMQIVf=%ep<1=gA$kFeUb256K*J|tcg1clsF#KW%vnm_dB2@m7gp2D^QXOyE~G~ zE}$fpzMv$PFM)c@r1D)*5`%Nt#3=c9P-2vP4V0`rd?1>5F;9*HCFaRy#m-l(6_hwF zZ_vB<>D^6wcUM&ElHQ)6B)$HiB<@_j`w_j{q<7f~lela2?pjcy0XzjtOr>0meW~Fe z2%~D=k5)gf6}*C*18|?$DQ}lnK&xp64{;8)AaM*euFljB*d#-nD*ah$snHN-17k0M zOBZ`y(K&tK< zv88E#p`Tgv^~WFPD0wTAlzeXN&{$;au#^Kg1Xr#L;qyid;m zx6Zzw^Z%W1{uki%;U++SPERYA(H+xx~81`fD*x-)sICkm;|O0C{D) z?R&*?nk)3Mzv~*5AK9EZ8IE5QWO_{7;i=w-Cdu^Sl<7(*(>wcdZ9P4#Et5~Cr{t08 z8J*(v4D&v@+JmbU`Ey~Gn*RkjJ;embFVm+L%jvUBLOD*)wK<7%*!}mp=wN>Vk=AND6F*mjG>y0Y=X0C=l#QZP7<4O}CzclYvERP48 zgmOF{U~}Sl8o&C^=w^fa{>vUtg#&zFb~D-u*ja5k-07<#Zn$&V!+zp^2)aLmpC4N` z(?{Lhjb%6bKK0gxf7y+QkT`c^*_~T);a_%RzI@oZ8>cOsS>qXg>C|0bTC!{==4@1B z_Qrmd!zz!0ak*bN_r_bBxiJ^YJvziN{`Avogr10I{K9*Zow-rIY#DRtzqOr*v8)+y z9hN1`!=TlAsYx=-GY^9ykgj>C&j8X%^Dvh6N|jZm23EM2Oq_>Nwrn6)d?>{%mb~*Y z2AF3aku(ou*+_oG$kXXXj|n)-CKmpPJ(j7>-Iq}M&Zm&4RC$HZJsCS*HjuLg$}4=? zl_BJ11LF+ge_s}VunV$Pk*Z#%-~5|!wa>%4MXhJ2N}Di+rQ@`f*5BG`D}MH@NVjgu zC(^C27v@G)>lXI{9k@~2`rE`=DXqWFH!G#}w=OYv^*Le72;MPaepBn&c7D?^l$GAd zbZ1J5Oj~O}DLGh6$s*HHN}S)cTkF;N=Qmw#;>n6GoV@y!`QH=MHWSNL>!tb1700!% zu$jm|zv=TPL~-+*T5DOZYPM3YT8}j4s&D@JO^2Chj!7z4ty3vU)qbhA<*N0x!je?o zsv~9{B&n?R$W&QExoSPqNK!(%YCY0Pkbm{1$(5_tw5w(cl&iC|m!(PCP@eUVTp3a)ozHC|B9bym^CCu8N;G z_<7d(SV$%eMrgUZ!eGheDtk-*a&?P|*Vh;=Sgz>D9|Zp_xjNY2)P{bw=H?Dk@y|PV z@OqO#p}B)UG$A^ct-fBvd6TpnBhBX=)vLT)s%-f+J7X;*wmq-m=C@FP?+QahjTs!8 zb=>^3=C$NzSJInKruN)kdUUX$)E`M6#H72XcAD;2<{vg-$@IzrxK+}P{Nn5=O#C{o zv3bdY7Q<&YxW}2yA7psrzC1^PY14E^ts??XMf({>fe!#et?4T`zlxL7&{$HaX;BH= z7msJYC^J-isVN1g?;p}m5zY+Koix~XTJUdHtq zI!-SeSu4}aXmRrf&p2c~50LB~W~P_z0%$QH8r-ILu?DwZ0O_1V_`(X zSD-W0M`Qo*iv90ty34unXT<(%wvqZoH>k-Tu_8;Q$t zOTqS3jH}TIHdwI(6q};hbj7&#xukcMV%I8my<#nBfF&I5iSmr)ie0AIXBE3jFBZ+jDt4-3OiR+cRg&1OBHKZ z>^uEENXlfs$|+SSk!IRjggH zFDUjU#jaEA2E~4&7}okRDTl$`iqZ3cPYZ+1iv3ZsvFK9N;>%VB6D$=5H!8-C5ATM- z2F31CtT(zjUpI00wiIRxDt3ipUsi0jVlRTa*Tj9rQeiL~&R>GfwG{SwP;9AU_kiNG z;>zFwONGHGxWEW@n59rI6{}ZlHK@OuxYt?=_F?#=2)3)G!k|X6L5eK}^`?n?p{2s$ zImKR3>`le6=CFx@y)HoAY2wbbR2ZyN?B|L-rr48;!O4CV8oMnxqmz}{EOtZ}C!#kd zqVCR>*W;)aUB;DdlJWM%v4nM==vO@!Ceh40WO|v zK8kSg1#qg=thP575-NMaeZ^pCevIGD0JPLc#=L0{!#z~+FpCDkXHnAR$TqiNCh{2# zb7wUySg>f0M;i484&`vE(3!}zW8#rG4pbwMq|@DaU`#Z@JqKA@FYx_v$SP4ehnQ4k zWod4(n(CIS90S`+*Ho&++40&SsxTd}v}Yp;%c?Zd(3;|qN4E0ex6^c%*SI-=QBlH#4|jWR7Pmo>E?t+9d*hj9^!QzHO5E>UgBR zFU4p~k6#KJVBmczJKN+RKu39r@O@X~WHmPwCl9#4XL-E>S0rZsW5N#?Zp$*vV*RM3 z*#(Te!k?g^Rg~ z6)rvzg-f2OD|Xeo*Ta?Xy&5N_y#^-_w31nVwaK{dhwIVy>z%1zkCar-g0XTIjFq!s ztegd7J0 z=Cn*|TC`;GVX}>PeLeTwG^>FeF=os~TMJ@7^^|duPo4X;CC25HMJB&(mCd3nSWL)% zC9hzmUDk2sI}O4K9_XarzV;JL!4w>6A4$my7J_{lp#^)+QkB6Aig8PiicI^lv$4NN zb!POj@X0>^q)gSgV>27;>VnLn|6I}y^BCLjd-(=#=uxrW6%{U@^zAN_AV#@^;!}om zFwV!J;mP6geEfn%3mdSjE4O~~SkB2^Lvvq1S9OmCn~Y8Dv621UOhfa$!b5?v13DK)3WNrJSVh1R0#BU-C43xzs*o{&;17%tlO=mZd&a z;k#i?0SfnxKIJ>7x|O9cELMVgvP-bIMd~m*V52*QV>eT$O~Vi(C4(|TroR!E+3McclGfr2Y$?j-*W)s4xds0qG$*xv{ zaaSwBXoVB(Kud+e5sHmdjLVuyxCX^sd9Lq7S$+*qUJgbH<@-a(1+24nKHkEz3?PLL1?joljP4jIbOHSz^xcg(9+R1hrpT zf|TxAKuSgQb5bfPZ$(N6BuZ&tUkII)Vupw;d$Cn1Ei9p9AfYg~7|GmLsU%~4spNO& zq*0McQep6Y#cr}xh@om1?k>fshDlsD&=Qw3L+j&xOj)^aOx}9^16GL_E*?jqc)*^jmG`z55%SY7A{`c2p`ODnBOuJG zhh1j%u-CMHClv-9p%LsrONGG&ie0Q&yJDYG>^q8mU$NzQuB3OFrC{?%kwaEq!nq3q zemho``>HS-HaYSXk8usnjnOJRr$QwtN-=ToWNah8-_Iw$#VXLwuCy42U)T6DQU4pV zkD9h`&I@@G|Aa&ACwx&qAt^M`2rJkoONGH8@L8~-mclH3qe`zlcJWk9OKm?IE%4FM zrawk)`smEYanz>YSW-G-?aMbzZqLk~ys{qpcD@i%W&7L6ZogQicO3G<26`&a6SnqM zPn_Q}Z$=Ar+c~P}=KILSYtRSQ#?<7YwbI!872rGgWFt*~J~U5dm@QcV~?}xDk9J%)!Z2ngp_Q#ZZz8`gJZcr$5YFrC%?zryXqF=!upA}db8XBU;K?e;4A6gj`H2|6?wEUWR_<~Cc~ zyrs1bsW3PSEE9~(6O2s1jiIkO8h7Fh@BeW#>bweZdfmi&?`F)#Q9pdd!6Rl(n{*V65wKwR z28V4-CJiHnF;n~(y{)NoU_yf?rh{KBHF8AF8oz;Lq)N+KRj`^!yHL2&MkfdDaeJbg zV8hBW=(UK%h=0I22=zME3u=FSW~9gu1$e)9qewyZgRBb1ZoFXDUY%3|#xKo@zie+$ z>&e!|pH(i!AEt-kr^u%qMT`H$h5t?B|ABg2BmTD*C;ksZGCD2(>kx?%AIG_eC;oh9 z2l0PO#h;XjzhD%9!3v0fkqy8nkk-Frs<7Vx+=i@nvINYa{VJjMC*IJqq^Yq$127|h z15iI@{EXq}4nN3i6HFseu)24VX6eJHH8wXloYe@yT{IU>!k|CoQ!uElhAOD`6jSM6j)c0z zbRNIbza9DPq{yGp*fjsl`Tq?<|ABc^Blb@gC-%=mB04ShcOnuazKGMW?D@1e zJt??$#dBp2*1O{0#xx6f_oCd2@#m>$FrZ;*# z9W8JiM+OUVxWzuZSQA^+r1mAITAkXtmv2$xST4quckbmZO1%03tjVbYyQ~-LN7kZ) z*dP5!xYh^EKBMu0Nn^#e2y-(y6A{sW08Ha_2fsPZy?8mTAo`Yw@6-yFP*QN)MHsV9>k_P5V+LQW;NQJ?xV5eYjSSk!A z;2Q{*u~b9>J`&*X3w)ws+xCePg@2oB$oQw)rj*SmyJ$yMk4$J=KiN(C$w-AkIruMF zXsIxmsn|)1d8O*70H?<+O@6y}K)>Wt<#$wKZJggx@#@5m?bQzX8fG*gH;Q3;PVaJt zjDUP_s*g*6B%_=gaFq;J5UofsjA=smeJ)xK< zGV1{zUqECA_S+Vb(LPc^k=arDQ*l!BPUp!8&SN`DaHx{9&+7z-3HyRmOyl6h=BFw) zq%d;l^jvUTWuvVGfJ+ic;5_o zin9L!dLbj{tBM=aDSAY6cl1Q*AjT2Rq|r=1&l7)EhIgxdk5m}E0=X6JbxUoxSvyI5 z2jI~ZUyfyR@JWuS_-fVjK@r~%&KvW|~?tMCC{0qJ06qRhreA1>)CTJZ)g zNuj+BoDBDXn8aKt-$g0`)oP&wRz`5iLffU}uMX3wE5P!r&IgZdI&6F)Gqw<~pP` zJXVtYMv9&eoheD;MbfbtseSOh?=7>P&C`Da2TX~&Ccn4Awlz#~j~YIpP>CwkFmV|t znY2bK3{HTY3wDa7!hriL3bt0U0wt=LhUp7Ps9&r&`3)02C^}P|oPWv(r9c(mD1DIM z+!UXkcXWdk_srn~3KgG14bm-Id`My10pwb+qb(H%-&G8|D44sEF^wMpoER$#B~JQr zr5Y+nJ{^rh@A=5X0QKM71^RF1g()s`@)eh2$79_*z`@Y+oMo4Z7Ahi?*SO9$+ID?@ zrbUF5?BFXHCm{>A!BUl`6C~JOImavR2pCts{31dXv$I9ygRabrO*hw(>sT;8=o~P` zVbhK(4tsgUfr)NwarlK62U4PN2}XrWFt!tdu`?ssUAf}$4S=Hyv>4P6J6jz78?^DQ z7m5D{E|_AmJYS!rv#rEfuUIhAZ7mj8Yq1~|1|Nou3r16!VC>He#vX}acjb!3l>p<$ zF29wa-q+b;@j=$Ew_Y4R$Zv0o!OJ_U7#!pk117qy#oz`l2BgHmB^V7{f?aQ^O4G9t z%qs>DVrZrzHlFPlgMR&zi$Tot6w?>rb0d|bXZ7jmaFgGABGC~_ADQff>U=0PnApVL z6FD>DbL>&u>HFwhaDIp326~A)eVYk)R)qd+9dI60PYP0D@CnF+V3%7e4F0ItbBcK) z^h1E-3y9Dj{kBnrT!m6lh~i#bUSKPQW;)?^%FH{F6(b}oc9f88hLF$))d>j`_JyQ4 zKP@LFPpO!YLZ=VkTrfJv3U-fT4=7f^@K>ZM9Sdy)>toV25CT<>GmVoI2jz$wJf!~V zINlqp9uij=c+X5Ql}7gi@hV2Tf0(ZYjV>Ed^bAtpOCf3YD4*vEJ)La6scj}HOx%F1 z3ig7fw%f^ODn$0~n8*&mqbagzTH@ z_MJTBp3F*;ulGH#-{kgt%zU`a-Qy7m>ulUTzBd7CKAT`8FFdQDH&$a)5KJ-CEFmwM!`f=35k?EE;%Ht+1`E!fIk z05LzVv>e-Frb^1OBu(Rs1DlA`& z%d>FVbo6+GUI@UggjpeB`D?Dw+iU`H4&NRo&_pcrxd*1w<(8-AK8fXFN&oUaODbeb z#t=)Lm-p+1gzS!wc-E{rix##t%*VP8CP6Oy#g>{2mG2tJT3hv4Llm7K9A&^X^05e69fx;<{S*qoD@=U8$9}(HYn|S*qkW*r{NCku9K=dGmFC>T5B3$}*)>%s$n&uv6>WOofv@|ZI zpIh<`Q#9_wjL^iDi%KGkqYZ=lj6z#sWUufNXRceuD8q3&jhj#MYH?(oQZmTC0WW;F zG+qqsf~T1rnC*}y^_cCTT?!6~6p#voi*Zk|HcN#@(gb@&F-(LW#M=Lods`|q?OnKD zS@2dh=R6P6^~7HWwlc%m{NG9_IyZ%!A%Gw*pDq027gzK9F=etNKC?|EEO5Y{U!oVim{#|?vCeN zJ_3*Rbu*3`E@L#{YwnL>+N6GYm{zQf)`=|>>L|8pmoZ$K&)JX>yqB`;*S6B?sq7*Z z1`7~Iu*H^whlpZp6}wBM?j-=+DP&>+)|{NkngwSqYQn_&bI2J-8^&;%@H_>+JeXj% z*C<@R-4N$YJl8RaiTX_X2lAZ8>5e28q4qQq^*t@oq%g#ZNP;c2lq`54*gcBbzBKnn znq1MLT)W*;N@PK^G@?b9G2;ZvlVfaUBg-afUz|5e;}6Q0ILFFdx%L^HLk+952Sr#- zeF|@gLskW#8X`w`FfylIu$oEj(tYc*`&~_YG`<8Qx$@5EdgXmj`xGtj0h`lnR5D40 z0rxl&Y?-A(?u=rw&nU)EE8)mNiHlFs`a%|eGwo&g4KgD(WL8Y5Sxmiq#nhU#uCUnU zIo`fx?UHcR`0AFjQR92G49>Jq!SWQbYPo$XVvl&h1kbc?$RgIM>oe`x_iE+Tnp%NZ zn&vMDJU|WS@qR2h13-00HC7r70W}9)7cD)FHo7$UD6n?CbZM{@R8JF*FTJ<9%i5mh zj_ZUs#02D0;JtD3+OJ3fVa1;;B)nq;W!D2$P*?`jNZl#m(&Q`%rl8Qu>ZQ18j=dnN z6MC!y-BEZBr|`J_$Xif2)5t7~bynh<-wLI<54bDV6eRAc&H9OZYDZPT;lquT@u|$T zCuPUj)KtnSC}S{D!hR9KA`0W10 zu5KG^7Qjzy0VE}bO|Z|{yJ7Hk4fid@xV-i?M%V0RsW9N`_7ay;E9tSnA=pgCZUr?Q z#iTO0!%|_e559?D`&lZ)0J*~;N#-u~)XUSz1omj@y#-gZgfUz6(%>%sNTFGeYrIxv zCQ6PudAJO8g?+VFmPm{wLmT>TC64)d7B#C&GS##B40Jd+AhUeWnBSc|2?Kwo(f zN^SI&Pb~1tclY6o^YEkw?>M9Jqe~hW&S{iaw=W(8&FgoYu#KD;azZbS**9(+YOLiVF4)=Erbzlfu+LWR>kg6ET8g;3y~jEQiKG{+PiAVwJJSzO6-An>?mW>-5=V2dTTb_k!sVmY1}=&7OB&;JBp^= z%*rVh8^@>3_Nm;U&+yoqdGT?A_0XP5v0A?~_)Y^QTdOvKYD5rGC8I{*XV7%UJ8mCG zc=j-OJ=m2czgC-=+s^MIrOgK@%N2O19Eu8b4%F1Lm~vQ+0-WnnTnKw*s@u`Dy7q#h z5=PmssWL37#pT0tp=gxGjYD=xRUeTm-8EI-W3YEuEW9PVl&4brhp_LCq&cVpCf?E% zO}vp6%B+dEVi!Il!M?lyhf?JyC)jsOKa?5>`|WWF_T3uKzB{}K`))rlc&ql^8WZRw zm}Q41*?0Gk*>^{7)xJC2Bsc}N7INUL2D=zvpm>F_CE?z@C>n zsN8QpYhklNlRThuB6g{)sC3Qa9uUst#YqPsr?h0T13d+86m!mZNZ1pTW(3p>IQG^i z%?0;YC0)%tl%^^N`5^bAgu+lc$ZyL00Cp|Y-O62n{B0c9Gj-#b91b8K_~LFa%uj)4 zCi3lvX*52tyrV1~t+GTa49>*M3ic68g#lYV!9J$gFBRLQ*zXkkgJSx8%%i1^3}bbU<@&@J}qCn zxwTh!&A^df9mT}rZ1}UXffQUx@os`$ZYgfpc3Mq^U8MQR+vt0>W;1>=?QNtpqucne zYTUz__SBx4_A6f`h#IShEZyu?S8Hh5yX{8aZ*L=wxcpZ&?mom@O91h9Gx3nv9)4A~ z<}%#AEz2fgxj~(GfaCMX~g9}i94G>{g`| zwFL6VeH}c!?M3_`E@{N&KZzR@jH{-Hwk#vMk)pQC_^-Wf6)$r#rFvue9tK+3eiiOK zhZCXh&$ORbQ)^btHlmEat!*f>O5LFpGbqi-NaReY#Y!y&brH%@sqr>$HPki0mK*A3 zQ0JpsDh+-PN;c(js^+688>h!=1~yO#9&m)4OSZ@ntr;4d;;Z3E{m>CNMdiLvMQRC- zV?j;EaZ{J51$HOc!*l(~$6#_ujcZ-vnxl`PF<>?ChcS)Wp{=9$^y1mpto2lB&QdOZ z{^smd1W8fVu{VS3iVpq4sJ;M?tz|9rK_4cT)cQ z7M=gTvHXuV|HI_`*Z8^9{KID@*J1QSxcq1T?Ls8ve_cZUv(FTr|7Xa4kN<4&D20AL z9RIUuyK`T~>RaJI zRx^?i{&1bh|KtQ^?(Cv-e|9YQm)P9Z|3O)EyZ7s>agJGlS_ z^w6=NhAB|?X{R1ajlVOxD67RMaSn&hKsBlsuf!VG(;xVr+|Vuwq1cm({Z_Hp6?;>$3bc#zjFhD!<1jx3vu4Gb zP2^9Hdg<@rzt?O|YiK^(T4K;ocB{yt-Auk=8qV(@6=^tg4j-Mh%`hQPK9I8{>r8wR zft&0Y&7YtTh$xW?gXM@X7*!s@9#!lK#Uk3NszY6FqdK(4*Oo>b-6^N1Qc?M!XWENYOz-RIgU0 zZcz%dW4t~nvd70{V*~C{rGgPN_#8^E9KLKUn!98{LsOmcxN5`>#}tb=W+dXMaS@5g zsZu|*m6}UEs!Ew=;=t@DlA5_|if$;bF^T8YB)$(N!*9@BLy^7KM_o&iMR_mS%T<@bAHX(qyUlO`I%NIOUI|%0 zyy#}`aFf;DR6m_zv!17!JJ{ULHFFX?xtSa1zldw*#<>^C^QL?0-ZF)oIX9%REzR6@ zC@8LZqttuVSG?|G`C41ff{`0vJ`j~Jo59&ycag%<){0$ZDX}(7I9i(}+#fX@du)Qe zq8K}5f_)timAK!s6nt70;|9kP?sPPC60X5gVQ`LO5G@<-3dPuPO586i#)ea{7SuD6 z-cn1!8sNI3T@uE`zlkgt8WZQpv>aZ=bPSx2PiR=Mq_MtXep54Qr6^#kq?=JYCYm9) zHYVuRgiIj|k3$_%o1iQmhmBCuYwtzAc6SaXS zu?aeW9<(gW;j?LxSqT?AEH7*^ChcP)fML^|d~Dj9y~weN2}IdM`TnB5J}G&9!T9=u zxmly;J&aE!#=phq^+@IMeorHw#W{+S?6*k64>oF}?z4HO}7R9qSEs&qppx zjUIjq@>3ejK`x@h+Vdg9qhl@PJcL34Hr^k%C$*5%Cr^O%;n(nTh;}!2^&m)_0F#0eaB_dNvk8-kYGZ@U zdvA4+d8A2n1d@}coP*3RCxs^waS}rS77s^EnF!@#?qNI#{AR<^`CAD3#SBD8r~+xa z0cTDc;wR$g*n*P`Z|V=bTy!GQaBUhW3bs^maJj+c5Yhp?&CE^cSea1Pu8Or5m9{cT zYp0167D7Q-!OpN$7&IwHo4$mjPo;#TPo-cq)d@CAu@#D~RO~B?eND0TiruZ)Lpb!JX|&UiT?tX7XrG&I)GNb{W- z8q=V}(0BkSF*G_|_)Z}4fd{n9=GY&KAYJjg! z&>A3G+V{s-JB33c0nLRJKKG31)pyEbZ`#$eOxUkw<4qCsAD5oL+kVnSl^#+ua3L7A z4#6I^6lQuUb{8v3={|6>Mx142yE}f7)cjy!1{uScVfM!{EQ=t9Wy8{WSk~FjBoivc zBIb8CUWgyTWp{z~b$vsdD^kKD!N?-PHdqSl(JAJ!h`o-uf2+?T?pi8GM5=PjG75im zl}5vy6Vuzt95BkjAhP|K&^D@}CSj zT~8qYaMe=WzHKqXv}1+e(c>3OtgMYCE(m5|F1H`+nv)o*ULu`@NcCd)n9b)T#~8&J zwGv|#V$@2EvH4^4W{hfy0q2PEaE`!;;f!?N7@lnfRc(hsuO9(R;{%mqKTb#O!S>Ez zoK!88t1$0?QXBV{;&2Xv2lcp4&LiG-0h_uxbC#R~+Y2Vc+o>H8{p5Q_nD;#@BFs7a zOQzsZ7Pq)f4R7t^+h0b|;i0^w^$?f=uqCW|UF6>qma{Z`uM56k-2P&>gsp7FsD4iC zwR^$>b!r)}eh6p7Xzk-d_`@WU|LhA%`7bLv|7EfK_c8yY!z7yj(9fObKXkdvm;dYw zE<{59Z%fF3_K~9VkE#Sm&g+HM1trbTsmp)%2_JR&&pzRDmpA{nxey)lKQbE`rn2&r z{aVra|C-5fF8{X`%Kx_#^ZzZEyS(}T-!PS|7J&)f)?SD0lMSPD_PfcJ@p<2Ha2;#m{%0qTthfn&dt;1(h&cakeb1LA_R-@A?Z=)?&gTCH6SM zXpa-@iyH2$ioK%P>xz}4PLa43mcphKiruQ%2F31CtOb1|iM!NN80%2%GQ~zhf0A&c zEQP&O70W3055-;=VMRP3%?e}Yxkk^Ls=w?C&u_DpkdTi>4;vj?IV3m$Y)e>{f#$lf8#&e-ykIp z#e!w=dV)P*smkCX#XMHs3@|=xgJKx=V6mu2TVlC z{WGlkV|oX%>SuVi&nhO|SynB#timK$Tep)612RakCQF58a++Y2C<(U(RDhb<%#X;q zsDp!817i{!B|XZN3W9z1aDP1M(pkardEELR_WI+SjpaTL8O{c<`Xml<6l=R@0zLiW}U;;9ENe-+T|_342s~W|c#cwm7P=vK5MjXQ`t4mzAMe<|KLRLj}IsKM5M6XP|kD358x~(V_krbSx<6u94uKc!pU*4 z$!f0mIM)2f6cAl@uzCK+8kMmF&Fvocf0salCwqSk^Iybye++Xk!mA&^z3DsP_kd>Tm(hJad1vB4$cYotYXhA7Ognac;cGg_(6$I!+6?T?Z`6*(SX{q;?SYGlEeZ( z9%)5&glF*R88IEndmz<~GmxI|H(bA^Gdj~9k3wJ?wh&FWNwU5L*h*kzWg46aaY zvtoZ#>_x?1QLGBGB!rm?c~- z5$gI;i)#z~`{h*$1QCNPR;p4A`0qw$f4&PvM6Fo)vp# zs&Vev7uA~_e(7siICs%GsM6=g7vtCWO}c5`y4%D&Z{1nNbbzgRE08@V8sS7y=9jaq zM*l5k8L807onR2*KrotL1baa-Pc_||73+Y`vC(daQIMN9jA3f+_A=FJ_)N%WWV~ZU z(TI;3dZ_SutzN={uqLFf@Nd!u*?pO>!>1F z7J&@QZro8U8|bl&iFTf4`&yQ*Q>V( z$L&JiKF8!?l{5S0nB^meT}yTpyY}$d#Y8*Hu9Rih@0DGo#Pdh6kAVw|`dFCq?bvsJtr~o+zGEtv_#nfpS-!d)c4az=J zvgUwbm*bTM+ia=IfV~C5@@V{bBS73arwo`ortj(~kCo9W24lvU`3E!4U)(rte)BmE zEpz5U5IbN-1|Qrzj|^^2<#$bkzept$^Vv8QS^Zjfr~Q+Xfoj1xP%W7D(BWebf7+-o zZH1YbA%?i!5G87eqw{CH<#fV^u3tc-h#VffPCBS|v>IH&n#g~{mPPrBX5S+HV`+$S z(#6Dlw#222`HlO>uCqDmPtkDYOT!u<){<|%V$H8eFfoIh(}<9V|dG%h@=g)(+VLr2)~^TZx` z#BAqaH_zva>!?+7u0eO>v{cv?*^N>%QX5XkZa&LrH>L2SDutxN-~z=iwv<0^1n=#w zv+V1LIJN-Gm@PSkWsTk{gGw9byjh)>InGGS6|f6)!@WHd^WWa|I|sR};L2>R#@Q7o z%BwkG>CK|@;;uTTPCHB4MGF4$xF^_rOUVkOg59B*G1X;OEU3XmmzJ6|S6QjAYkw}& z{#2&@CCq|ZNhf%$z%sRFP}PZRU#_}%0v7bZs^w!d?MGK@c~v9o*H*SQHkdvnhs z%m8{lGh|(+ZLQh2=-h605|8AgeIxTVJJY_PW?rVfrDiE6`qa-_-yeCD89uZj_D3l$ zHS6^D2QNy4>wvvzuvf0S%>Q{E)G7D^xxw59v<2~*K%8{WR)N>wCDnI}7IUGy zMNLD@(o~0xr?@Sc*K7=qG(hf&$lP&=(*o!&D#xDoeiyTh4yG}f*nFKXL6eQWJO1@D z!T(`G&(qkwA_bchlv0Oh*QCmh=;f7nJF`e`?B(6CQ;V`|Fmq@`m@30EkU7uHzw|RR ziiTwGPn8Y*kaxrGOO)M&8f35T+?!}`SAg=&D9Rwen@s-Q)K6^Z=l##Xto@q#?^gTl z61-{t_s%~9=^hhcq?v(q0GQ=_P?~LwN=vf8uAE!GcdEKu-kC@I7R=qBO=6{nyX?R{ zWB!+*_~wRIeA;(G{290oR`knW&Lzo~Ag23rzcopcVyzIHhgna6zeESZGtR+sEl4hb6MviwQh@-y-X zgVvUuj*L|FVn&vflTWjb!tBi!`w(ikJa)l<4KTIA-k*lga=N+S&A&gP(TjhfxgU1O zv_C-CeE@P&QF1y&qid?VqytmP06uH3No&`L2>1hNXW@-fl?V9HN`d?j;`s42goI5? zy-8JmDwM7r+avfETp9-faTCt2MHBK(oGflE*c3CSLeXJ~=BK?GCkye9ac;rMGD{(1 z-uQ7iLG41E%-An+Qg9x|xd|t~$fGzP!?_vf?{WSC=kqvAz@t)}6*$SS5a(Vv_r@8W z@OH=uY&h4W$2?@5HQw|ttnr8}27;7;NG&$H$BX#KqreO})~#_J?XD8pDPaMkW@0-f zq)dXa1KX=y{GAfCQjYC_kiVG^>{bR;Xr`m35TiP&(8!-)4fZbPN^7`}D)w>3S{3_} zV%I2kgJRUMD{QobWSt<`}#1(5&U%sx1`; zgV1)rf>ysW7-}heH&7CeEjuaLEEKy?v9+KMgiuum8!SbI^>P-=EjVQ#FT^gzW)WLN zc}2M3UIRHTA6tI}yLagd{WyMf4@ypLnYU!&*{6@mtw!qGtUGQ9YNyZ5nTILdiCfrC zoZ+o(3U3E*Tjc3=6YIU3Gct9PcohV;e_TSRu6;Xb*SRWib#@u5+UejL)#YC1Bcv^bkI=TI+I)fkv0J~| z4rF(4Wj86q?woW#v7OSb!wdhDZY$k;D7#6;r2BvDHg(btl(WW<0 zt=T4pY`1PfUm@2eD>mn;r2g02n)BT?=cEk7muf$z*lZ_u8{gJ!b4&HgAPo^9Wf-2t zAMFDdoAY;`;XO6yqzuDnE5oNnB%GsDCl)W^vBiG2zeKVz@21%$WwM*=c+HAr_dEoj zQG9m2i4Qv_t0~PYshB9gx3apEW|fr5YR-C47vbvp;Og@R)gi9sHMi}8Xe8rjQ9&2d!06=^A4M5HlDM10T#bHjOHS|eDjg${6Tr zWak(;2IP!gC~au@$=QXt0hsfGs6s|L0$YnfOxzoR9SZ1+cp75jpv!r&W< zaZFIc?Pz|#iIgud!0)TaAb>fFlPHi7QcG@LtTY5}xe|^MS?EK-Dg2YI(3|o(VbtB77y@_i_vfHuUHn+II;4yYu z+>oBNejIMgY_ut$q!@h|RJ0huUl9ACMrZi`KYL#SUsqB6f766E+ys(9fdUm?OMplV zbYW>(O42sv1ri!)3q`hsHqdI9kS5TwrW-Uoo|L7CiW(FY6}2v4MU+4bl+}t02&h%` z2Z#%ZVnL+;?|073dGl`W%Tfx8{_p4W-aYqw=gz%z=FFKh+Zm4bnRy;Kzdjs)=ID2} z+O-6I$;j(Z&dNv*EX!P_Q%#}D%sw5A?8yw($;y_&{y>=Bjbe14mV42o&uEi4S?)#G zjBbc9$8xWOP4LWeFA1I>yRzj7e>Im|?sbGekmd()%e@A>036LpnAgc)MtyK(?cJlJXHtTFNHIES6zmwq zI9@GStzy=ZYU&qnJdoEK-oy0UN@Be@LZyski!-gFsQa~Hz%VWwutHcFr=|Klq|k@z zVc%8VBzZ@?m*d79gUv|tjy+Zn*J<@|rKge@xtCXnl{Lf=)k>tq)tX?P_HG#5so~Zt z7ST$z>7@-|JycUoDp{ZUYt8s%vL>~7W=+Y&WU}g^%BrB|=q+spP)T1+rf-1WMbH!K zljBcFCQ}#BOqNVMA^Fh6svvpvTQ*R(w(2quIBi8OfCf9CLXRIFpMNDmMPkNTpXehGuht7oX5WbxF3NT%+YH9g?ey&%$q zN{S1@;>v-(-a3;v_CLyphC@1w_o?z{7n}$P9?MRJyRw2Ex^E0eOQX)DdKYVXVCI3j zKG;kR+YfYJkhNB|+T51OIVV8ZN$_mtbsOJWSX^+1ubX!I5WoYVd?=0&*?e)qi?Z~yOJbIOc1i3_ zKNsxjCo#8%=6j!J&oTp`28Bcf#7u^eq;`Fdlr68_&G;U{LnZD zPXi$E`S>{;OxJ!5GEZ_bTB|R&0i1 zjfyoXwgc=7iH}3^^6YMkftMCLOfhWwVzJ4JB^8S(EzAu}y+x0?QZcwi`&SOZ1C?() zOfx9~(oNR0HWFsrshPxr%*{s%f&?hp*!(C^*(&I>NYK!{Y%>WJr%^$$*@GHBVh&FQ z{nrhG_trLAeO;EG%v5%wp;)u;Vwg0(m&$K16dVqUe-$-+*Z3fK9>3q>R{=IVq36py zp_jUFql!JLFsQ;S1*^7H7*KQtqv%SwK8n?9e3KQcn?d#>R$Q0Aphgki0jXw7# zR$Jc-vAQ4P^ke*<#&1tgtoX8SV)e9&6)6!b!6;UOQLF@`SP9lgvD)6+>Slbv?mcL$ zlXHmGf6K6MZvypAlw;4H+dg{ghY+N{5Cs2Mp;!oTlawr~jUD*WLsw@m^@C`yfa!;`b_kzJ}t2vG{0N+fIShw9G;;R(=97& zZF}vF9Skctwj}qrH`ZAdjL>H;i|ZQgf+Z#E&;;W;G{HWl;XbQaZr)ZROfr>=x3Wdf zaD>S=LN^hK^ws&i{Xh1Hn8V{OMv7&GxVi=Y=Xz!6=waK1q1T}SHm3}hcfdt{FXHDI z%olhJCVxwmzof$83dNRNDh#ewj2++-Zd>_Vff5oor0^7CZs>u(5AA~h=E&ynw5AK% znikAz%8bPKrY{Cf-cDS0g9s1f(;SBxxyNDA4`Wn6kP3s9NQYn@mI{M4ihWYC+&rF% zFu7&;kZt7gBXK;AojTAPkN4T$Jbu*UF(dEB<0F*Eq=d(Uk;j6O$AXc^g5~CMCBo$9 zaV|aa13VRVE$His@o{>hI@*#l*P!QA`k_gQyFkI(kwU?) zu~bn&t4FZy&Ch()mgye!!i3%MYIAscp=LpITk9!JAH}?J%oq1&tWRt^@4TiK<85fc zqVpEEV39R;{XjRQ_XK^T_L>W;QA2EpT*# zh}4t6*Q?Bvl6`~)yVBkbjh9HlZc=P}^Y_PyIqJ#6=kJ6b_&d3=wQ-6O>^^XK{PyPX zariPP!HnFOV5tjlQXZ2MuN8t}d?gUh|5vdV?JQj>mPrz~?&U`X%K#DUo5pD8qt%Uc-G+u{fTqgMzC# zVNNEI6oSfKQ%VOfR~t(QFH2vxZT$-%vm$vh5g3$Qa2S3k# z5Kr}_TfP`)19sb>xevN!3UaVdeC~O!&ULC!7@;rO!q+yf6G@3a5sVxb>_$t8J`pT3 zzFmqSFX0D{<{aPtJ8mzJh$$LWI=+1cFU;YYB30*Nty<%()>E<#k<9#zy0&?(bDQB= z8m7pFO~vYJ#FPyhwH(^BGHLa=)k zi`kPk*Q5d_L9_(LFk4GJ3FOQO`$qud^n(5It3x@I!()Hc!%nXXIVO3Y&f=I1k0@%DiJ2PW>|%{#A${& z{vL*ykk@8X-=tXnX6^pl2f59;H*o(tjWR|Z4QI#SZu5m{426TuZ81ieI<_-!S9oQdk^8(QYyYIIB_-~51^cYM z8wOv|a9>v}Q^H-NAoXUlBM(!|-Bb|SWVv=$rQ2k=rekuU*<{&hQn6#_Ai{WcuoLcF zj#gv=s#>=R^P!+*6Xs(<$tKKGL1o(tZv%<;P&5KV`mp2ylYrusMfdd>y|pE{gL15m zD_)5><|CD6ZPwg0ZU$XEC@jtoiz{|;{#>|+GiNvTJgdnyIv9o9%b5)-euEZ$1$Eeo= zm2*p@{;GFp(sAb{r>wedcVt?7AJ-y9N@jow)(LJ1cBiF^g0+hE(^QuI4=Bso;{ODY zGa?nh2w=2BXexg@R{Z_lk@`>vMD|X4_m;Bn^FO+;k~H?NRFNiyjct$?!B$u*G+ohx z-KbccNUM@MezE8wMwVN;&%z4}P>Nmq1b*MipvOA^LTK zKrl3d3?-|*1p96WgA_YNu{g~n>ZlTNRU z)cS&TTB<0xO|cBWYtvQDcD=>q)T2EuxJaGYkW5c2&Ar;9>W%w3*?AM*(oHd$1s1b$ zCtLpv%%|hd>^aRBA`~l&kKs3n-38|G^beOz^dUPgIVQ_0WyM@(qBRYMN=bqb zLprjRl3P`9vcE3EttvR#Uo_wca0@5K`T@Epv#fY;`1{PPe6wpq4(cJ93G>~Vg%e}V zb!o0-?q-uIy$^YI6YYZ7g%ep@Hn}ABwvSl>rUPYsdiLDJI2F2=b=3A=IN=I3#nWr5 zh-DY5J|-2S!GM2*U1F&)pk@{<-0Z8dCI8 zAL)uHlyQh5cr3eX7w@urNV26QuIn*5F`~p@0TOLy(c)(_i}vGFam}pgg8$xZ{)kKa zOf&0{h&C_H@&|18mmD;(cn|f+p1>EmqtFonmrA)TaXS&ZEQvb6XRkt~DU_ouB~38F z*aRabm9b#VF2OPd!8N>GXAzvX8|I7I!@P(u7VHfYKlo&;_`&CQWLK=O1Bq6w6M?Z} zJq*8PyW-Cro=5z7^A^tPLm8+HWE7)3WWFb3=*%_~yUJ0}=>=LBP0S}^v`3HE;F6`MCbm7~ie zd8Jz;^r0N(+&JMq%pljaU*ZE8fFi``R&35-dx5$ublV%@SfCk(bRJ} zEpl7pNlX|y3R5LdX*!RtugCCj_L2pS^XJY=U`Ev9xvidK-UKFBCJtP5&ippqIq<+N zOLin`eQ3gB)qdnz%mH=liWMIjjo(G6gvF;X^Xku97m^C~>FUo&XB@b?;i-^VYy9>rN6gK+O)npEcS zjMaYl4yc+nt7*}qWaFYarePKF6p-m1Ei}EM?p@hudIO?9;CDrqa(CPMlVPG8Fg|a0 z6MRv5K}y!C2*$oq!8Tb+_Iwj8nXVe547&+}Ss7XEwF4gFL8d-StI`}E!?4m>%5=oR zg1-Wq(+fNy#H|mO8*uO2W9R)rEr~Fk*tEpR!sXZHFx7hAA1fmZjKH_Ax(NgGB`OT7 z?CwtwsW6bjK0L@*!RA^D4geHet5}vWTm$%s9)#gX{S*dWxBOou4BqfbHxc;LyA=UO z;EBLrk>Lqb_~frA0r;5;0I4wG77T)M3kJbD6}wHbECE;z_^2KP;PrkAKxUUwuQ)*! ze1IHFdmr96J@C2J?@|vif^8In+f)chg#oi(uvwN017^KocPN%61gij#=|Kp7-%lZM z>w>#0fe)q_^rQiHezzKc5o}}T->sQXDhy6TJ_<%%AlNO6Q5Oh?t=F)D!qxRXm3 zV#_k@t9WujGXDX1-KtPS;d@X)(e16-D?%e-Py9B(R+hsv6fkyqAq;g?k-FyBRhw=F zgQ+`zfh7d7-5jB@qbgj~S!ZWQjRMLDEZcSt#+T95N?N*tv85~6cPv#D zkSl^ct{6EinDDg<+w0xGWovyhxx*^l%97Y`B5O~K=&`*Jh+O6H$8UPoW7Jq)v-N+{ zyv-D0Q&MN;QgFq6EUApZ6Q^Qi1dn-ubCgu(S=8*EV9nn9ROgWjgJ$HpV6B!4gRdz@ ziI8v`6?kqB=g+r6j{aAgTe=~$(MV6dTaCmBVnpaU)kskpVm?J>=xD2uo>UnkCGBv* z*bW!$^OhK4HX25_AhYKPj{`(;m2buT8uVxtj%;A~(+qmiweQ0g- z+vcH>U<&iMF*p}nAB14Ugt8+?^LC>dhUTy|2WUCC!dWczpe4snChPzc_FQwXUhnOS zdmky|B)MUU>~a?lJb!h=@Q~&B4ak3B&9~upLBX_UxWzqrl5= zk&TQj6nXcevQX4ZC%qfMbNSEC_(=XUe$3 zHpg0yX$y>e1TOgR1{G`As@LvELg01VyqREw^dL`g=QOa!TyQRf}M#61#7TW7`V)S z6#4xULShySSE3`AsaKzaY-aM7Gl{z*dCTl%-coP95NBv88zXt!b3=N&?FP%8T=f$) zC#PPQBPVz4mXkA&>MbW-?lDp?_kwN}K6#ZZ|9${Yi=HPH2Apvx7%OPOD#3rjCR=Lz z=HD~@%)cJm8t-xb-S=MPA0yr7{CiyUkCfz}V9Y)|BI?p?yc}QDnqmLOT65it+DH0a)EH@2R`si_-K=>< zDhxIuhXnhnrNUq&cx}U3s<*P1omYF{sju~rSFiOmuX<>ZZO`1={9fc1BlUADTCeq_ z7r&x;MJj}C5d?z4LN=7-l??~3OE_1r^=QPD;mvVI%(oDAGLm`2fH@=PBhE_CvTU6Z z6IbEvhK5FLDcBa%!Bsen)aPrrLcnish!_mbwv*x;Fx#ZUAr-nvs4(6rGioa zNI2Wu!?o(ATkD4;QyYy<_V}&{@gVHFOkHp;Bz<#)ldkWO=b_AdbF9i(#N9{TBcmIb z1tpb&r{D2VB$TYzntQQvXxKb^;lh?FZ42P@aNz$Hti3HG$cBwF*TV=r3Sb$Di0UfxHri?PS34Q&r)q2TFhkMe=0RhCqEf#1D2T=QOv10#(m&peh>|HY zRWCVqL$YHr?Y){vgCye@7olH+JPb6_&X|BBh0z8fn44xiF{lcN!YSXqq0F<=t zj{x;a=&^#}SWp9uZa*H>P<(GjBMrlsMZ1G)5o%BTcxEA$!;`sQ<$;xHZr$+D>KwXZ zf76cZ#QS!Jju?P5TjUc_y--h(Z{3ekRb|0Jm{5czo_?z9ju%%qqY7*I!k*OY~wEENXaHcrAFV=2rc05!Il@vX2F%9dhpDV9uMoj~L-<7c{F zE;ABL9cl`}VR>dOZU@}G3g48GZV@EmBp+9?}C5br4Jf>n4=3k2fz^Z0@mG3^Vs8o9oPA!!W3V z%%ZGsp}($puMsZScf!mb?mF27-53#&<4kM=QG`w^bHP8E5dB3la7Updz@f}=1>fVE z2~3t&YGq~hctE}nJ>A!?quGptF+~*Ygs$${gYy+AQJ?mbjW*I zUkb*t48g24J3&r%OfN5;QFUt7Y031w^6#Nu?Lw4wsaI>U&sgfUhpWGYOVqPfrO8=~ zA>U_~SouzEf?y}pkn;Q=ZJh@Bo|2@D*Q9=)OxJzG2sj>Q2HnF#sbF&Xmg2VElIa=W z090bat^PjbJa}cV+H^I*8NWuXZhy1tUw@yB?l|j9C`>hW2Z`m66##f+{eaekm%s2Y zbFc0n$?AtT=`UMSu*vO*-sYzOY$17cEl6!$P)+RiGBIRzIfu$_$QL7 zx`z?$J_frF!G07UtS0qvZTgn-E_`WC>WoB9YSE~g)FtC;QZH1UQ+4)P>mQ$lJ5rd> z2PK91Qc#$07ZjMi9!44J4q%mrx(}3KG@WE$+X`f&P&AW-qFA!B90UJD$Gu|2P{2!FAuX@-7c*vnurY>3k#iM;F6>6+eLB&Yyy6q>L#P3dBJpZozwHd zXmi^+9nA#y-4oCQ%D{r+!liJ{nbB;{7t7K~{+fS3g!Ow+xb$EbA||;5CBv*p7ODK~tP3}-1)#MI!iQ(A~p~)TSLUd1V`%hz%+x}9Y zllyz77P(9BIVZvlp!a&$st*7m&51 zACJ_v$GY1+)U`A(xPH=ov1>E5Kw1meicxr&MqsXuAuHf5L1Us0^mc+)!{S>$KmG=>cMCgJ`s(K!w~>(DB5ZM zVNjx->H+)Pna0Phz|QJ-yy4!!wuEpq*SE5<&2LTMmpQiaTgUYBt%-N{t=pBa zV|)45KJt|&XShDAVBc1ZyO|5dt`1URzzRb! z)|`UTAP|hzzhE4C7py_CVl>hOE436>Iw+P<4ATm2xZ@N%QL(9t{Zp~6iWTL%XG<&< z28Sp%MzINsO;l_m3@iD*DV7R@eArlm(b^(~Z&oa!*rlKjGmZ3iONGHt6nk2+3JCod zOt_JjLbE`z<%<0j)T1WcGnNX25rZ6dsHM<30BW-dx583k@U&vjDTdAg>KV2oOhG-t zSe%tJ(4Wx1Fz3vjwH|6VhJo@Ata?bJMZZCTk&Aem}%yz%A7R}9C4u`}<;qiEmT)sX9v z!0&)aNDG#fIG_}4nY}9xRt4)+tjkhG!3M?lMOq~sb4uc4-}XuX?z8tDOEKr(c`*cU*R4 zvg54djKr?!Y907c_3?SH?1!%9LVj?1C!Wkrh03;l(&)*lJrVkocz_F)7|40S4~ z#fEAGb&;Xwfx6I8tVY@l#Y*8HhGHK7!St6u2I_S~Z31=0j*NLTs2L{QE1<@jyMF`q zJA(~Cz8_(*L7)WV9FKzyMqiGCvC+$IjS5V4BN+FOJ;q>_8jhV%#~F+x2NKR{h~EH- z`mtx<2s)rlX{kUgA@e?04nd1K-m!3LVgR|0?`C@Vgqn6n;!S6G7#- z7EgQo`|Jv69UyXcYM$k+blsWJ1;nTa^SBe$Eo$|k+@hHNY5MLC$C(`?a7e-Ik@?)Hisx2Rx?3i3WDw#fQmBm)oveWo6cH&j?UV@L3nF@{2s+7m{i;p#S zs51=3N@$CrJ_<@S!UalQ2ugIrN>HL3t^;+TDYxY5b>`WxfI7%vG(`n-W%*uk@AybZ z*AEd2)l@*uL~)kGtL?qEPPY=A)4}sjTE;LigJW&(5?jw2U^w3L($W#hH0}9?rB%C^1q-NreGxC&Bo3!7f#-U9rz7cB^7vQ|z0H zy{OnLifuxs$UA;&DO+wcBSL07X&BDQ^yw@_?shJ|44wxVPkhqmY_2~OXO6=8)^WTX_RiJ-1V z87K(q^)3tJ7fn^{3eS^BLev{v8$u1nuK~YX5WgH=;n5kyx(~pj=}q&S=V5aCF_@0d zImV_=G%hYprFhAN9Om*!bGx#Xx8cP~s>Dozk$tpSle1>#a{FCSP~L&|$qTUSUt1Gr zx|>4AX6B(LOr^Qb*xZMjQkswYDKBW2PhvgGs&aqxz*O@<#sJ?xtKR((Z0dofC|bpX zc7_ANXxVXPW+;N~jUUTQ!bB^7%zHWfY3_`aWrW#9-dH=H&^SQk$J9K-kKF-P0%Dq{ z=4H~%;*B* z;CvO%XX3mH=LVdw#+l)6hJ;B0Bqbj71iRAS4NY&9V7DvAA|}{fiv3KnUnur_#a>oy zAaYKgWrsDXFxXu&8j6DbPO+C1vrP&&bi3^Zbx8MunoQ*<`&3j%Blio8&WkIma<_X? z{R0xQBvQ{^1g5a4LN5k4LGQ}Z$D-;@k??n&NX%NeU{P!0pqOI3!;Rag7|-ZKF`n4p zVtn$yw-}Q*?`bh+UT@E0Oqp@T_)V=xNrk~@aZj+%TPh5GpxFJ2J)zi-6?;vwzblpp z*_HS>3sBxMT(JWb8>83}ilL=ppDnOd5B2Q@nfmq@THkIl^{CXhm|USoF6!G4)utYf z)VE0tSf?H{kMyD19n@o4mb;m5T3bK#PT?`h5Ie9F9M8^t)7NwzrH{ z$DcZR`;_C4TIOsh)2t(r_-j;T|a zWpzAGr=bsPV{*i!$>nbrwV?a&gra1}RLr#cQO)u#B^Tx=Qzgmt(6Xv^;09twci?Uy zq*LvoNkzdc!#QgO4eSI1)Qa;`JYAKpFS0sdOEUE{*Dj_FUYShQm)52#htwRsY0;i| zV_vc&S?XRFocC}+>CwR}yCB}GZyt@lJVcdeqH4c95tOWCpJy_4Qlb44`LeC%t5$ZE ztSsPd*YM8t8_E+W7bQnLP_l1ja9+v2E0~U8a>?Bxegy-nM{H~>Om2Ok8hY*z)hiz< zS$Pi=l$uiNCpnqg$8aw_Z3ucH-K3gnNnA)TK{9>A&3G=EzLqE9K>CKw0`cUaQuCeH z^5mdOfp~IIvp_sKs8b-G9JEOwo(%NRltdnNFDAi3UvnND`uEQ<;|yJU(smkw50QRG zTF~vLNwWylpN8`8Vo<};Tr3E#Q|vRK4uq*#fHh;-(9S%;cl{CBUJ(3C!*Sl_x#liq zS>DF}YIz%_THbb^Vjlw~jjAg^iFUt6sn3C0W#0QO#U51Z8KquP>K&yxQ#ZS|NTJ z9)5j}iez`A#Mvm@-F#2!0KZ4EahU1(IJW&8oR;yqT{IHT+(_afYAE!?VX(Ro5fIBW zYn`Z;3sLDD9Tevc_c}x#WP}Cz?cc!PE=3jS4w*7=VDT;kTx)G1Y-6?@%h9mHT!E?c zW}mYND>lqWvbDL6Fe)rJbL5Zax-xIKU`XB&?>*5#JKTIbC2HNOYBU71M`nYf(L`ABQeEf&!Tehb-42NR|pcvSK%Y) z-tagbPXCLt-nWEN*B0+~K3RAoG9@oKXUg1`MXjSvme3errN%|_jH*UI{o=eQgD)92 z_9eVl-CQ;P*59c0l3TaUuv7^4M{SH-b1vF!N7c zM9YRLWOo6N2cR;kpElqO^&C8i^M3Za!d|nyJp}w5ykH~F3vqq~=iLz3qc~HyJ&7~B z9DW0hEnN0(9IOD<@7A&(p z85ZI$#y2gfSKf_jK{KDG1wB90w73*!nikYk&b0WrniiyF$ZZz=YUVqEYb@qNTnVZer@U>{ZNi;8_ku|r@KNVqYU!W1&aCMx!I#lEH3%ZmL; zu{Ra_mtvgvDDU9BM^a&MGIYFP)b@hSQ>58l%z<|WpJnH!IlO9N zV%vG=HMN*U^qwaw3?;Ut z=yUyNQIvINWcA<4u7fPQexvLnCENT8b``iF*d|NKt}KEX2Ya3M$N}Vou{X%nDAz(@ zJjlJy?ZmauG|>7w^~CBJE8ID?urz5@77`JlPt{cBXF=SmBrP z*@2YtSy~m43WGL;6%1`(Lxlkv#}>OuF}5uw+!n=>%U{m0oi{UVzYKv+4+fOs6ghSb z^3Q0U)3)GaXC0NXoqJ<=L*wj^wk^VP^-D&N8Fkr#-BckJpB$a-0}M}a#YXwA#Z+kt zOQDfzc0iD2l4H8i{aUe}&+eP`@qY&rojih$2qce=2H>$7%$LK{^YocDF5~msla`oi zB}RvRc5)7tKgg*3QFuiUf|T)#k|-BJs&HSGb#}#<(eaJ8_)?JAibO?Xr_?DS_yo-U@I&Y2DJJF`?6x}C=!g> zBhR9=EcQK*OfGNWq{+lfcq%iP?{7UQ|@M*>bi=*Xi1x9G?t z>L@5P!6@N9%x{Rw{+vK$e{W?osSu+Vu#k|tB9kgoVbBRo!rf*m<6Um)A6Mhj=j)2{ zc7yz)YAq(cW*oRcha(`SyH@H<{>kNLP>(mN$39ZEb^yJ;WIc4^%``B8R&K4wVBCot zvo9O6E>rR;UiefO-|5GYdbJypfQV#=p*fReIP`@;H{{(8Jp;#SN7>W{{0OK>Y(3fGAefVG_@>(V=t|D z{IQq^ksS0V?T=;nQq&GWQDY~8nTjWKG2NrVf=i*I&8ai zB6P&ixdV{aPrD%u6F&;Ssd<`k!b~Xn;lXy~iL%Nm!w_n?50C@V zv{S%-g7YMte};1d&OgU_A&=&UiNXCC)G6 z{41PUCVq`GmGeP(_uPK33+~O3%M_l-8sQl6cT0tt>v9Z=6MYwqQs9EcioFY1>B0qr zVv2wZMIn)+Zwr(;gfjo*#j&E<598N43@sS5==79LTaMXrj9UvEt~zimo`nx zRlLr!(TX?WRlF6bOfdn+)RhUTTPw3JogrkZJR4Q27V*3KZuy4hGuE?pCY9YVP*T}d zfRf7YFi=w2HG+~Vj+&{$d_LP~*;O3Z*i4O7amx{EH~gCM`+8gz=M6@9?Ud}DG9s%* zSg#F1eDwa7JsL5jr+RJw-s`o!O|7#UG51=piNCj-5tMFFq+VOpbb*N=0W_}K8WOFx z+_kH+$R&4BP~^x}Wi{Y7El5^b?V!DtAhg|A0m`bfn66Ryd36)3ET&<^EBhPVI;zztSX#T zXsTVo7TddFutLKzyCvMMiruc*2E{fi_7}xoSL`K}EqTWuEfoe^6k`dOchG@=gd1!r zH19wiVN~e~ONGI&6?;Lkfl#0lF0@n_R46u5v8X@2(MIo3&24R@OV@bX|o;?L_KshW1uXj#%}bPn9gyPmWYhvn=D>7fIpr#y9?9)#_n}`lmgNc z$`Zy8=244qo*kAjp!_jy4M;q4LOac0DVB!du4v{;olgo|i6M+&3oI1|S1FcKjJB7A zBRA#QR~7r4V(ThF>JS7cc6>3yc@}jZthCP9%aHimqD-a)Y-9t#Jb1egBatcRr7C%2@97chH9sdEDvNi^p$`3h?y>!k)We zkca@23WFAe73@MwiML3>sM92zS#o3-8o_DBCb%zv>x!DxQ&{4=wLXzdVRavuB*ri96a1#Ge zyoWO>xOP1O>B$Rb%kwmDXzc820*H?^jFU$7sjykK6_g7aJFm;jlk`o2c~6AWt)mI*nW{ExyVlVo$4OXN_M2mI`*dG@n+ z0ayu;pEfm5KFzJAFdXrN#cXxGYCu-I0gZDbmBUP3S{0yCFmqIPl|Qem)Cu@1%7C`Kui z?^~-FXT1qlIb+(Xr&Ud_vR)(aEPn>RIN+?K0!7|$Labyrb}d%0C+kvMYE!?hO}(7# zn6Y{68}Oov7DCm{&ZFebFX3D9C_PHnr0Z@LkCNKNsNRxHSHGIm+=8pucg=CI;~0*`(i?Og)nn4>*W+GlL;o zb55;!m6x&6Qj4VPBt=TBz>0!>;6tD;UAGDEUCaK?dfb&I$g6ANUly5xB~bQr;6A{n zynrdUpW4Znrqldld$-VJnXn7d32$ptuO|D?4m`q0`;%1TQ`CKGO?o9e|7y}{TDmpq zH5+lNOQ*M()5;3m6E6u6yb3x-NEjy6q@;6o`IC7zrR^^J^-ihB1Iey*Ct|fcNLU`& zj1(Ru4G;R8plxE?&s`Fjxpk=xnu#uVYq+$0qxsrxlBku>m8`r2=}n?>J|{VzE%cI! z{7+4X%ZD67h|)T~ZZ-X*u1=;4}cnL?$VsCG}Lbt<4UUW24iQUxN$uW)bR%6 zA_|#+xm53dT(M7pI@*N03sk+Kegvw@P=5k7$xvK7DY3BoOWrY0sf+dQ_dumgTjnRA zB$n4eNi2mhkR+C4K}jslN?odVZvZ9V@;Oiw%oqGb!wrOSBhMbJ)O4lJ2GwAm;N&9d z#o?^x7Y*+}0ZRPvuLaeCdbA+;E~wv_yR`qa$If=bK=f%5i*zGG9SolH{Lpw1=I|Q= z3((=+Iu{Phvl{DaLYdy%MPj-CCtBC!VKn*i9cO1rC?Bx-oXwxHV>!X9&Vnv zIxpKx*hI79UyP8O3TS|3?4#4n+xYB#_+g5E{tpMpPLJZHvBk6_*5VGE8@EnmnE4B5 z%TUIvxL^y?25mB7>up#IBFzSF2kftkxM?3V>@ni};*ycYJC?esg>)1;D*-9M&v!#Q zbr?FOc0HftBK-Nc#6xMF>vy7uQU=-0oBG;`mla>OY(w#w%Uv+eU-W&d8b`rnmQRdv zCA<9GKD&}V2g2%m&TTW-`G$G>;ZDSJZjHIUpUJ-y(Ca0^2ci*NSH_5VIM2DuXZxsg zA-jCGV+qfG2 zw6Ac1Gdw$)mFHCE%gNo;NYc)7FX@&#(qDOkeSwgRHCVt zPK)97(nWpdb+b|T8JFf)n(LgR#fithXi4yRUN3Ene>*N=L;IYt zJtGM_)La+k(nomN@%5!Oxe$PW?x3$e^u{%{;~ zmOtz>#}DBY%5scqc2_8WgDF$I)AE}g+b)h#*oHL+tQZr+niW&}%$iBC=6t1dy1Cvl z7h8@nw==%|C3w8E`xQw)!A|L{z{^N+);AII98;h?z-*GmZ9+fH1pqISoRjOP{^ zEAe9%U5g)$(8usA!dDgJw-bI$F|`}*CRUZS=xH0V8l$;>8h#hzNBf+`nKP0&#Kz&> z(yX1n#vXo{8Srh!UABvCM=VEd+W}>}Ctd|4}3)iIj~L zwp*s=nRW|Dk=aDCk2L8>vjx~*VV~`6gyEr^0m$54_7%B(_B+@9W=iz8~i|aAp;QwtM^aIHR|z{R=q1iSs=;zlHPVNWs5w{sGS5RXZnk zyo2j@2C%3eq?N!-^T;ZbMNro;^&xF6m7U>jWLft z%+zDHnTNKNY-_ewUm;bl*JN}-UiE@xH6LAodM^N*o%S8f8W*J93zB<;D>L@|KJ(`A z4;pXEAUEelhb%8DwhS9>r!*cCUkziHz7t96gFnPs7_8u`$E( z?;mgc{V`fp)-y%wf0;M_ejNXwH%(c(*x&!-gTb4)dg{H=H={pLg^Kmm`=@VutHS^D z^v(MyH{(7?6;&?#<~=G?<3DJ;i7QhdMp@(d9$H!6@ow##-b}y!dbe-(>&?EAIC`{i z`ncuO`ztqNj`*O-&HJZs#vJ)U<4s(ddT;d22TE+-=QhI!N^F9W(6k>#M}*9XBo)FH zl*8IB6`KAO3Ab9YuWLBYm5^tDsMrIFJ*(KS6#Ii>e^v~AE%sZ`yJF+x=5X@fNtOx& zZVo5dG{qJu)}k2uZ6w?>#kftJVB98-6gvME;{d2&XDQaG*nGtyh{{ztlea zS;aoD*bfxDU$G|?`>|q|q5n$aTWYB=;N&>Lu2bwz#nvizuVP(_y^IP~p8b=h!r)EC z{-xLubSg-=p_amYdBsL5_JCp!DfX0NKUeHE#s01sTz=Yj>|m)dSfbcviao8^bBevF z*ei;Km^C8bytAdkU@yh?QS7gZy`dOfU)pB}S}F{NDYn02qZK<`vEL~6d&OQ;?C*+| zLb~Mp23sl&5{i{8wn?#{Dz;fM?s&ym!eFan`B3YEl~@XXITicZPM9}>e(a)Pp`}7| zE#JbKH1ce@rHXP^=yksdXuPbp_jith1j$-o^>rgDM*qw^4Rg4|9%gj3p zEENWgiZv;=La|kf-LBY|72BxTW>D9fcl^#$ zVNivEAi=6F6$Y~vo1@rD#X1zbL$Ny*dmGfh%saSi9jP!l(^5r2gJM@Gwp_7J#coq< zy@ zDz;9sdlmbIV!u@EZN)GaZ(q(#AWONGH&#lEB1PZWDvvA-#{MX^2haq;bK zDeQO!YDe>qW=n;^RT^wn#9RCaU)+8&E`VqijJ(6II0!+P7!R_eC1mG5Bw?`8yk2|suz%HDPsFWnRy zeb!4aLnUrLJ3cIv2nSh1%tt~p>=v~)@wk)hekVSrthZ`X~AK!jV8s3$vNvEKLD?z zAyHu5!&Vw$IvJQu6P^o7CRcwNluQ$TNGaI6rdjq1zB%gQXfy7iCZspV;IZ-eGe>XJ zdSzSo=m@Fl+bIR_W0#!`G4l$zJPLXi$HjOrcNEJDI?eS2=zyJjoa%cJisXbc4u9ui zyMpYgymC)Eg<8#=+X}?meM&_;^l4^#DM$L@t-XC+pQlvZWxh2tbL=s5Jvi5dncL0n z%#;cj+@Cz*=D4=ss_vW^qTMBZAV(vcP$JVuIM$LzcI z1Zb>EY#)L12{=P&UL4UjI`@nC1SUK*y`__+6Sz21;y0u7&XE?!D*t@c=l3+I~)~V0lrq~0D zu?~~?ex=xN72_fwiLc&LFsl`7Q0x-Lu23wc*tLosHNeHk$<*@R6BIj1G5WKS_s&<0 z{%i!hOfeQT!3r#ejS@hOGbZ$GONGG(#W<;ocf()^%IWPU+)zuQNv&ABVsyp%xC!@D zONGH<5EjA4Sqe?0^wlgz#u}sEQVVNlchoZ`6KYH*XiVOLz%Sv~&6qTy#Q#3f(t zDeZbd*-D%2&M58iWym^nRO7)MtE0)MEy!H35H+bB_n}4_3Gz-Dg3_BzDhyUBc8#S% zxO8ygzM|Lzian&*FuXwGV{S=&$0$~*nB5Mvm8SOcKPHgrHK}K6Q`jXtnR=@x1uOYA zvqXQOZq#eH1Z;)zYnSRThM*gpluk*`j0gr;VRl0pgYy!XV&CUPobv;fiRmp67woD# zyDw|@Ww{6y3C$TU(u!TPpIM_X#tp4l7z8-VjTbzzg=Dq7aZf?xlnedQ)q-QVF;=Oh zT3eWCx!djEj#3;S6YPDOwU7YD>)U@+Ot=A>PcP&`gFDY(5Y@^@bCm=?G4-=u}B z|C0bKkYa!JKZRQYd#nG2jhWT|RS3l64r5bwcNxySrcPwqT~pN zHO8R?4fmXmy8G)G#BpSs))IpV*I*2ojqZ_XrhJdVt4#98I zF#MUrtAnb}UDVprIIH!PxeLzE+5oP#>HMY^Z0=TvEzIUN&zlRCGxx%#<69QCHBV;^ zwP;r3?51h68s{~(*dR+x<@D`|IVz{HTlJGs7$czMUCXygw)@IxixJ*~ON`MRrzo0{ zGB1)b8j!j{4$&x!aY2nzX;GfCD?1EGaP&L)E*Qqv3Kap9Wh*|;LvH}&syR+NpQG32 z^JSxZ39tmpPIkGM>!vZ#j^oS9@dS@nL@X6!RKA#ZREPW&S0rAt_2L;?FOrf?DFnM6 zp#}SarHX?46?;}O8k`dDEydnZjQdead{G#rOcm+Zv#i}#Atc>x zw&I)@%$IlZEv#SXAfa-6$V9su7a32V=h9Ua(qe+19tnCgg1XlJB=CdsPPy-XBzke~ z>|FIR$yWa91(qMqS0o)zT$I?h`386Hm z;1CsgQnDSjV4ufRf^D=^Q9zX{*xway3cklcU2Hnd7g#C`SkFng%^L1K z7H`f>m>;PfeeoW&UB$b;t#!=y7imfRGa8fGDU0;En=i(FAKqLLMXxRwNz2ir5FuO2}eUy!j+=H2*&N@1glc4 zTCrxuS`}mcve*>GA6hCj+dN5pXCes_UzQg&84uZ7Uy(fenTrM+4{F)&)6kMTvwRdb zc4iw*TkdD`4UzJ83{n9GnCfKIFc9YOtfu-Cu`}u7rrEW|E17J?F>T4B)~5M2^PA^+ zb`%0)*OQhd&Def}mCD@aIdCGHW~v%P$LdO;i7ot z1H^FX2E(k_>6O8gE80Aec%9~)6H^C@xf>GWCqr3@5c@vECCK%;SFv^=? zzP!Epy-kSoCH#!%G7PXjlU&)=Iw5r${Kh3qJL(Hlrxkb97bnxFl}f1eY0YrD-E1#* zkSFumY@{9(E$ERf#;2pPT0j@a!9T%_0*v`Mst(k2)Ek-oA#THG{xzaF=OYvz49>;x zG}!NQc!E4>-ogdkwk@J2rzNXKdpmpT?lO^J@1rkP?`!yR6B5+k_;~T}wDss5DtjkY z**lrEpA$@nqIUj|p1>@hC%_i|dhXO3jwUFkItGs+5YRdk(+n@%tryG|j23 z`7zowJsbWhc<)hK@Bi>j|Y|Q2<#0Y$3`u>TCmjXa$bU#L+O?D6j0H1Hx_xHB8-`@?SB-o)$Vk|AMJ!$k9BPE?c z_=Q$V;*})R+Yo7corZmpU>pW(@H?sBqoff=MMgr|Rp+tI4Tg5&RdV!gFf^dia3@%0 zhY3JoGMi#^EERH(j$kTEWl`{3ONBu(BvYQHxk?I?BteZYX1JM_3WLun#^wCHYet+B zi0EbfO#hLcNyK?NcHH32@7;lWMp~(@(RVkFDtoFrD4m2EJ!h2aWj=KG5UA`S<`I;D z6O*;6Nu$O-rPqrsm8HXB(Pk8SMvEWF4@0IG1S|{Uq>%bt=FyxAN}LonfD$K#$b2(q zF$QT&MoL9H?ys_%ny6+0hFNPr@x#EpuDv%x`L)JIgN~t0v|s9#MVS5;UP4 z`L5(XftO(ioxKk&E*YA`m7G6Q;-q0Fc)_7=o`q}IQTOK7xuYt}U@p%oBMbOOM&n#u zI6ccm#OT>-!0{!j9g%enWXdxgcqc>CvP4~i-)WH&g%&e9deFGRFLU@y)^ag9QnYfX zQy0JI`UYt`Q2PC&-`_CW@Y;{UqnGU>4115iVN74Xf!d={YdumSx?dc2fu%y@=u^Ti zRqPOCtY9oL@+`eQ3C2M;!B&Gh%4n1uEfogbgy4$?8)7L;_XhQZ!EUh>wmh35V~~Hi z=MKC#nX=TI$hrV;Z-!RMJR=0p&|D>Q%wgie0A|8^IFpR>jzJDOiQ2AT84%Etsb8Yz3=E2^C|o>n&9j7-eIyzbR&vjlr_Ek>;ZrwqJ(e?|vI;W%xF4 zBR$xdGzokSDKwnow~^i_>*N29;5}_4{d8Q_)NLDS{dnzBs&8y*MDqk&R~kjQZgP%> zNk8{1-nU!?sREzf{cxI-H5uP%H75m$R$G=J;W}Df(aei(rCX3M7DWxXCbC3IwviU> zN<1almn1%TZ_^j+&%uG>W2qBgb7D^*etm^U4^|HXJAth`QLlmL2wwTmZ7AM1J!1z8$n%xinbv53aFtb9Oo#FG889g9Ac;@PziKFWpwnLFc71g zEMJOH!x7I}I6t^8RbytKSfk@|R+9T0aFnAsB88T2E)#@9+jH*j$N@kPg@<7UT#qC<-IFFL%ax@g|O0r>|2`p{0!#Q!qt zU%r#AAB-BzG9N@^>@)+^n)%Fc)tj4b=NS{W6Bqunr|S^Bc=z_ZqHA7$iKvVByuwU( z#Uq@GFmXw%*t2r(?)O$Ng9qt{t|e< zatZ9NpU1;AF(^~+7~%-y%5^XFJF%Sdt&Hwb{P^``BfEC*z&*EX<|fb)Q{)*yT7$Sr zuFR*bt(!S8yAdII+=dtM`sZ>P3?D7mzl&T`PP82-?Al;02u7g^$lPOL%^d^Dl6XHkH|g`9+**Hb4uu z4@5jKm9oCzj znkkHtPC8C#=~kRvFLZJ)*c!z?sTf>?+h@7qv4lf0w%GR+dr+}Q6#JQC zzfkP=ioLAZ-xYgPvC@3^j=`1+gLR;eMrIcU_gX3p$_pG;VJXw;UkN5bw4~GjaHH4J z?c&ztLUvJwjNOpzSW(_ia+|hCM&)>7rK!0v2xjU^Z(Pig$<#IS3b#YDET%nUJ%v`P ztph^D$We1I zdz0il5sNow#+fTnOgNfNHNYY&$3CWx$WbqiFm;3!q+Ht>TP3|e77q8Uq*uFF;#{b- zzn!sD(EgYk8{?e_%>;QiB=xo`X177HC}y`o@l^W`r(w_bu3f7#X)&J2cdEyMI3Gg* z2h5Om@~sl*NjO*GdRPnEd5UQ>b3hHh=oU=}VfMj%fm!kXdQ<_1HHRcF)w7*-b4YM^6}e z#9`hu-TSyO&0%t5Ya_ZGjqUg-w1rnjGi7pzUiwX3U-~ep36>9*CPrqto&v62vd!*H6vM{(8@ntPsYTfAX>c1qx*oqAJJu9fNlA`DmP}3TaKB)o+Wh z=gf#`LiVse;C*CZ_AdEZ5XNwEVguAf0J1gDDF3ZXbJG!z$Dhw7Wc9Eq*?DOKn zeMzwoK{ii^>0K0Xtt2TFV^9*`JWIh^0(ES$v6d_q2HdYnu-z?%F&@RRO_{lyYudy* zO1Ql2<3SxUqcJD&+1ELqScqA!hp?0 z!JfAieDZ?f)l`e-@TTQL1uJ`6ZM<(~xj~;u(*mLTRpE5dz zcdND+?+}sCyJ+tnIky>UX0n~aJ=k(?H{~3uFt{3F1pBz9gqwnqn-cE5t7*nT$sbFX)s~kE_te&HLGntHwRzX(oM#{k;suxnabwhTzT*dJpqX3 zzpEYm{6C^dY6a@UhJM!yy)rJQV({4Llzk^&E=ON%WHb3KPc0)-p=p!}b}?cS>{U?n zjAs9vrNmm2a0!+K^DK?z2}ZM1?~@9H`xSdov8bWzO@2#a2V}Q$eowPv9#aus+j>Jg zUYz9S!%uQk?bM{jGHWfBSv9|z_Al$@Bk`V^h~!oRFTw8+{Mdmdho^O7=0;7Pd*R&K zGBBQVPQu=%vB^$QHfXu*Jvuib(+4VUk+>jZHxstP3oDzwW#%yqGg>}j!pR?Xx*Sf+ zkHTeSg2^~Q14dJJIpIa-pvW~}FuqJa5{slKN}t`aHp(@)HkMFS(kl_53+fIZt(xvR ztLa))a!7^20)!E)#ZqB#xnj!{`;=mzRqQK@eOiEz0RZqqnei83&PMsqm?t|Ymk?#QB8|sbZ_t}g%2&>X^`vbb6ZQ& zKd6jd#`9rjJhLQHRC`j)UK2Foy@33S7FHA;)1A?zSx-vloC< z_k!K37<;w^`+;KjE5=#u5+7%=OE@jS4TUb-IYcurQqxj6crYhwhZz!o@4obAL}Qx@ zuWVdSZHduIBOaN`wrG17?6R^UNV8w@x`IB{74&YcG4d^1(x0%|eTrr`DRJu}*cv<~ z*w-vo6hNa}jJ;eE4l!AblZ^#q?#Z*PEd?V}1T(A0qShEqv1yf)X@Suc>)8(54RJ;7 zFgEyThcTrsuIc1UNB2I(qmG&~cY)OkIp@lW`%I>ToDbkgxED`FQDba)9}O;V79Cex zvs@=o?>d)2#>$dUz;2hADN3vBNb^YOxGCJV+LO- zEUc~d@I5n5mS3edZapor+D#0{8WwnY9Y-&(ql}l=QS|a!*@KtYGs_!L-_)P8{y=;y zecl%Y(?E#>SEqyMQ0`|D9dsT-Avk6l1;L16_%ny6gQib8$6t0mv2jt8*X7_ZyY@P5 z@K7XR4i{|RGl zcpr4WTaV8*E5bQ5)g9Pfb$ot8dcW$;tL3jyX|BRK3bP^5P&J#{_SelQtL_FoOP1Tl zKTB_!eZexoyx!MdzctymnYx!|%3pMaI(7>(y~gZU`CY&J2R;x28|kCS-B0QFHs7sv z8>x`H+y;WZW2rDW1w0e%R7-`yxr&{q*iyw-Dt4V>YZRLcogwkjMWwuViDJ|!g59VX z7uN{(JgDPLAID}(b?=q7?jzk|zJHr;Y{wTq(}Ql@Z)edrzhRW_UMb-UpM}T2yDOAqv@aRQvFCO z!` zs2?j;Ka%QEKWYo3KABzu19DI@^&{gV7uMn)q)*AVCkxe{OgC>G`_%F+c_mZ+8Z|8G zZnd%wi>1qIQd`D$y`KDPja{9Hr{Tlm=UCmwc~MyS+>k^U@*FWUj|OWG1Ct9dhbU@h z-j8HG9Z{uhVY4x_6u*(f@Mn(ybThNAadCab^$!Oga~hg^qCt{b8u?A6vv`kvi;sn4 zGnoxFCy_nBGBjy}uKHQn2 zvwhH+qO*H5MNjYp(6GsEf=+}9N~xfy`{BFy-`hPooWm4lmk^H?R@d$?mw_`)$J%R} zrZiRAD&+AIgwN5-L>Z2nsu(~wrfP_s_`mJ1j@6}=X9#q+AEH)+bz$v2(;wrZyU_Pv z8yj_em#Sk@VemHiCm7rAf?a5-qTpi1IO$cwU9H&dihWtJyA=DLVrl3edG!O@Un zw<`8E#lET74-}&Ylka;*F)C}p68V_>XViANrT#0__68*I*&ft(`7o9b9{o|<|0aW? zyAT_Nn9~N%*4%56)c>!!-%HI+4m-^qv67wUel()Foz>i%=8js?J*jQFS$KK-tL^_7 zq2C70ZB+Mts=7&G4@;DK!MHR}8 zs12q|CW$l2S(^@iP2!b;i65LNTU&ya!;@}aQiStZY zqVAw<(S$`Yz=jiY{2FU%DQ}x`rp)~Y=aD$Ss5*cY_8V2K)ly;b3B^9G*q0Rhs$v@z zdt9++6ywZ3c?b23yq9`Luo6pQuUy4Ak43_99*cxyD_$_R;ssl+7~AfGv7IjAS}g?~ z@SeHLJA5ye_XCiw{l;6mNU^%BGL<$k@i3clrMV~V;Qms?5dD$5^!!bK6T?q0(jzLDpXJw-cM7Fp^Yy^cA~EF^*YCxLXv~^Z`o?51Uv>ZW21|1W!K_e#y;h)R&=!%jCt;r0pHFW`v!ceZBCA_ zdj@a8Uuwon@$XpiT*=B`L0Xb&j!J?x$MTfyNLM0ZHRy;;r;{#;tMRGWbv3;iUttmh zw~v!c?rtvqUIm`92pEs=q$9`?wH=EKC$DNQeF)>8$%iY4n3$cl6aeU&H z0b{o&J1#9x)TS;eOg=oR(1c7)9gMS8 zxCs5GKLOjem@h(yYWgKS&Y(q^sNf_4H8NknlF6w}S8u6JT}ngp>6&zU74Dd)S9F!E zn2pcjeYv&Hzx83km-=s8{$wR) z7xUIe-U6%FI##ddtm5>VcBUjc$kuLj)Ij7ca%J~S>i4R!A0#TE$>v9oo z!o^H?ksiVvAD=Ge2_It4sWk~+#(qf2J#V1Hy{?@FX0a(Siy_Oa;sYaK1w=kUkw>a$ zjLI3TFC_!9twn5iFt$4o+qzt_^}RfUdB{ENH!S?HESqt2whWYtXh4Z5>y|%Rh%kJL z6IZOD^+S{NIW2wUw90%;N<1Mih)c-;q+|%i=szMQb?KG-VDmA4HlS>UU_aEvw(uLV zt}?OO;*cr%P)8^c=_DAi&4mKFnOmJzZ$aU0kYYB|7Bh2Bt(lXvnE79{qKj3Qs|ci8 zC|UUj)VAh>sSyiNG1a81S0!gHF8CIF*re}(WoGVL!AP%jKt|1W0&-XBc5sKfmk&Cy zW93?2rB-g_X;!iTHH0DaH$rdMq*3hi=~-vBc_m+GUWrg!Ok|TWZ7U7ik`aHV5DZ2h z7Kwg5oM>&wT?}YbR@?D|0AXs=`^&xCn~hASOEWo>PFH#tT3sM~=9Bpe|Bt;hfv>8# z{`h2pgqsi&kVV`AL<));HU$JE2>2q2L|If6A&>wONMaTR6--D1gx4Tyt=1K5>s}QV zwJH|HqE%G1ii%4S6~SsnYu)|||KFK2bKZS7_azThtc91)%{}*f=Pq;R%szJ}bhLwx zf>&x^1&1TA)R}7F_$Q2xDi7Fo8j1#i#K5#u;{!Eo5(9Bh{xf#h1_T+su%-&_H~&0mmpv@wd$vml~Im;ZORSoi;DW`LJRBbmeWzN?l#)7 z`nBk%{@j4M{m3&Yzt0TRPnrpJCu?=rSDukmKYvP2{U0~zx6b8B`r(a+6#)859GEv7 zIV>awLSi2Ds9(>kM}m>{m^+h|h`mRHtbp8M_VFfH3fL0QYJS;e zTff?vNyxy14OHTEPqWk`5y#a}QOPuGa@ILnld{gH>6YMqg?Hy0*$Lr8Xniy1p|SRO z4}@2!0H!U2?RHq>TMPODm#*)MN50mDs?!r7(dYZ|_^22S8K|?x>yNRR%?InE*^Q8T z>jt;mAswOFgOIMm2;z9P4$^V@>}Qa8s3b*1zJdmG4%KJrLz-i?M1u#|9W^$r)c2bW zDN{=eNz(4FfK;!aLH$;|*2D9VjzpReua1L$ZqV*%W`mber;k^akOpZ+rq9x?koa95 z6lp!AVcOk$BJG4UO0%{|4To##7)V)Kngxm9`38|5fOL{R`vfG`!54D23rvl#2#8c7 z(r-n2LZp`<@tb}KiQn%#NGIxNq#}CpGmeMEcb+OzP^4=i@m*Fz;=8Pa#CO>QiSN<^ zM$UKXCDM42iXpMjsa1=wxKqxqgTy}HC}&$CcJTcUhs5D=mav(Sj@SOEgv23zF(eNC z#gJC$vwwtiH>xl3>On{s>Cj&d=>csU&q3PQh0eYV=^?Np=-Mf%p*3!q2Ue!`8 zp3d)*3+eazT~5dUNm^^?K;lq157Nb&)ymncgxvxu9obsEdLB|wZ1L(9{Qu%0k~Tx) zH7GujvtP(r`WTzfCPI2$ztsVdxRI_0q)YL(@p?|5?{o}3UamM1(wq8=K;x#C<% ze8u^Y!dJm)i>tiTrCu~{ z2XQN@)@iAy^9eQYwN=A)>-Yfe;>4sK3FWcjQx@mzyPS@@oQo6(6T2n0X^|60Elb>P zls|ihc99Dg+)39uX_Y#}3GXcEi)k2Wt*sbEjb!*%%9((c!3WiET2YHWH7(;aH(KJL zvRr@ZPhA#0z-X1ZbC%QD^1|6zU9zMMmkm!FhGdH}LiCliqKUqOC}1Vhym@m9^$etV zqZ89;3^vSPwMC4haY)Q!H0!EaTSd>I+_f!k@&Nh_6IFp-PYiE-Vj49*(LMeTcA?Z! z_-rCgUsHt_pm!UAYcNj}8eFFr6_)8!n{f%Xj=qZ5PQ)b8m`kQC>|XcN4PEzIfi#Yu z-|ceZg?4=@eKRTmx`(mnpb0qn;92e=Iu9aO#uRx6&$1(M8oM9u=YF(x@1E|D$0k)h z*V#2N$c&S(dM~QcNu;sOpZSt_Uq3JU-p|jA zzPEn0`$ir+Vo{x+$F7gsW7imuaV8U^?$yT;zoA*GPlu8QcHZ9KQ#bm0>PG7syLWr) zGP3f67frMlyf~5t_gK{1&*Qt10C+q;Q6ERN;Qspb!ICDj^LG9o_l@|A!XiF--tBQt z)oQ!@c&c_#)S-DCiu>+_K35;7MKaMN^y$vxDR%B}qP2tlLbGj>fW@cV)W@yNU`$>o@(#wsrJ@0cHhWTeQMVEc&cV=)Sh||1s1obzR|}W zBZbuS`gABUVdsgy=2wG(yrHztCZILjtY_@LlgrgzDDx&Cu<&2Wv)d>4nPX$$HR<7# z4|7^tQ|jmSM_QcY(+2>^#-q>sV04$Lp6{FWbFOcnBi+hZ>f=VzQ7wY1RJGgH|16#}Zulyurd(RDVI-9hLPJ zv2oSg;F-jD8q9ULey5Vz1(W%`sPaht^a``xc<;Ib&r5Dmjdrb5(hhd1>MBxITwL{o zP}2b|R6pqUlfGAC^^xEEsgwr$fqN=l*$U-7$X3sgo56t&$pfs(alq zKTnN|+Eb@`JT*ffw~LtO>eHdp4m*$FsR_QGLQ`?LDL3*|kGdIto|+%Er!Mq(YPmj+ zXvVYj=}>8ho%@?{-6g)Bx};f8b+4`P@l@@Ss6AEZiJRA&;|MkFx%zY{q}X{2|G2r- z&r`KaoAMOL%{nw0hv!!A(B!yT_po)-MBMy`k8H*S>*I)VGew^cg*ZF+_tc_vKTj=6Z{Ab2 zxjvq%&5zns=XlH*3yU=sQm1;%n4SB3s&<;6r)sA)<*5g#(B7fC)S4)*AV}`rX8a+! zNmz4>(Sp!jj==$7h=sjJ{`l3N~&>WY!+_pGra0wnb&VI&9QLcquk2m^_E= zAJ~%MgJf*2u~E^4+EA&nkPI@`J&x@!*w$cs0vlP%i`dALUc*Lqun8Mk z+!kyU`X68;%iMvD!uH?T{)25Nw$>EfrfDwzk;XVLJd@M{EaTI|SRI*bc*% zj;#x}uGqR^%fQwHTQ6)!VLKYzG1xM(^~QD_wgK1%VjG0*cx;2QQ9Xew1ytIlB@fmh z^l2@c)Uaj72WIj*7oFUBSANws(bAxSQT`v+}IwK4md%*9@I;M$(*E@gzmE$h5HejOHT+5tzLng zgL*+|*-Fz3f@i`l^>mDh3H5Z)r?>@pDE*#7Zy6oe@}W6CC+!cq0?|T!dj+3wp?jkc z1TZ6Vf4Jv3&vSg3iCEUX13l629VnEpf7Tqo50jI)>5Ax^0;3@umq?h-P>uWB^*mDn%FelGS zMZGHvu%`~OIy#U2BJA^_fhE{iV_%Ow4RQ`*Pc@Ha*i+FBFH=QLiwLDEYFkAhR#C$- z?p?JA``=)H1@^zi{w`<$pMF&B!v1RP+d>1^VE+a7*J4lo@7G~}7WUU;e=YVmVEG>aEPw&$L{+x&XFzheE{xiJ)1$gIz-5xq0RVS%u*t~y#qaF6%1MkAW1ic^^MFYJc zmyHJ2A;l5?C7`a&ormy(L<{SVqKtLt(_v_xQ4F%qZ08}8VvaV}5gCVd? z?xGmGzc=;Y2W4u%{$Bg)`}J>wj=#&JVrsV#f)vH#SmA>N!tB3q)cWrht^Ie4(*C=l ziqWXU+=hF|{<}%%c@y@}&-8Yf+na^#zgrWN7TP(s^px0pEB)ygwf^_5^k*)TtirvJ z{`Wa{e*j2wvaqc#iR{hvzyE&qd)2>J)1Uq3FX|6V|Myn<({JGZ2p}QwGo(Mq?N`57 z{d+b28L(gfKdb)tCqJV8pC$e8ow+{(NC>#n|Gky}_U^r3|IzCINI0bShr{Ip5`I|w zL;vVA;KQSBfH*wL28hF>Yk)XBng$4dX7ddYhey!>LG`b_W&i#6SHMEn{4=CK{r6YE zepdbWj=lkOpJ{;Go9R#Q{SBZ$ul?^&|9@Wn?@#}KUj0X3{@kDbn~*~Hzw7tI%KyFh zHvoln`7@M1d+%=m`dRhgXMg+8&#V9a?LR-O{s-(Y|NN}_@3VgZR@C}G1}>@nvuEfE zNI$InGcbDn_l&mvvuBj;pFN{%|Ky3^Y20oT1F-m+&9{H{`~mHssYdS@ChGeAK>bJG z{)3svFOUzu{U=4!{>;y8UjI$4+-y6*BDMegB>IoO{b!%oKW4SozaO*y zHDG`FKa`gI4E3)*(WgKA+aG=c`yaT!{o&`e|LD{Ieail6S*7Wo@y|a+`LlOs^Z~HX z6hILps0`#620uj^sCQ=coiO`MA!x6MLG%p~`@;Yq{F+?j$1IEX&fMP^XVi+FDU6zU zu(!qo^@%HPXmm)@GxU<=s0)SROIv-`QA>s4Yg)tZ5_Ye!HNu_}wn5k{ z!af&9U-a^GTcTXR??P)0GwUF%v#`m+rU_dj?AO9*2_?SY3SsMoZ4lN8-wLz4gN@{< zZ-vp^$3-h8f9GIl}UUl?W>rc8RbWVeOH4^8F4p zlA~zuab`V*jSv@i`_2wN}gLt+0E_LVT2d70n20pE}Fb1yRzR(TdibDOif z$AqmBwqDoo)dUT56s3@(*F}3HwyozlEis(98a4Yb4l}u&%;qwFZZ+>0ZzM;h3Ohj9EyC^)hWX;m zwT}pURoENCJ`lED*hQFlh4pfYksK8icB!yCgxxLd5n+!DyZQiozw3xUf@%ohIxYVN-<_3o8@0K-fZIG_ego_i|x3 z2>ZRTyM^5+>~UdF3VT7=%fj9fwnf;#gnce-r?6PeeL`>Ls1zfionKfFVZDUqVX}}B zNHLPsI3qdgVPTI6dso;8!dhX19=^7#)!p;;nUs$!U4Uk^Y@A8U~95n#5 zr!X6ABuC{7D->2QtU=hl!X6Ozs<1bNeJ?B~ouB5YJV;wuFGhl1ggqwgU11*xYt_YG z+uBIbi?Dve#tS=B*nDBt!Ztwql=WgH=%uS=gN+2e2rCp;FRVe>y}}+4_NuTqgnch8 zrW-#EdV#c>^Ka1|-sC$JyAna9PZwUKdSWI_&Z62f+db!bYMuNQvdra87!afkz z>R0yK)<%N82|J3W2y1nOy|%THpci5NgpC(=rm*?Ks)cQU)K_5!O%GcwuJ>n=hB5!@TPAF!uvNk~ z3fm-Xr?A*#_-W7!Br545KQa>17h$V~Z4tIrn3HL*O)(PE7h(N{O%OIw*aBe-g>8WJ z73;-F&`WR2h8PKY5jI`eQen%4trWIO*hXQSgzXd-+lQY9y+Ha8>%~aWi?G$gwg}rQ z%;{^dO)(PmBCNl#3Bo1{TOe$qunmyDWW5*(dg*7`5Fy$rH!h>@TdVKl8FU4b?-VatTA6t+s( zMq!(T?GzS!yuDu@qcvk)Ri0{e?{sHc{9DVGD(AfRxf&=hH@l zUQV=Zh>@TdVbg^z6}C*+N@1&nZ4|ai*iK=wBlv013#5lwFGhl1gsm2~Mc7th&PaQ0 zijklfVf}?o5H?ZR0$~e5Gw|mmJH67zuh2HeJ|KVatTA6t+s(Mq!(T?GzT9%TI$| zAa!EB7zuh2wp!R0VOxbcr`T&#j0C+1>o07Au!+JJ2wNy@1Efcib^2l?=w*y$LyQEy z2%9c!sjy|jRtj4sY@@JE!gdOa&Euy*FOZ7#yNolEqaG3VxUlzxeJCvHRC{e3BRQ&% zuw#XtF6=B}mk6s7_6nqP^}D=oB(yP}X4!BfIckQmS;8(Ac7?D9g*_tdO=15K7B|*D zBf&_HIs?)y{Vr!4$x%-VTPN(F!afz&Zk)ZgqmeLWw6LMVCJUP;Y_YJQu(u%1)bFy{ zNRApc-m;U8iB$UHp}51>xShP9P@fls+pFDf3awNr}@9x55I%|ef{5; zrcV|h-!A%f`T08E(0Ulbz!M2jBs_zQO~7xtW2Q zC+4~yayTAB-Lud`aA_tEa6VCM6R}nu&kvF_o#c$XSeQns`?Rq}H~PF-YUss2{Rv)d z*jU8hyg+bMpdlxthxYICtcRg3cymJ__#Bf!155{~endu(KrkmGGf?-pih+UPxQtP5ouF!YxiPZf5OwSSclUpIV~wUyKQod zlill{+>W#Eb9P;|uMWlR`Pkfxcsz>Z2YngoHh~yUNE(@)}_5lI{*Nn#f4r&DlEe^KJnVi=Vi$UO%pExKn zMorGEptYv6(gHC`jn=w6Kp)ex(#N@u16Z%2R3Eo6=VNG^e*9YLFL}B_!tI97t0*kj zt6S&xk(DjDbx5FF8$Bj!WXnAmQY62|@mjT04`jsY6D=DtXFQPT2 z?aNKp_llR7J6j*eDZ8*qq&-aypQqjOzeJHUhoz}LYGxV?QqkMck|U%y3LOdy())I7 zq~o%#N>K=t4YUbcwxVBuj0;H9#zOXFR;{456^hK0V&JXNS_tX#e74~Yh;%Vv2N;g{ zP(`+XC$=APtpK<2hs~AV#~T&w{Nhv03n`VLKW~%6aKVn~>jgXms^sxxB=LAMW(&+& zN3Vgv>>_xZ-O*YO%!0zM5_YYyTZP>z>=|J+!i(>R_5RHLXoMHD3}HQl{T@<_6nf`d zjO3_w;*L@uzLrWS{C@8X>w*06MO~KbWh6({3!~LI>8wK~svhvX&ML_E(xDk-3N_p3 zYD7sc-8vqBoaimY{u~vXhMnivO2wU3F|)FG)}%ovmdz`zD9OtkG$`Wg5bhA4l3#Fc zWjWTBzo>VgO!UTi*GmXRiWSJE*;tV}tM=N1=|*zYFEt~%2EjI3ofM{1GD(|}P_*Ws zDu#)(97O|v*&Pl1SdFk1!f0_NzV>5bJA{2F3<;odR|e_J)|5e}tCZYCHMHbZ=5tNG@ zB%xVS*lHsI<3e^9ZzM=)JtlmA3{^n2uA+7)a$RUW>j_kp%GLSrz;$! z3~$bCAFY&IWptw^RYvbW#iO!<1XkJKkczO%NOEX3Eyb+fNRE0%*z3Y{g;BKD4ywG} zqczG-=|_c{iJi5Ge=eZm^2=uqt}NCoKNX}G6<72M8R*F3$~ogo#?31& z99#%7J#>aD7h}o_3d?%+9@^{Jey(fiejdBkK_ORYOMM<)t+eEHQMuG2_#InDseT6; zf;Pf~XeCj$Ub?9}C_cw6)A_dgKj|bBW~8q({0b`2`kyQ2Uaqnu&ii$(f^K}xC%wS*74PkWgT>*AIUoI7waI2i%QI>sKo3pBPFSO zg-L5)EPWM(F(bnh1HmWPQpWLxZkR*SMg2!hl>bsm^H?NfqdX>r)+GJwfd60ZfeGz1 z2@PdY*#(8g6*|T=o!E4g{HUF)#cVus8nowO%~2Pe0|;bWzlNb1?QJR!#)h&@N^~c4 zIya(lS_v{>q}i?{TBnwS2F)%ko>4JV=ZsWOPSwHMvY7%&3UWj$BhkCjt3*itupTWO zxf4LL8*c(Q(IkLpV^8)p$s~X)#KcK*6eWAis1CsFKf=BdmV-BAceG3@yW0b^KN=Sg zZNlug?}6F>&!?O|<{mNi{Nq(iKR^(=?1RcU#E@f(7*jr zm{8h?;F9|8Vv`pBRg8lq40C}aX48#?&+CLy#?S7;451#lZxe<eLC=iR19lf? z1a-j2G+_i=chd;|=gTxU@Y8;13P3m5^T1yvflrd7#vvS;QCh(4I$@L+FvA!SjO&Qm zl{X*|3?yREMq*&vsqulhCoxQ;hqNX=i1a7V)2@fsMqNNS5c|LSwT9-E6`hZEJt#=V zSm^e*T)?uT{MkC+d>f;~e4F1Kop1KQ%^UyH(GNrUCe-Us$?IHvcW z;%Nmv$uVtj(hB;GZUv>m3?wC~c}8;7eZoj9>~6iV4Z_@-#dsR%HLH5WL)|Gpt)?p#F(hYpn`mm_AQ2~YC+pE{!Mz3FrUP*FP1>7>D zPAg_Bg^^a6kzUyy>6IA`S4!QEL)3>cHUrik>LyUA}4Y*IEwlz?2w{asQ5SCZ($qGC%Bpj=mD-okQxZmvDqJm zrMD1#nkfW7At@k9j-rty%%}s9*=Awy3v0@ro`kEMChX~zJ+P;JqFmgh6>a>ft%x4r zvZBUi>89*xgV+&CjyexEz^u|pj(T0#Tf)NaXe+J_rAzDJDz6DU`gRZOXrC!wH)%@| z`(|25bE!>{W=EYOjdi6+o<5u1v!(0BmPo=JMz8~BG~*^SvLI%ZIx%a?mL7+zKohp~ z@gCUH|9mOENgImT2Ki&zkZ((1y3N$EZz?^yM{I~B%&Ud)XGSR#vsZ*s%ET(y#VoAZ;CkSbJjO)@Zu(JW=5jw}xmwe#Nmb6SEY}tk zaU5l|Z7HtdbzBc@RAHg_^BPefqm(m6DI_^+Hrz5RH4?hlg;CUEcQB$2ZX;TUGo>EA zxFg*PKfN>&=_+Se6qTa(hwi%b3$?rQ!ZFizMC_AmW8_Z~1si94ev$AJqrVE#A4!h7 z5_(|vJ0m&jEn%C5^$Cr@dIa!nkLuhbu&(i|8#gfm>y*N|6($=Pi}nY6kw9NOEJAaD zZ~MdUj=rKBHCg8L8+|o2k<+Z#q<&12qpIO|W_3n#6vaGduLy&=rMk`S7M$_6)40v; z+TAlZPT+q=bGp!&Q;C=pNhn9bpUmbN$x)99TO$nm8MZt6xo!{i)970X`Z$HYl;PhV z=6KOXw~LH^N<}{;v3{75ewdMdn5_{8{cOg8lo9U1!I_>o=eD2gcUwQy0{D{_4H_lu ze#z3sMo;I7o=9@^kZNWN;d5qB87WCUBaGYfvhYFM6JPJj8y0A>1gFAUNbg2~drRe= z;fON7_SiQ2X)dhyY@cs=G6f^spdPWUDY>bZVOJBTt1XFIhLaHr^qYmo0sod^3NLT# z(g~(@X^mJ8Nn8qNMx}6OcNi&2ku@-TN*H~U#4OC3mTOaLY*5rc;~l_x2wsp3suQ;F z_Q0U_nI;2|DMf4~h}M)`jR0;_`t@=)C2#eF!YPs=T`Pt}5)a&DMkAP*Q7;`cvI1t0 z30or!Meu;6-G9JCPw}MP?jraVeg@+$g6HYJg|Gzs$1aI`mE~6qr_Wh>!9Np4StL2C zT-XIh!nkK)l*6&Ruo#B)x@JvkSZaMUROlV_LXnChS37L4`su2f)Ow$2*Jb;#Np!@9 z+-T#KtD)8%uQu5v+G{HmM&5`u*rd=eimi~ugJ77^AQ)yh8YxMU1u%P97)3E=VfM59 zYCN@(3DK`)b01BIae$ zT979%vle9YGH+Jal>NLU_Cpe;p+a~wqpw<-(I`%4WDU%yvcZfh8_YuXvw~_GHaVhX z>lBX(wIPegk6!(oJusntrh3tY8AYsWL~BN#s)jYANL39Avq;I%4Pr(lq4bO}XLf;+ zFmt>xvIurZ#>4JtJPk9K8BuY_nh{x{_v;_G8U1q)%;7C7dFf&Jz_@nQ)Xld%&30KjM5`!ra-MrMbv;+vu18sg={rkp6*GG z+!eC7_rQ+!@zPP0Be$Y0YkLYvw&)rvAT=s&`&HH^m=e-ju`QAubuq%9S(TCS)xI#Y z4t7W7B6dd|-ONHsQ>e6kKhEZQ?8&||#fg{qz@GNW5>mJo{nUk|MmFSEO0qWeve*zw zjw(Z#Gdtf%j=Dz}Sp>VI?2X+~_QotMec~orZxZzo9G~hjDR+hc>pd{3eYV6DZdMTs zP0=P!o9)|+$gKPt0<2lxC}u^HqsW+;U1%gnkufnNt6+CzOw6bn$1IdIt#Fr` z$SSivrsOU)eY6Lrw9l2A!cFL>E;uzZA-|H7HKCPaLL@n=7~#!~(kNy$SsgR724+-V zVn%5cGt7qCFgxS+K=sFKkZ<8@{HI4AwgWSvj_mvL(<9rE6lkChMwL@P4pVg2kMC%X zAtr>xuR`L7A@Q}4_;jG*GPQHpuAKUujC4%1`m5aFGb8H9cgqQ`!LHrYBX`lWAjUmC z@>3)J`{|MYFyebpk9^UHf8R#0L$_cd_)Jd2NZek(r3=}IyO4b~7qTzzLJ5uU)zOXG zJUA>pQ2o>zyv3xohvPquJc(ERA<@t!OaKe1OiQC7ou{P_b52-{;G{R@ImR3W0 zS4+=9>U%KVg$877(d->a$7=STFlzHVO0zG8#UoS)YSs!8U)vGVV9gE|b_ApoG&@F^ zt#Q2uGS<`0Lt`8;VyE z5g>rarQxxd(n=qX#xeiWuu$dDw4Dg?7=%mj)@D1lw~Tl7HxGEh}1A9 zCZq<;)sRNkOkN)oW4x|=q^Wj>N6U}Gbp`szXy{Oep*=9i6)C+Z_7vW|&74z>^WgC3j0{tju6B1`58Nmgk^$*Zy~K(0yjvjkVu(` znOi@0MRxtzhs`0x+X4-zF3GJQeRX!j=x31FJUt>KKq(0J189$gXJq}@r?5Rh+CqYo zlaa>~r6?mX6|px-8G%WOUCg8d^e$_uSC9Gz<5gEkG*~Ylvj}4i87)nQv`kCIkbb43 z9`!X|su_(9IYKiUOUlef$3Ma2*`DY~YNiprmtwmQCc{71SJU2J*YHRfvBULPJrc_& z5@Iqs{Bk^zuyquXFsHdlI4~>{(mF?&Z6v;9a#F|SxPy{gB-u!Kk%@$D5efAuJseLn z8$~(_1fL%wT?a%u(&l-v{6)}K46dT*P>fm*?i$ERh{{o(NVWpVFOuB`-Z+x+$SQX< zqww-Zvon>dBDGG$p2G1Q?0aE94i>@Dj3i|3!pe-~s0Lw|38MkBeCjuRTPUWn-s3vspZ>Y5(mfB`>6j6F zYz0P{PD5iA&;0kpr)KMu>6wnJS7xtF%&A1vf{ZLKD9SHBv81dF(~lJv44+*xZI(87 zTExnCfM$X|{eSRDj4H^l$oE)(G6H8}8uXyLVmL;0U!rwEy?|_t6iUxE<2ebX0@1U^ z#OP;57*b3+_Rj0}l(C!`u^f^dMd8crBO^Jg1>Tn#6%g3nTw&Bm!b}G{j#M9{GojCn zR)KhDw58z{_D3@W^3N6Q7&crvJHISTPl8^E5XbbvdP<@S&h(cI$5Z_#$ZPy{#3Sj= zY1(R+ZW=aPwo&<--g^ylNb;o}>5GV^BjI%Tnj;}eJYy)c3b3>ZF?)by7z-y*T|!fg@Nd`LPE!w|X}i^^O(wlH_2T zQ4~2fqr{il+rmhL%)S=(oiIH)bf#Wq;M7ibRe^wB1t9aRwN#MF#GOMXd^?EuLjtl| zSb`q*c3HFeY4#k<0;s!&bpjDFH%*lUqRJ!??mU5#0RGu2HizNRl@~?OE4{1tqk?0M zUeAyefF%B?fLST7Vz$OeNebzPVcxX91+ETh>>vc;pF9@qPV2}1SEcpY#YOyyP!s98 zO}M)?op56k02>z~B-~P{PKPe-&o7Ne{;Ly~SP3DL9Q86TVz$vpSg#iPX4cP0m{Fmo+|XLe}Y2Wq$+3;CpdZcJQ05;EtT&=Q+V|M)rMwM1A1}eP7NF{%sq* zP`{Wq4{ktJ`73?292I5McgH^+2)?Mn(<3jyGpH_ok3J3rU(b@&Is(D31N9?k1h9HZ zhRk4gQsVTdPfCqJYru?70u$;lNdISCcJRAE{rnk$V0mIr{WK(mV>;1d9u87O8l0kb zr3UIR=#*1m2q&Wx8=bl+aovfjF@fOU@itf4x1*vSmP~nwTqlKY1dkkrGkA+R_q2I% z(yf2a!-4UEyfn)1I&%utpOm;{a_TxvRvP}+frc^Zqz!%Ha+e1xZ^T>P*rW$?Z*1g& z`8O_^bZd6QrAzcX$3WLtWd}FzN?i^QXxCvLsGoBc_&)*zb6*Rz8IFI!@gD~2Uam+B z1i$UO=HG!k1Hotc#o(+BoF$O61UTy$$=P)oltQ9qg3Kaoa@ILnld{g9e9ok`{c(J( zP6khegh>++y~ja1K}!XYuGi9ekj}&hBJrvgQiiUQ{0`EgTB6$H4cgrS2+o%eBzN5* z@f8ChaV2I9q@xkF;`I#Locw+bcBsDguvjbEEV4r)8ooUV42DIcOoeyA{z<~PG zP_GKLOWcX%HMx8B_wHH!Gf|Fg*)ncnTGH^AiOGqHHbFZO?@#_PjUHx|6>2s~fgb5Y z0crsmja5}huSy-HbFglZVpKWl%zj!Dqfd7>$06tL^<-AiOT;H9E^OzfDR_mJ$wck! zkhFKZSVq^yCMQ;ZZ(aC!ccYJYt3Qg`yB})BhrIi}K2D3|-A(#*$h+)39_7MNI9Tsi zf9$5#yVW0C&qVa@M(e`u-Et@+xn1?+bgrZ8X<0BMDCwl?gOf)Ey0}iP<`XAYr^k&* z>e(_j?l3ruJIGqV^DseL)h1JiX~oR4k_)n@pHfmWzPzwNhbBe3bnV^b7&6JBeE{$Y zA%#4dBTN+*5nuglI^%OiCGk!!-{>o1 z2OlWut<{1s&+;4vgTXNOP$;k;-_t~|V((sJ7 z*xI}N$-!LpeR2X;i8&?hFxRQS=$pjN!n0aK=JwffIC?+R&4A@}52*E+l-A-!BNtemV`G+#?~4eB`@@%3+(KP?D!X44c79;mO`hXN&GB1!eY*dPuJc^~`5aHoG*6`+l?zs& zR7d5)48w0ystQ#g^?U3oU%MIm&u~m-m?^uxMoF^;i?EeSGMi}mQD&8@z4b1=f55x+ zg083v+#Or!=U%&I_w>?Vze{@PR_>mVy{wmhKR_?;if+g=d#;z`qI{P+JS^X1yQEDD zBcv&=-=4oqZ#I~8*UeB8w?DhY8h>5j_dY+iZhH5PLOFOnicfpxefmWAJ`{KIrD9JK z26YI#&`6G2By6d$KM1=`*aN~I7Dmkj{ESV)whH@5SS(UdcGuEKj%q8cgRt4cN`+DL zFJD_FjJ`-=Mqi|mG!~FgpwBF0;u-!gx+$CBl{pTPBQFG~#P-5H=49JhS;m z!W<96ekbgY!fqGV6J=b!_9!Dc>UiWC%uXx8{5Y@@I(!nO+gT-cYwVi806U0NCm;VX=4(sb5Qy@X{7tA#WYkv2&! zF_NQFQQN;wvjdFesOuo@(rks1upkWT?mIN=WhBf`0x1c7SV`((BVnyRJiSc28(}0& zECK04&0aAQ7Ny4V`I;3NNiSMh1w-DBP3IP}zHOc_rP7$V<#n1vEBn?_fv0A3tX?(x zk96=onw8SG(Y-M+7^_Big(RyxQyEI`bp?DAA6kBz)>cOwR0FwjUEcwRyl^bm((<_; zYx#!J%gkNJx?Az?%D4?fV$hIx1}s0oYhncYJ{7318-`cT4!)5c{5mK2ZBB4IHR*Ai zUG17Swc`+g==ye%;fC>F3zF$(Wyt%4&P34i(r%!Kl7?sBO zD>Z6vS2wDN|v@mf>eKJoiqyR11J?Ri9Sw9}jGf9il}Aag;?peIty(EH$(>2&C8Vz~`<+D*fi*I!oVZiKn zSjO(&-6}8?pK}`OI6lKj!!%=KoO$eK#ASXgT$R%6^BeB*tNdWi=LG90fyqTymWJ#= z_YGtRpWzp3)}tXcHs#S3{|z1uG?kKi?8R*#2&fJ8{=p4DAdr4wg!b#Si6*l|`eoy6 zFc%Rh_iIX1zDAmY4l@7FARRLTea(9J)lX5;A=KG()}*y&h?*yHHfcly*}2wJ$eAGI zH0@z(u=%ibJ(^3`Q&ZS$U8v-A0wnHjLNkz&ripX`q~mm1s79pAMY;)6mOgtYq#;^* z2om=qy#tARkv@UM&v4+M0oolU63n_mLfsATaxA1cEscW2ccFfqY<`b?olX zBE2tCQldTE9?}$j?OlJ-&eMJ^nuYo28h_Pn!=3IG zi`Y{-5S+2`?rVGl@MmIu_za||~A2FK$^*!k;jjj6l&k2YSFb`cVfUN#|F)C3djt9UHpmRQ()kSPHRx&GNt+b&w=avK=C}gQT&O(ak#<=yl@m z)ZrfPs>gh~e5*D@-R1i{X~EUQ&6d+5QkU-R40JyW*Jx9Vkg z50u-5?cuI^%(`%U_cHY5B)6&htyRflbkvYLcYmSooN8UQHM#YXwp)?(Z^OW?so&yu z=$AX9Iz73~k;%!ac7QZ>bxuo1UWU#6_%U7Z_;%Iley^rOqEEG7NL0TSbx6FSjkUct zL>g=GsXlHO+g5!XLsO!5gX%rw4c2NW-Sj0V%O!EKt<`5SZq3>dseZ>zZHQFAV?AZ} zZjT2^@9nB@w|c+O=-ur`E8vKQ7r7N|2U}bbwF1yFj$cRtx9H>E@JVtc1ypG#hlm3B zl8l%GRf4Yq7GCM6fQ46DkK27C&-Gat@blcvs6AI`JjbbijJn7iM+n(5`gAv)U{c7k z^A^7GY~i`So;ufh#_rvo`l3ID>caj_h3aw&`2!ZFTQ~De$RFhDhQEp2bXa(Ia{G?S zLpvn*!O$ok-Ms{k-4EnAQq$Q-i#3Cy*5Yw-Y$8^Rx%xORQfk#jpAKn}ohSHev1YKJ z7HbAu?b&@JPaU!FQ$J57MD3|~kEc58<3l2O>I-A@qysVyb{@e~t$aPz%6i7`-JZIF zg0%g@zuJ(j^NH|FO|V-xHZi9Ax$ngZL(M!t1zi@kf|eNtQPxc<;~(_#)A8*vM0~Lt z7#|@HEiihd%Scgt*$eTV)VXSz>J#r)jZGnIu5eSELe^Yi6=nBsPwEshwWi1_BVr2K zeerf5MJ)b4YDIjDVzxW8PDSBWDJ~LqgXGB`KGDuYnKe82AD^{&m!HQM@3J1Iz1xM& ztQT*$F5D{Na9{kmpLaJ#?cKk7yt`c=M;wl}R-ZmZ(oA+9!Mm@!J!8Xp@$1$z5xnax z)UwoCHckhhaySI6~`?xudVBXj2)1lC1=l)s5;y?L%_fO4uH*xV*)F3?< zQG2(W$GZddaZ03AzO~1@?7Y2i*0s2Y+cRR!J*;OUdKc9m9uU^ZyGJZ~)5p7u{vEY< zcc5Ltom92d{)w2WZPw01ahIL@XKIW74jG3ML$K6HG`g-?S>zN4NO?b!{xa}hxn;&NK|U0c8ftSwdEm;&eO*c(|`<*+SqxrZ=_gsg0I>z5-v0b z((S^g0gDc?E*g3Fh`P`Hyz4~eU25t{Fy5u6Au7lmqK^ltKFGNvSjtyuiSt1Zna&mYXWtxtV$O7)D}3csP+3e zq4vwDRq}6Y&ULj^wbFi$n1Q~norhGy&eMF;irTOJR8sr3^)T(-E^Jy+>-%wn@$St& z7Err3YVWS`cz2^dj+lYo;qfjz_fIEku`Y1v3k@4_YX91-cW<^X+!nxP{o1*H-d!HG zcN;w3y}4=c&NruRC77K@@b2Zl-VGZK?{;C6#oD=k-u;SNP7bI&)f)UY>D&(KRtaaI zwdh~t#*m2VME50r4I)d9j#_O;>Kb4udCk(t-6G{Chw9UzIs-fRSKE?Iw^FQ?EJ0^o zlj%g_lFrtJTP4~`y4S4pv67liQG53_(-L6Ye?BqC5pt7f_34mz*|~piQuCIdcWd6V zp0WEzo;srD6C2J4n#AuyggZn=VKcOo7sp8JMF2VnfBz)?k{o4Zf?(C zZ`@yr#J6{Q6r<3gVfQqp0`+a%-!Lnv)T}i1TYPgr4v7L(TG;HT% zy8zoNh0n4`AR-x z#@s*hqy9wt(xNK}%^XF)TM+Wp3wSH`CD`AA{YBWLufA$A_IF|bTkP+~{ypsP!G0_D z_hOHdAuVlQMc<6vk3CJDL7d+GLG0;UN%ZtrRbl^U?61Q95$wOl{xR%hp@Y@fr(*v& z_IG2y2KzG+HJ-r!Hte6p{(kJ&WB&y9=o6}1hy4rKcS1r-_wSDVTI?wseF}RjVf+<) zDuS=Wp6aJhV^7ucXRxP~HOnqN?iSj)(I)rItkrks@#GsqVf5BIZqa1&qto##D3(W`=|GYK6<-4F8AxBEThja zNFVgQnfI%fRAXcq8t(e-`ByCij%`LENxDqYWQ5`I3fu|r7h&Az{US_K6d#UI`mtB^ zaojIQAA2MH=-Z4s_O<H zzw!q@$J0Mle_X#kFOT)j{ADO4QhDr0*T*lU0<*XD(R;srgry(&DnC?P|1YlK?lt@P zg;a3&nm&FZ6_~xIk6%ayX0Pev7gB-QYx?+wRABa+K7Jt;n7yWtUq}UJuj%6#Qi0i9 z`slO2d>U3h?X$mp8m^CDNcprEYV%Xk$-?v6lf<)BF{4?km@N`_ONHGc3_ZTa9r|p| z{m@Hm*hXQSgncCJU&6i>wo@2=;%MH*NDjXEv}~EMYlPh(>{($i2%{-%`F<^onP$;qzkMp~-@`r0#2zyl6UxdvLy`-6!w&`XN0{X>~&$a7*xgnU1B6G(jn|>VfPDrNEoez#n(P9 z>`@HRV)hp!IqErKFADoe*uR8*D{QB*7ciiU@AtBi9QBT{EyBJR7Sn;Ra8zp}C8;!F ztA#xw?0I1?3Hw;s4q@L3!^GSAtsHfik&@KC!X6X0M%bIe{vqt2!af!DUMK6{4~^ug ze+&CcSX&HoW4+LDH{u&u&kI$L)wjD+-ASbJfQVgMZ`UqJFk zlNpnQ#YZq#1wW(INRE08!vRMj6-iQSjO3^e7)ZygvymJ%P}mS*X9}AnY@V?B!q!8& zT|Z-kksQ?>lhZIe!bpzF7M3flNZ1@<^}-s2y#;B5e#T}aIqKMS%LW_TA+gk2--24Rl~dt6v@H>KXwx=J;YqoxZxS6IEU24S}g`;)N03431H!5Nqz zML#3mNGRJ1yHMEggk3M}&%#y~>*)681M?&kNfw z>=R*wyJIc~{fuEoa@22yT_fzz!d44=L)hEGz7h7lu$*6E*tdR0o{=1Ni?BO{{Y}{O z!nO|#i7XuGO1lA~S|_NK6Jh3yp9`AB>1p+>^c zU|~ar{Tk9H{fy;Ca@2>y{wd7qW!9ijC+mbsDz^}OEMDPS=iCSP8N2GuychK3wsRG1^O9l zjO3_}$5?idk?_vKh6>Obi3R@s-J*12DGd38>QNPNx>_{Uy>SST32s>9;v9P7W zmI-?cQk8zjW+OT3xZai>ZzK%H7j}-Y3xzEZc8#zbgnbODRzG8hk&u7%v23)Fkbej( z7PeH_GGTWJyIa_IkQVD_&}2>|A^$KE@(*Db3R@uT8eumGdqmjd!jk)8eO&#FR3kZR zhOk+}mI_-Y><(df3wu`B3&IZWk0lxOGt!OZs0)N$B=9v)3)>{@9bw-J z+bJw(0LJUVvpPGOw~+4~)8Bt6?S%^JBKxw@WhdVVXKr44gAF98rLb5L*dr8LG~+)i+jL**e+PfJ_|zlxzVfvHjXOl)Hwok2@iB#Qpyr8AI-FsYO7v#V1iWYL zDxfQ>;5r`LXV{W)n_|x@XDQ(HOTdOzp3KiRci)~a1X_H4VOcpZx!%M&pft{emn8Ep zZky7?0Crlh(yoj65MJ7MjZj|Dme-b{n}^m6EgMds8IDQ&9KKDrUdEnufdZd`n(%2W z|K32B*bCwW#4K*NCdpA(2)oKi4t;B6+}$sX#<%gcqe zba8qs2kizgM+L8?|b4M71RGA{ES*;womZ7%54;E=;dT zc{*mUuL8pCw}Idr+aO_i_BA~9wwaqAQ_7A_G*b`TIkd5`q;^ZQ%Nu8PYufx~ZRGi~ zeWurqdSdZ558}qxWn4|~S^ZQMc9YkVf%S!d;}z<6W>Qh)NM`!eVRCjfq@mi~g^+l% z&_9Y~ZDs=$e2T|r9*3*e*#3lV6_m|Cm(5^}_Pny9IfY{jXJbX`k}_CJdDgUPg{2kw zQ)hG39lt!xKxj_NcKSY9h%Gb~l)Y^`e6(ew^0a)cbd5Enc`-kltbu>2`Wl*dGgX6Q z5OG7_PV=|Vm-u|tT6I;_AGQ8Q-#GLQ?;ZO1fJoo)*6P!t86m85_vfp2I;*PRxvBkz zx9WHHV^-R?bNR=9`h1CX5awBgNAjsh*_jouNmuGoY++71!^sij4s_kp%mX+(YIPK8 z|Ao|Xi8+q&jqjQIbVwcSyaj?h6iikf#cpV|QEdGhNg3m;1Gi6k(ytNr%U_!FE0izL zx1w2T0T|5){dP%61NozA_bv2S;;EhNE$Ab0zgu+Dw@B5uux?53l*m=-bNnw+q!J>9)4ayiRm>qJPV!_~c((rGUDfZ9!YZ4LU@eXA|qjqB4Mux(@V>z2ZC9tfrc|vu{h4IJp9LcAE~=eOU1f2tpdR~ zO*`EiLu(41C56ayVN$Pqw2P(^6zi1gh3$|o_@{p^?T#BYd2G>);{1xrvcj>`W){vV z9G+iZ=qgR-jn)nd%X)=Mn7GK}>NMp4C3CQtZ^5{-{L+GwlCn{i#nUK6xC~n8y4u`P zKQgzlyc`SLk1U>6QczSpBe$?(W=X-&^q~~Sd1WP2^QRWgE-FW$>wq0MDnh`f>Et}! zc#n3WMX9F4Yv$%*7*t=@?nD{`DWp$GM+cfsrH-)>scgu=3-=|#=hlGlQM6w~?jk7+t|Gau8L?=hV&9@AN1O~+eR zYRYon5z8UTQU8M8nbBRC9f$B@cD#|$>MD#%*>~X~-dct` z$?k<1#Xq+xc+voh&7l-RN9Dtyn;)ebN;h()(O%WkyLuyK&?M2Al-nfHBymZB8I=^6 ztuay(P1|9ZOFdNUAMc4NZuRtyMm;8p^wH9YA4^MgBbSy`G-`r}b=vhOQ4>jyx)6S5 zw!laZ%~@jDdSO&qPdq(P^Ko8ILslnR%qm@1z?UOC(?XjEvAS7=8uej~D&M+BeKuCL zs(C7JGAh?1Qo)#45J43{jl?^~tCJxeswI?JbP;tstUKEiQZsQ5j!-7SI=)etJ;oOo zaZ^gfaz;Dc)z*x?ja;34YJ3?!HNL^k*7$fDM7u)9F__z}jknTEPAD_!2@hf!V@!nD z(YIzd)UReY)YiHp)$B5?19zSFx9MEBqLQHfC0apI-D(i(R@6wbCv_{zyrFYH?nYY;w`JeR&`bCVw^i;x2saV1yeGP-L6GZ3855*$gPbeIaJLvtjtIl znJR3Vur0#23TuHN=liuX5^fo587&YB-3+qj1;M8?@IEh4l~OWk=#jMRu{a7 z{<(65;g!>;7naRNY0p)(WT=ab#pTmW%I4@Iye|8d%tl*M!Km4lJ`rjSg z^nO2aaR0*ucY6tLk}x6?`esIrNX*s}1t8{lrj75WTA(dh{_GTj~EXtpaN}-OzG}y~G3a21T8k+Xk zgXwf>epx;$`RGT|5i-<}++5#~?GK`-n2_mcA|l;+Oib9FLmfi{;og;F^w2)!f8<|^ zgt6G;7W%gi^*IurG4;BGBy>pPRGS&4+RUynQj)q#7`2?RJJK|}i--Q1B^n8-am~kb z-7EBtK>0@sQnGHIEm^Inpn0te1>=E`y5N=KRXU`TP@9ccM?eZ++G{u-bfG7LWBiG3 z@TYyEMDQh{+W($Ma8uhKi&|h|`N-k|Z5I*adMBM+SK&1xB-f#o{SfVR37py{-V^cW zlyuJpYy3;cT#htn;uM^sITKUD=1lC12d1S};hZa;Q}Rs@@JqfM6*fqB-t-&UvrfM| zh{=%Ts2kyy+090BXi7oDUJypDjpw7>l%#0ML6RIr85UoAwvocpZ^}QWc!Jj|jjZ~& zezDj;R}MvM-#}c1(z9>m4mG(o8;GIoIl4TTo@t^w1x_kFs7*&_{mKo|uLyQ84tYjsy;puQrbQ=mSF>Os{XFUJMhw4yWm zEkAo2OD^LWV?S~-&e%rMa?^|1!*)-S6AGrBAgVi9bT}uYhjvJuVmeixhS5sD1N2J2 z18Ak+K%@mcbFc_7oX*rvXOh#ok({o}X}B(fU-m34l%*xo5ZAa!FX45s(_nOcJ$CpqTy?}oMU}hIQ^G%2IU?u8Tm(U+Y83ZaQO6=x z`mpF2IwN`UzGeD&ICzTddhS!A&P;CDyIbckc{t`@XIvlZ@#2ojs%3sXleaWmG2`iV zm7@5JY}VvtF*Ly_ex1CPG~266`Gk9}dh6WX2Wh+Fs%~>r+ZR_QYZg$=% zxQDIO(lMnxd_2_@S-fc*#i>%nHL_}(wBLkmhq~ydV;jEPbzDTk-LB1Yd&`gWyxvXJ zzhn|v-M-`Zyq@rLOKjb+g?{etP_O^EpD{h;*wv8`dLGr+mnPY~f+Pp6fR>$UBu5nr zD-u>IY@V4{U_}{mSIdE5evc{g$o6Eq6 z#dw?ZK}Q$PL(4`^Nj{f)Zyph$z?2B>4Nc3^<*BI^ChxG%Ol~4NxW{JE-A&P`jVT(@ z9mmAzI}W6;UG*;;zVYwOB0pb^xC3jDq~wuUE+&l-(|er2 z%j}M-I(#h+mSYyE+0LUITNr2YC~0u;EX97hinX0}II_Q1D(_x}*ng6Rss1=J28mgb#69NB7C|-4sItWDW?@u= zW=2|OcVt$~$gG&btfuIsgv^Ri$gJu?3V$rK@&ruCssL;pp z?%E}Z;ixblyooDDM@YA*u5k50{L?>|fkjxPTN0^=%X23*ok-cT(%f!bRP;H}jHg_9L zZAKN5hW7Zct8cbjt6^M5I@QvKZR0cIfWdmylT7Ojg>N6-Ces}fFUF4VDb(*;kyQ?X z6symk1S!15W*R(vnkSrd;OanZv|nkIQZmAWgO;{^V?>@R2X9Z4@$4tW2#T2YLJM{I0uf36Oryv({+uK8}xM)pr z&pW|9*(d!d?uCBtqG$7g;wgF42u@cJ*%cR7$n6uF3m$t31quHW8s&2K4E77#axT{k z@}~$8?w%qEA1VpE$VixsLD+r5dO%@Qb*oh`BROg=B);FpMsm~|NGC&S=w~;QqYg#E zl37Mqv4=GbiGa!Yxicsl0&l8nNnN)Wy!FD*6 zRQ1o5WP1n43@@oHE+`)~C^vs@_8g3)()I0cA{7G;N0jika%A~b`_GKJ+CM?RV5r(Z zTOUVUR&10$9U5+Iox3aWwvFQ~H?&P0XW3ePq-uYbbzsvRyK)evIaBoG`Cp>QKSrlC z_^+_^ec;>s%(98Bfaj;={Z4;~V?K=7MgdFg@UU#~nM5KKT5GL4YQq^l;Q zB7!z$9Q9qJk7dN@RQSi+{WBO(fNB+WVf5~TfBNT2fiQe?RMFhRf}FzQ85J`*7aKdT zyrOVU_MFnNitp&jBMPVK&yvbe^+gJmH#@%wA1BSN;A?eSRXQ?4p@Tjzp%z{H`AHA7 zoKnBm&@_}P5n|JdN@o_9x$Z{Jsew0Dzj21@fTg{|3nZyJw@cUO`Cljzu%*#VoS=6y z5&0057X|>)GsnaR6$>YcyN8(FY|ipm zXUy&w_KsY;MHrpY(95X5yG9#N~rfsg7VqD_SS&aJ>uR6AgVqC^<7UNK*D%xL?i%oX^ zdrNYSnzj6ja%j2MMY%$&dfdS2Srf8!)io#hnf@NA=84o@d7W~CUuOp=q-Hmq zf-iy+1Hl1Qm(9eO>RqRYs2pT}hb86&p9=(E%?`e}YeH&H0|sGd2hYL)fmuB; zP#_Zn1+pe*oilkYHC**WaK*Ge_$L-LBv-IguwVj=}@*PWF>Q`+qwYBm{)%LLU)4f%7 zvJC!FRo&gc-nGN-FS1J-wgbF8AAwORpMLa_7Zv4u^Pw7Hj!!VhRHdi$OU?0kbN&W% ze1D(2Kw>tXB_{nAN2V}l-v=MntCoQM zIQh&rXzT?~KJxKmFUyd}i-_#poAbbc;#EPZ_-#%gV5f|uZ-jhK+!9iq1;{ zMv9b|^bO5m^*4BBh9|Mb)%u5LsG)wXAkEGMpj(aoi`V~$B9(7vb!fzSy0jISxh9D? zzi@bwZGaAM9u5sar*7_Ucx(EWtbAs60j8JG->sYCJzbUu5A%;Nqokz0Tvkvtqp;ll zlv6#<)8RaF|BG#mrsiq#sA(9?Fk`vs)yBj`@)UJ()7!8sUk@AzC+XrO>}9$2uu%&K zg{3z^!H`1TWc`#xB9buaJ=`**44&CKVb2QtUKk}w?5>xQP{0$mS=jr+sMBNDluq%u z#b?-V!HFFn^Rr#=^y-Ip!9V@m&Agr_$7p80g3y=k-afBAo%_Ns>mOBCGDl|Wh^CsE zfP#*-;&MC1hs%IN-&Q5)aT=*mPjnXPsx%!OW|55_Gf+Oiq$-ks%QS_P*R(z{ruDLz z7Dd=La2u*w3@kR6P zMbk9#^W}_@>?UF<@~5*KSD7e!yP*=0wi|B|rzx{}Tg-+eM^VL)nPVhJr!UO<3A;kv zktOi8l!dc9%EFoHIu(x8BHTVSjPOnn?^ly8ti@pe0LI|*&t*Qt=T#J*T3J|$FDG@p zufWG~=gVw-{W2qDb1mSliD~o>m*EST=pruN%w#3LDy4VbfZUqyicwnn*Auo*C8di* zr6lo}j?Bu;Sq$P4cTWl97$)PZ=>w?=O~kO*>~q~Q%w104Ns6?t{F1}#(Ca5oF9uTk7uty-ztYOPz< zy0t2b1@}_5b^R-?T2WiIYL%*$|MSe5Iq!XM?oHlMwD$YH`^)5>_qj83@0>YvWYrh`IhoMilbnhyc2)iswNn7LNM03g0apO?6CTr7K!?t-%dtIT`zDV9#@1i z4{N*3g$AQ{QPd*S$%h|0b-219>X45g7NLik=f7DZ|W!EOda>Y-xdB1yF-bZ`}cO|D!&{%&%VYR!%r^jA$$pt$Qe31BtSqlBaz$&Cz2}w8+NyNxVU({f! zS`^(1Z%If-$R^52Z@4Rl;-9%Pl#x_ZEzS0A$?S#Y6_q7@!t&Gd@)-Hq&4>r>>B!Y= z`RTKr@^d9p?Bs`E*L?XQ|Dxo_@YBlAm-((rA?15lBaC3zSxTxD!C0k;zh~6nCdFP? zY_nq1z&HtejHN_=%=%pD5Fxtp!!2#Qc^Vn@0=Hss?qR8sbaPDmp$;$T+NoMl)>#ZJ@lg^W8`R`e^-v=aOs~S zeymkPWTT8`!P^;Qv&K0yTnpBAyBcODE6>ok156x zSc&g>#okx!L&aDs#2-rqDV*d6Y7!b$ILXaYC@D#v>5`hwxx`3!qJCtaHqRc!^En|A zcioR1Je$}J|I8H>@mUp>i%Vx$PDwY`6JTl8g39@eu-6P5MV6EqWAmn(EgzL8-YK=% zGQ(CABd`*es`N_i7xKn$X9WiyXm?~iS_aIjBawW`DpJ0O7MR7DX@XH5iN6;Wdk>U} z5F5M$+5ype$HuUZA+BRn##{l`MHm2^n8qv_IIKL=@GI6@TuW`gy4J<7OET@z1?-?1 z90I@7>OvG6|2!qb$6qcXf`;7272|lI2`35Y``J`S(dhB2U7{8`kQT_iNk9=21Km! z7~kX?53Yk|ykpIGG-?-+&C15?0v;Z`yd^JMc%`Io0O z?IwH&b^*i1gR&7W9xtGHu)<2ho!smSt7)Ae!nA!A)aejp(R!qO?_7MNU^SMKosELA z(h`5SslQ(;_K;$aD#qbe3CrPC3Cm``U~Kja)*t0eu>CBBb$g&Dn@Z~(OPOh-5=3s4 zE;Bo|bpee&cZvsf2p5?_orqn~H52N`!Ct7{O*z@95z#5cn$#-A4NQkp0nOtQxS3`N z+)OTkTNJ$n&M2VJxgBg^ijf=Ez=wkKIk2Vaw9o=jqJ@5_6l+_`(2vkE3h&Cj6F5}> z8`W!@r;nPbNZK2flG-sbS#9E+j(1@WE@Tr&Op{V2iOQ10I#MdBD4@Q?eoks=q$EOJ zogQT_XLXbM$_>n{Fdvy(lXi{y9ea?+67$&g>9aiNJ-C?8Z6&Kt22r<{tUBowRotqy z)18Ngx_NAbZayjFw910IR9Yp2Vy)#I9!jftkG7UGGfHRAbP0(|=~(9>n9|E2o&|+_ zx@O68sBn4mE%fz}WW z=3EIVXh3JJ{*E)C!?GE!4<51g!FhOg+zzY{&TM`aV06m2`yH7X++hp6TunE4Uf?Pcs<0G(w(^hL$jF$9TZ?*vT zT92>rj&03~jFnq!^g2@`C7XfF3N@nl28ORP-LdSb@wZ7M$4m|wy_uRAIUs1af54!@ zgJw(|H+BF9+m0w(n!u_G(<$n-Dy9?J+M})B{&=NpL_Ujgq~wS_!7i{*eeW&xM=pxLuN7lq5X@xLI{cJu zf@&F&scPARm!~qT1+?OXtn~hQP_=x;5kqqYhFP$_V$v*{lji>7(77{q?M2yQ;sJ%z za81UfMLdlrXnvf2rUrBtj>Zba;HE7DkWp&$G2s-zq60NC*BJ=UID_#;n&c6ssngv! zu&?SgoQVVrEJiL@t!Yw;7C@N{h0@CM7F%2Asb+p#qiPQX+k>k1?E#HRa8T9q^;Xpu z*%>Xq3JcWCt5VAM$uq4Sn@P?QlF{ZrWq?b7I9#=##mB+g7z^=u+`Hj^816moZx$>5 z{yXlp7jk^o*kX`+HLafiPpIOBDxx9^h*(rblrCP*2SrM*OslGERB4g&z0;Amf>l`x zM@uVqwPN2WMhzojyI3mU(mImT`^f%D-)gu5`=L{-4%fo8&i>B4& z_9;L{9MRTHsk@By9gKz;eK*nSJDm4t^c{aw-|;u~-L;U5qjt2u``;=U5vndACQgy{ zw`z>-{rFWMYBWc-7Tm77jFj&!K)wmK$Wp%dsA4Sb;_r3EHY+w7+G?87TM0`+4?;5u zcD1E^uYrz=ZgvOO?f)7{3mc|HbmqdVylXnxAHfAVaVFxAs5)&{+2Toa(@eyhCd#!K zrD}~ZYt7a39t#9GMxgmjT1&kLzdiKtS#J@nlX*^63 z^AsfxwwP{HRXG>vm(3|bA12TR;dAUauha>JqUplfBH)cjK zD5i`+YswVAZ$NuJvNSV|oNEe}=KYaK3hm#K7b3KzeD8Y2er74(ds8uTQ2cQ)L&CDF zE7<*ffv%&t3qPiXxSb1(7kemGQ9|61i$jM-GVyvOHj;_CrXNQAk(nxFL}_I{JiEzn z4h!p5Il{erRai;+9=c|pVCPy&4)qi48O3-SaEenO;73g(oSOA*$>r$M%F>YwAkC*? zYnIUkv9g&dTit-n@?B&=h8Yo%*GTy!hr{v-5jXPriOMG_-=kCtc8jF|L+%92u@vg? zsba_+2LQw12Q0h6=0_s=0)}xXB+UTY@#6#b$}d2;=R-Nr6Y=xQARpe|-SE#`0nLEU zuPmMtyKSK{6|A;byKMnAfj}XT8Etp6=D5%vk6iX`&id7Ly;G|eEm{bhZek<-(lIe5 zMa)Z%Kyx9>E60jpGw;cfei;PdA~#tAAt^6zq|xTIQ-65n`)q;Yh#b4Ge8;3L`;OEh z!OP&26$WZua~+G{(G>>sBD}e&$X2`esDzO6y)WQbu&*rTdo*7l*v^*ny`GBoQEZ7~ zXDPNqF-nQNW36I0D%L!S<2KhnG$L_(b~7x&zvf7sT5W4o;^Md31%g3-{|%vg`8yUm zzArPOdn#7w8Z`DAle&jh>PTU%134wwH`cYDAzI>Ftr#Um zFv^<5ce7#~R8AzHvUaq$P-vE~Ln~WH{70E_{zBkAFeQ*0ME)m`i6H@`s$^aW zyfBD{X^`1W`(}Iw{{`WsuGnpgL2cQv9V~?j z%I}$ZbnZ|(EF>Efkb<4yc)wGdZjG2nSEJ@)O*vq5oAnBFT&|Q^bZ#xxf<)# zxUrso@cN-PrAhh5cDG;^_NnjPr2c-PST_jLOlY=zZ%<449v37?ST0DA_#Ou}9n8w- zsgs8Cy`8~q!Du9%l+OV|i%n51+BCYU@UhL})kOV~Xj_WebFO@=d%XYg>)D7(-#c+D zkZ`F&7uhs2sd3jtY23irtjRfJ)Y6zMH+u9|Y(_0-DmC{ts0V)DhKaF8Fj|?%KLP{Aghhk8$(@AEEt9>BHMOuTsolPWO;AK9=wBP`R! z^iRr4Pk(Tz>l@p1VUbBOUD`D4w?M2_sUL-Y3x0aX+WyNE+L9#YdzavuU{_d5R(1(? zk7DnrzxNa?L8gnp9+vVktLv~Cie0YQm5Na=5YjjEH!p{ z0|LjHu)%kFqyD`jJT*-Q*_4bey(tqm^cGu+Q}${o=~Ak~IUOv(DMK|~;a>`Hn*YeM zE1^ojfXs%a8ZR4^%T(D&d%IVXRxHw<*)NM6gvrLIg}d0$Ax67zR1qa5rfCFQgHVFq zZK-_kKE>Wr>|Mp!DUz`46iHYP918Xu#n7?A?iZ9D%n}cJJb~3RGk4^f&0F!JxuKc{ zi+=RXW*=>TxdKhx=AYR-xvFxYsYEh7pIO9je)&|`uV}EuBy~PBcU+6)EimT?n2IS? z$B0Mf4bKFx#68P94fP)y(L67j71Dg9UoP={C4NMlE$ozgN~vX;T4pW0y9UO$c1W~n zY-I*FdNWN-_@peGa2f*Ow=qa|C7M4lo7rTSVN*#{ank(w~ zQSB;`600SGoe$rF{n%3ZW=2P_M-*GH{@zw>i(<6!E%9}>lx(IIjM63Xu}dWw+YW+# zdqWvx%s>{$T9BwFMv^GZqdOm|5h3!h%Ha^WmrCVKTykn6X^N47g zr1W?nqigTP=XOT9+H)+$foBQ3(VGC_k*vac&!KUzH0}GcIhLdP(h;FxFXOjcVDuk4 z2rtw&WBvsCExSNPFb9}j(v=Bh7ds>C@Q|!bRaYi!7|w9iXq-?M&}JbSCVD6RVagCA zkJ%xA$WrYQrC93fKB^>lu`GmpD5s#=$MS)-HfF69n{2hs9(LLRg(zZtD$v@eVDU_p zwJt3fp9&Qx=Y?4$SF8A<EojN&I!P6wC)IcBo>}!)D*N8sd1QYjLP25Ue4_?64YQYUX{{ z@1}x~-bQfTL)C6dM~Jpw2kA^11`7tUol2+XsoCU8RT6O>YZvA~7bH+MG~T&(AxDHl zQu}34sU$+dHskkyf2AV*rC{Ee5iV9L-QmoHgpS|YY~x4*D;5cxHd^3uB!LW-z-iBH zXjV9z;iHiX$4s=Pq)8@_!Zl8Xt#PnE-PAZ;pu1|mn;IvrQ2sYmIIL}+(%Oa;R?6fKRgA{uBtEW)koY)eC>X~K1-n==+V>RfNyS+22*$xq37can-#ZJ` zL#75g&r(v`h(Fdg5_TP^qfHI;xTRqF1NDhuqb%inrHYj)c9CM2Di%`%nK^S=8Dy3P zJ&{Oanb70C65D2}E##?4Q22Zuj6{2g8;xry!*2Lzu0SW6o1vVMU@@^7TI^#RMc=tC zWZPX~AD*^4$If3|Aq&1@&(|q11C_yo>(Yzjj)`}-+b&?nIM}asXTPu=$;*w9N6x#4 z#~nX|8laf}LB*VuoKYeeP0r{h&c~WA&NSx(hKPeX?+#}O=X`jCgFKAO z_|2N}q~t&W!M;E!!TKX#1l!M2SoNnEb4~oQ(iqzOMnlHE$_-i$NXf*D zU~7;5Pt_+%JQXKXe!{-LcOb=z%fE$W<*aPB6P0Hd&6&H`dZ!x;U7Y{LWklM+c*FdlrrR<&1sBF}iF z89kUsC{TN-*&k#ll5eg_tTvuqeAa#**7j6lk3J9oUca#=qy7d_KS0qnu{~q0ESMj4 z2lI8?3YSmE`&XMEiPZ<^0mH2bx5A^>6&APbLaMlBFS#+>@i>9ogDptg1O+1w((i4> z7d$|on0G!?4C=LRY?QKsxExh(z8Q@wLUM9EGO@j(AT?emLrn*@46_C~-fU3xmj~mg z?&*1;jx|r~L7iwu+^^NAKLxeiJf&nv*k?ekFc@ac?Au-eb%Mblfd*@dBlsjljyW7i zzK?5Wh01}92$ioC51$i^80`G6Ad;IlzgAl zNKb%xB&3n1z*ix@hWAs4f-u**lx@_hm^)lhR=Kb|VCf)Z+a!TD8?3g76^8AJr(}4) z{@9>9rEIPl=bVE=5vk)kLc5C97Y>KMgq;`|%fuP^zc|S3~IYXDSvG{g(DDxHtS!09XlkEW(0Ce`Sf)6Xf;N0B`S{=ey z!y~R4BP(Xi!U+zdtrN%v`9!hBmdMKTZndvwgdGE~UosGLnjNa&FX-JlXiBUvrZ@>_ zcgDB1!9F|D)z5aK`aGhTF8E0<5tTvEC89DagiFL}afx8H!U;jDe5qzq{9}Y&1BqyZ z4rTTPd}-H~1szT;@T-$O0#ElwT5?-tADQbH6clA2pPN_U`?-biRnrd1LO3*at>TLX6qT%p&JS{GMQj|oQ%8LTxr zi(_cjIg1`vDzNBv@Cu6SOi5(WiW#R>RhFHBwRHu>M_)#SSH+A)q8v~t3(T?&!Fx=b zI<-H9=%nIv4bal-uu7T%pWyde@nrr}f31Pz7hZ00w0)|n+a}fOU`$@R}1oxS^vvi(;`)_b( zJio`C?;D42;qSlWcSq3AHM>pzJyX09ZGGmuRl{xusXvk{S0<~U;jC}^XrOj zR_sPJe~v9+*qbed<;G}}307e#WA%;AtM}lHNw1ZrJ@9{R(C?}Zx)X9$+MrzxH46E# zyP>9oO0_}hPuigJG`$UagtkHD=}!?h)drQY&j3rcLFH}fZBSy;29>Y+6d{EAQYp4U z1!E}_s-047g9?`32K^|a4Ju#ISR3>aNb`e@v_Ti3qLHhKHmI|&l^S-o>nE^x539Dy zPo7v-Id9>dCR(5w#**Iryfmfv(ua_m-Tb@?F@1N<&&A;Fe|_`QCF1{@pI!y?bB8rQ zmmszs)%-jH&Chm_>`a@V%v7d^-*7(MYPbvG>ftVe3pG6lY15NMaeJDcw{J(&^WN2g z5va8+xc2%!w>^uXy`S76ZO;r<TlT4(`Y0I3 zm&M;cmdZDyFM_eY6Mv)B-_I4hO|b_Qdq}Zzv??X+VoTv54aI5|Gc&-Z%{dk|=+U5H zy&n{7=6tWlQoeT?D7F{!y&qZ%hc1C)&7AMuVJYAHH7I#6Yh+2si;BIh*fnTr9%tH| zYc1t_v(VBMY_6qZ+nmX)F@x3(dLBpZo`ERMxcDz|58JfI3(S>={}t$-$`u$FkFt(3 z1t%n9M%Ro8U5VsHjtI$=o{KU4?k02jRz{$s(nE>~@wyqXOu{snzU4R1M52(DI_`{o zFyqempv5h=Wk`u_Yr)vR6zn!j<$L6aU{5IajADu8$Sttsu_bt1@h5nCQm7Rbk z*a~n)uq%}U{AcMIeSlLL!76C>Zb{aV<$M?@6tLxu=garZjub1%-zpw4#QOSWti}b%OI^-8gbr_k5NO>b~!)=m>tqBd5 zz0zj)1e(s2h!%Pvi(CtRE#59yE7%otO^3*oxgcbK3ld*GbvHsk`2D!GYj=_IabTpw z&bE}y_lv)~6zc_fozsS4`&kO-QGpVFTt6c5tpjy@0sTF0Dc_?34Z-%Xl*mT7j zSzUtZ_SEW0od|7JYNX4i?x4i_O+(rKNg5w7}ee{l1&d2G(5mLVQBlr>Q$CmQFdlh?7vF8>0 zqhj3XDq)$665lk%xJXa1)kk(w6Ow&^ULMMC$^x%!xE##g$ra4+s>+3C5$*yEe+Jt2 z&E33R!Y)8rMIQTe;e&~w%+1Bt z=Z(#2eU@=^xH%7efbBbvIb+ena%WETsm2?nq7~=x@a14zqyXtpUt4ECFLVnwO8KTx zqg2!)VvjByOmnzZy38uRGqhDoN)G!GEQwHp-DoMyLn_9ujQC?$M*N{Kuy*@%&Z-@hFFoMEJ`s zw;S~Bp<@~d|NfTU$1A%@i5+vn79o^it1Ol8U8vY!75i8*2>+&d;r|By7KJK{pep)V z6vyK_!r*=SvC(ow?4-FyJq=VnW$Nxm6jLf|szO=wZ|bG=tf^{7LBN=bDF|n2&XDrG zE5JX&uCkPGhEWCkm0}%`1%h?4l&K^*D-u&lyn(Qj8_AiUG%shQhRB@rJGe$j=X`T2 zgc{5FD&;&W-xzol>`ZV4Nm?_jPzbBBXLyP4Qy&dqouc!`1I(GoYKs^Nea?>6xc^zC&waj8;cjonqR; zEFWxHeuA=`ln)CwSbu3Sj^zl3I^SZP#TSefulS?*3uaclal^%AFdvriv$jpf9-af` zWbot@+m7zC#vN{o-4QtB`#_%Y-QS$?jUkz7Jf-mY%BbVO*C&!Ez$#nagIuuXLf9NZDg*}1^s$vYmdq#OR3E6|Pq-fpGU4Zd~{JlELA?xKbM z3#`ZHsmuj^_6{yo@4pL%uX3};WPIlJD8s1Knb#cf;h-%)qdO>=>70L-h%im$;~}zMp7)@Ki}>X&3jDpD2iIvkxkP3XCYx8wzdWUR=HXB* zjKMggw*`X%%{{G}8>nU?Y-rzcv3bdgqGp#0pvSu#Ur$AvP|`Lr0pnU@w0FMxEb|IO<=Y)TSRA?2+Hi> zzC@9l$ZTt@>Qy0~S)TeibYT^8efzDlx}#m(wt1?|!0cxSJJQLd(b%CRjm^U@@F?S- zCOMq|l>lNACS~d8!JL^GhUaGoaQSSuA(?r+sz%wl(}pUO`P>T*BA~OUAE2J5x;R0l zjFc?16YNI&)b}1!e;XA0lVX^MHL>_!OT0kBwzib-4ONUwZ{;0-QjAh5*w>1oA8Ijn z3X6`$f|+W(B9VM7k^JWb{I8$ZW3uZEu9;9ju8Z^%>nHS>yagVyo4$V183r>yxt+c_ z9mWYg=CN-%)ATK8vTwPlk-p_MJ+9=()jVE}+l=*W(T@ZpbG$*I4mA`q#tz~y1SP#r z4n?H*KNmn3j1LviyWxvnkn7=ovK#)HE1=TMKz`}sk&EY7&O5EFa{g>+w9~6f7t4~+ zRd{pc@*CN)%w6a0O^j1fdPWvcL?gM<{2q>VA8jEFZunnpP$b~L$UK+uslrK1$EnTM z(t)hpIRM!XWc7s^_aIlB7o~cT*O}iP;(CxAX5%S%vdJgQbKZlSc3ls$`l2A}x{%cu zxh`T{A5yniH%#pKh~9E(#%Vpte0(ack_jE-(t1QFt>V39+J<+R*4e?%uuJOfrcyfI zc?hQTG6-NnVK3K#UT&6KA5k3iasj;*wRc`tS}*RmGeS~r5+MKbl_C}%4T?k}* z`rLduzmdvy4dS5m2j-htOhw<8Lc=t)ughDs;ZdZ(rIf?IK#U4|P*1aXZ zT`c8$v^XnRU&Yv_6^w0KiH~hs!Pur1EW3rnT3O2X+AG#sv4M&WR&11Fuo+?FtA^f| zcPz6MPE!SS5?ZoomRZX8CZHvDyTK+~%CvJi{-i_whne~!W&|Kv^920rvZMA$(Jw>w zg)2;K6HLJ{o?Ll(Wo<~R$`^lY&{WpSj@4(W6G;eo3?P;nTyJXm4Pftt%n~4 zdl-`z&w;7H0mJ(Z-ml-l{(((JQxhWx^y_cTf$&9TSV3cS+FuTesh9E^k;C9pvu+sG zV=-rX8CkH6{RyxVNx1n>KmCzgV3#(2z(~{h$<`5UQohH9V1m7BDc|dbfP!(oq4+Zm z6B_sFl30CCkCN$$`UO3Hj&{l>gbE%9GG-i_EQ!?<9~tzyF|0GDRbu0q-KpT@%#hV% zS{2^gl1=ngWAgE+Gl$zZjwzTpZtQ>&tE!3$i{PPn%wB~>6FYxec>cr#6055^yC~qH z)!ankc~8zQtav4l)KhFD^?fu^w>4{Vw?zHOtibDH|FH^ z!VuG#y*?;OY#iOAgj|_W&o+jK-9IDiCub$3zWR$o9Ewmp=H0@g zL{VY!#4i%77ZoKoj_AU~Kuso+fRfX<=@+zIj5m*Li7)sfQGepQ_6tB{zcTWEE^Dxd zLAoQ!HXPcL-}SEjF8WCOu9o<&cLU$G(SFxU@?9J4cfHi`yI#U~y{X@o;>=5U-A2cm zjpR&ke!<4ZII}VJ1+5aRmlnZwF(1%M-aiRQh%b0IxW8n-#5S~FCvHq6A5GMJ$#&G@ zu8F$G_CjxMtI4x=E+XK>`<8h!@ zFb-{qzYjotW&C}m*hx?wGf^yayg8tbGZcq>U+qThHhp@xKK->m{aT;4Ks6v?eNYni za8MHSk@|Eds1oyiR0^#2|JD|p&O>VcT=?pPXS|;@6ok0~YCdD5Pv|a~8erstlNXvk z#1TAVxpSc9z7NC^6DSAPbuMT*WS78$DSVKdUDp{Vl=krpTEb*astd4GLgm$=K0Ts1 z7+)2iMAE+4gysH`)AdiS5d6MrsD@vI^4^V$Y_B@i4&a zi<%?YmAMvOrrezDy8ZI!u`+N+iYyS|<>Dt$u#c57r z1UdbR`JLi)R#Tk*g9#AJ>DqTP<@CoUq7r?F`Pa#15Ve)ae74z zr|X-=>3Wl%luTb>(?=Pn`LVmq??z;Lh4B#2=^tdu>7SU0Qk?#={SwF7@I8{#ePTG> zCj(CJ7su%XVmLj#S)3kj(v#x!K{kDk)969tYJ}4V7!UEB9+xSndA=)a8mGr5*)Ium z*!>Q2`X153(`#-i=ygn|fcDrI53*}pKo9SlA2h{w0t58Vu5ANm6}Am(y{UYXn_at0 zeh-+j$j;;If(pNq&kG9L*0ymU(k}46-{WaPer=0j{jn7ozoGhP+1YqqPEIgDekTOL zQx}=L2VdEjuWV6()a?;?)iFeKvTJV1-zR@;ey{w!^T$FnmgKrB;|)BgH9V`bCoPyW z!z@MM02u3y`{B64*4M!#blVK(qc%y^aA)#86AE%`Uf{O{nK;9IS9Z+?d|c}sR!>KF zPwVgSHBXr+Tbp6;MX0?{dti?|#=UI?<#{jIm%608doWjQ2A^8ft{|tppnI#}C=~O! zAg87}zZJ51H<Wx;a^GIzQM%4eMlDygJ2ab;p|F zoTNA$b$ymM!x*O@V8V?@7!Gd3nuGnF<(+GOf11S<1$p6wW1l$TU}OVL;5gx+kAsYl zYz$Y(< zuk4|yZrbMsBRz``N($OzlujZI4oyFghXpxS*vM=hcJV$u_ zM;3eUW6+w*KCeN~fW3ns!>xt85$>mOWDc8`%o3()7~GL?Y{QfBu_(vZH9Xb?rk`BqCSQD436pkC!CK; zmI>|#w>R8AaQniIhnoa96>d7*QE+eU1S?NSBqsEV*CDNw(A+FaGcr18@IYw4A;l+{ z1`2c}^dx`(BJ}&q(C_i4dm#R0lDxr^5B766qcBkExrzPWo(#?Z1lYOF9-9C6I>^l) zzsEPSFaIC^)=b9vzc1f9u#vG~Hz)CZ`PM<1eJiI>I_QuyDLD*8Fz!?pjLRAXkz)Iyj7r!8 zE#-To6-y}A0Rvm&uZyL8uZLp26x&a+0~MRD*s+TJSh4FByIrxn6gv+Csq)@hOZnbK zie0MMj}^OKu}2hJuUH-$?Gj&srF^f8VqFzG19LIr?;K0vfDFafDE6jeZz-0AdPc&w zw3P47#t5WfCtC`p6BIjJu{#vITd_wJTd&yHia{7n%rKK+seEq_#m+!Hy#&j*l<(byan08-(wXo5!cy4X4NCkyWGUZ!Qn6%Ra>M*X?9S1=mu73?I%sL=(h z0F^%e{~ENxC86>ERrH0pc|Rs<{2#0Q$4m`amB0q1z_e_}jh}w=%PVPLBEu}x1=6Pd- ze8xlUAYV=9gM22Uz#yOb-LQM_`Xxbbxq<8ImkV|p(mgOlVy6hIU)JH&{9fo0=HvxK zJ6>1+Ic7k$`km+j)#|^pW0vuB%wNgs0I!X{^iq=q#ZB@09TPz;udDx&>42)~MFa*^ z|79X>CaiD(73rp1x3}X+>q_(K~=@+>Uw7f$t7Q!Qlxz=23}Kk%v+denTbSfU`_6?VB152)@mZd9*z$_%`i;?W^3Qaj?&VaJbnINo!5nWG_6Cyc06tQA)?Ot6TafpDtk`FY9SF@m)AV15Sqgn*^jYpS zSe~VPZxg5&4fdj?Oh0!K#N$1<^nPytNOW=p${uaRqREfpHQcx5qRH!G7EPi@%T<%e zZS-hcqes{oOk|JNH$B?zTQFI;cz-NcER+S4C%OfbAhKT>T|c%kv{-S(stQ25h?2eS zw8e^exI-3ErWPw=5#<=Sh;q!kx{UMP#uh8?h~<*0Wt>GnUxQ_o6YoPm|B;AgocDn^iPVh4wn_6tnFm=DC;=EUI8U5MgIg!!hWS#KJ<|II~SC!9_2bM!MGw# z#(h2qC1X6_fRYuUTp1`&$AFTj6G6$-i}dN``t%xo`v3IlTl(|^ecBHyQDPnlN@5-f zDt&C}>UKE7B{a5l5`6UmKX^YbW^8F{{MeE^c_c90WOe~GZzQR1Yjpp*Zma8G2YZZe zB&lvI`%}T*nCp2jYZ24)Ue+?Y=e?|;Sv~IpFe^B^(c1h@jcyDuzZ>a!n>_$tY|ndH z$4qby6)a+PS-uuEKWZJ z5f5_uLGwGs=|7v_jd1#2;~|#QbsI9}^zThXDNa9Uzr=Aie2?VxaWR}eE(1=_iR1Li zF`O=M7N^TidQziFr`q(n(WJ}F??yO%vhfhl>7|)+y4FOL;`I6UOTrv>zau%FAH(VV z3^?5}j?-OYIK6wbIK8_`Pm0rBZTcLiIgQ%rV$&|hLp-N@WyajXinGurfE*sZiwM@?UT`*uHDouPSe&zP~nhUu*hY-mt*WPdRgyvU{>_9-rE{q($}{3I`<*L<(ph| zgk`;#H(b_xd85mEFL#l-d$2aQ!>UMK#IoMnVQ#%=Gne%qX84=FtapULqL=m7mhsyn z7WCB~1182U>y^b%jV-9JQ>scJIcsxv+LO zmm|SZX_L)4we2ETZq~MoTe(@=&PC?#5!sA1MlI{T(Pi^?EbE2scwFhrdO7|?t_Q!s zj>vbc*%ZI5mu7*3%X$klq;3)K{HQ#5&2}jLYE;4ryW{uMUHG4$p zfSNs=a5Pf~^f%m1*8w~yH%2gWYYykPMP)PRnPYVT4;J*ixNJ_~sTj`4NCzycUS5z> z5t+@^TN}ydoY-t`-&8i|xEyJi&DH3aMPzgJ*0^l0HeE6oA@32{j5PKN%v+l&w4Chf z<*C)%pgQ5Ro3pt8N6Z8m?)1^CVnd1({1+H3as_w$>igrh02hSNxCr-%jK{*)f0*AV zWd9DE17k#_`sO$hVL89mL=Yz;^zkd>qoF1UPC(jrz`jv)pxxr;KqJ?ER~eazodYfY z-#G`$c~6ctxhs9%^Fyrq=J?3}^i|*WnD=yZpPP~1hI60$4U)Of4^8Emn(I8+^d3^b zFAV*DE%dvO8LJTgk#nOQlM2s`wzo%S-GxuPXnW>HcjRDJvu8qOUHJF!+cTN@{JwsB zCNrJi*Kf~kAvwpZzkf2bUq*}I`{CPvqjSupa0DAFJi%z3SFlpW$`m_YF&d^6f0ruu z1I1ob>`ldJ+d4n9zSmo^y%qbXV*gUCHD;wHY#U4Y-cE|`s@PD) zhAUR5*h6?+4#;RXA%rF`!b z#XeW852RZB?PDoyn^J7JVmxg?{GF}XRf=7!*cX_K7k^(_%J=fIc3!YTOZnbOip^52 zTCrt{y^VDS5_XHFum)bSuNCW$iEZ(>pQU_ngkqx=t5IyZVmByulVW2q-*fd06&ud}V6aL{`CdPad%a_@{+9B+EucOz*k3JW)=aF0x_b{Uea*zWNVGZ< zof(OaXox<>rRh?!eU5whOjl?hy&i{|Jh=i!V@8dcGOi4UOG+1v#zC$y>BW`bIFfaI z`TWZHr3+}UpPSh~JQOW7uX5geF|W#gm0T&~xb5NXx0r3s@)ngYhC!Livc=+AI==MY z+ym|SR%_*}GYo$fAqu_$=L@FZAiD=Y!J`s5cQM`J1ET+8j~Cn<;vtKjNXZ$bf}M>} zg578-IYCV@F6S42MV3Nln{z?465H0UK?s)OE+i?LMT)*=7qE!c9M8M~(sQ zf|#udT(fwR4B>S;zCC6uD0$Zlj-TbWg1+vFHMgUofF(Cc`8bpl6ZZzA?MK1xRO}wb zo>6R*V*BF-5|%kAVaW@@xGhhxfK6&fcvL8>U7)NTag&2K2J};rHKA7Yd6>`LHPMu=6bi z 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