Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/boringssl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
authorMartin Baulig <martin.baulig@xamarin.com>2016-10-20 04:03:55 +0300
committerMartin Baulig <martin.baulig@xamarin.com>2016-10-20 19:43:51 +0300
commiteec2ca7e76c04ca41ef5bfc875ee3b0374cb7a94 (patch)
tree1ae353ad512bac182c8fa1e572beccf8a7fd1f55 /crypto
parent2bc26c2772ad0a5d6b0ad4ba2ec77c8183d8932d (diff)
Update to chromium-stable commit 3cab5572b1fcf5a8f6018529dc30dc8d21b2a4bd.
Squashed commit of the following: commit 3cab5572b1fcf5a8f6018529dc30dc8d21b2a4bd Author: Adam Langley <agl@google.com> Date: Thu Jun 16 10:43:39 2016 -0700 Don't align NEWPOLY_POLY. The alignas in NEWPOLY_POLY told the compiler that it could assume a certain alignment. However, values were allocated with malloc with no specific alignment. We could try and allocate aligned memory but the alignment doesn't have a performance impact (on x86-64) so this is the simpler change. (Also, Windows doesn't have |posix_memalign|. The cloest thing is _alligned_alloc but then one has to use a special free function.) Change-Id: I53955a88862160c02aa5436d991b1b797c3c17db Reviewed-on: https://boringssl-review.googlesource.com/8315 Reviewed-by: David Benjamin <davidben@google.com> commit 13603a8399cd50bdc476cf46ac8c81244aadbad9 Author: Brian Smith <brian@briansmith.org> Date: Wed Jun 15 14:03:32 2016 -1000 Move "no inverse" test earlier in |BN_mod_inverse_no_branch|. There's no use doing the remaining work if we're going to fail due to there being no inverse. Change-Id: Ic6d7c92cbbc2f7c40c51e6be2de3802980d32543 Reviewed-on: https://boringssl-review.googlesource.com/8310 Reviewed-by: David Benjamin <davidben@google.com> commit 7975056ac1ca5917dff1943415864f12dc913657 Author: Steven Valdez <svaldez@google.com> Date: Thu Jun 16 06:38:04 2016 -0400 Fixing iv_length for TLS 1.3. In TLS 1.3, the iv_length is equal to the explicit AEAD nonce length, and is required to be at least 8 bytes. Change-Id: Ib258f227d0a02c5abfc7b65adb4e4a689feffe33 Reviewed-on: https://boringssl-review.googlesource.com/8304 Reviewed-by: David Benjamin <davidben@google.com> commit 3675dddab9993e9c521c76c6b10176b8da7c0141 Author: Matt Braithwaite <mab@google.com> Date: Wed May 25 10:43:39 2016 -0700 newhope_test: corrupt things harder. This ensures that the test is not flaky after lots of iterations. Along the way, change newhope_test.cc to C++. Change-Id: I4ef139444b8c8a98db53d075105eb6806f6c5fc7 Reviewed-on: https://boringssl-review.googlesource.com/8110 Reviewed-by: Adam Langley <agl@google.com> commit da7f0c65efb72556f8fc92e460e6c90cd1b1add7 Author: David Benjamin <davidben@google.com> Date: Wed Jun 15 18:41:51 2016 -0400 Unwind X509_LU_RETRY and fix a lot of type confusion. (This change will be sent upstream. Since the legacy X.509 stack is just kept around for compatibility, if they decide to fix it in a different way, we may wish to revert this and apply their fix.) Dating back to SSLeay, X509_LOOKUP_METHOD had this X509_LU_RETRY machinery. But it's not documented and it appears to have never worked. Problems with the existing logic: - X509_LU_* is not sure whether it is a type enum (to be passed into X509_LOOKUP_by_*) or a return enum (to be retained by those same functions). - X509_LOOKUP_by_* is not sure whether it returns 0/1 or an X509_LU_* value. Looking at the functions themselves, one might think it's the latter, but for X509_LOOKUP_by_subject returning both 0 and X509_LU_FAIL. But looking at the call sites, some expect 0/1 (such as X509_STORE_get1_certs) while others expect an X509_LU_* enum (such as X509_STORE_CTX_get1_issuer). It is very fortunate that FAIL happens to be 0 and X509 happens to be 1. These functions primarily call to X509_LOOKUP_METHOD hooks. Looking through OpenSSL itself and code checked into Google, I found no evidence that any hooks have been implemented except for get_by_subject in by_dir.c. We take that one as definitive and observe it believes it returns 0/1. Notably, it returns 1 on success even if asked for a type other than X509_LU_X509. (X509_LU_X509 = 1. Others are different.) I found another piece of third-party software which corroborates this worldview. - X509_STORE_get_by_subject's handling of X509_LU_RETRY (it's the j < 0 check) is broken. It saves j into vs->current_method where it probably meant to save i. (This bug has existed since SSLeay.) It also returns j (supposedly X509_LU_RETRY) while all callers of X509_STORE_get_by_subject expect it to return 0/1 by checking with ! instead of <= 0. (Note that all other codepaths return 0 and 1 so this function did not actually believe it returned X509_LU_* most of the time.) This, in turn, gives us a free of uninitialized pointers in X509_STORE_get1_certs and other functions which expect that *ret is filled in if X509_STORE_get_by_subject returns success. GCC 4.9 with optimizations from the Android NDK noticed this, which trigged this saga. (It's only reachable if any X509_LOOKUP_METHOD returned X509_LU_RETRY.) - Although the code which expects X509_STORE_get_by_subject return 0/1 does not date to SSLeay, the X509_STORE_get_by_subject call in X509_STORE_CTX_get1_issuer *does* (though, at the time, it was inline in X509_verify_cert. That code believes X509_STORE_get_by_subject returns an X509_LU_* enum, but it doesn't work either! It believes *ret is filled in on X509_LU_RETRY, thus freeing another uninitialized pointer (GCC noticed this too). Since this "retry" code has clearly never worked, from SSLeay onwards, unwind it completely rather than attempt to fix it. No X509_LOOKUP_METHOD can possibly have depended on it. Matching all non-broken codepaths X509_LOOKUP_by_* now returns 0/1 and X509_STORE_get_by_subject returns 0/1. X509_LU_* is purely a type enum with X509_LU_{REJECT,FAIL} being legacy constants to keep old code compiling. (Upstream is recommended to remove those values altogether for 1.1.0.) On the off chance any get_by_* X509_LOOKUP_METHOD implementations did not return 0/1 (I have found no evidence anywhere of this, and I believe it wouldn't have worked anyway), the X509_LOOKUP_by_* wrapper functions will coerce the return values back to 0/1 before passing up to the callers which want 0/1. This both avoids the error-prone -1/0/1 calling convention and, more importantly, avoids problems with third-party callers which expect a X509_LU_* return code. 0/1 collide with FAIL/X509 while -1 will collide with RETRY and might confuse things. Change-Id: I98ecf6fa7342866b9124dc6f0b422cb9ce4a1ae7 Reviewed-on: https://boringssl-review.googlesource.com/8303 Reviewed-by: Adam Langley <agl@google.com> commit 054e597670b158012a585f0f3d3bbf106211a7e9 Author: David Benjamin <davidben@google.com> Date: Thu Jun 16 12:08:26 2016 -0400 Include intrin.h under cover of warning pragmas. intrin.h on MSVC seems to have the same problem as other MSVC headers. https://build.chromium.org/p/client.boringssl/builders/win64_small/builds/455/steps/ninja/logs/stdio Change-Id: I98e959132c2f6188727d6c432f9c85aa0a78e91e Reviewed-on: https://boringssl-review.googlesource.com/8305 Reviewed-by: Adam Langley <agl@google.com> commit 2b360714abf9395d85ac9b50850fcd2fc4bda442 Author: Nico Weber <thakis@chromium.org> Date: Thu Jun 16 10:12:05 2016 +0200 win: Add an explicit intrin.h include to work around a clang-cl bug. I did the same change in NaCl in https://codereview.chromium.org/2070533002/. I thought NaCl is the only place where this was needed, but at least it's due to SecureZeroMemory() again. So it's two files now, but at least there's only one function we know of that needs this, and it's only called in three files total in all projects used by Chromium. BUG=chromium:592745 Change-Id: I07ed197869e26ec70c1f4b75d91fd64abae5015e Reviewed-on: https://boringssl-review.googlesource.com/8320 Reviewed-by: David Benjamin <davidben@google.com> commit 80ef4333591db8eb79c654cb030142edeab181ce Author: David Benjamin <davidben@google.com> Date: Wed Jun 15 17:46:31 2016 -0400 No-op change to kick the bots. Change-Id: Ifed0b7e23bb4df191628486b0c07c888056c22a8 commit f8fcdf399c2da11e248c0b14265ed4088001c5f2 Author: David Benjamin <davidben@google.com> Date: Wed Jun 8 15:56:13 2016 -0400 Add tests for both Channel ID and NPN together. Both messages go between CCS and Finished. We weren't testing their relative order and one of the state machine edges. Also test resume + NPN since that too is a different handshake shape. Change-Id: Iaeaf6c2c9bfd133103e2fb079d0e5a86995becfd Reviewed-on: https://boringssl-review.googlesource.com/8196 Reviewed-by: Adam Langley <agl@google.com> commit 65dac9c8a30d6427aee988a06dcb603d09863000 Author: David Benjamin <davidben@google.com> Date: Wed Jun 15 17:24:20 2016 -0400 Fix the name of OPENSSL_add_all_algorithms_conf. I named the compatibility function wrong. Change-Id: Idc289c317c5826c338c1daf58a2d3b26b09a7e49 Reviewed-on: https://boringssl-review.googlesource.com/8301 Reviewed-by: Adam Langley <agl@google.com> commit 41e08045f7e5150f74f5020d3f470335191d2e46 Author: David Benjamin <davidben@google.com> Date: Tue Jun 14 15:53:40 2016 -0400 Fix typo. Change-Id: I7699d59e61df16f2091c3e12607c08333dcc9813 Reviewed-on: https://boringssl-review.googlesource.com/8280 Reviewed-by: Adam Langley <agl@google.com> commit f715c423224a292d79ba0e3df373c828fbae29f7 Author: David Benjamin <davidben@google.com> Date: Sat Jun 11 19:01:56 2016 -0400 Make SSL_set_bio's ownership easier to reason about. SSL_set_bio has some rather complex ownership story because whether rbio/wbio are both owning depends on whether they are equal. Moreover, whether SSL_set_bio(ssl, rbio, wbio) frees ssl->rbio depends on whether rbio is the existing rbio or not. The current logic doesn't even get it right; see tests. Simplify this. First, rbio and wbio are always owning. All the weird ownership cases which we're stuck with for compatibility will live in SSL_set_bio. It will internally BIO_up_ref if necessary and appropriately no-op the left or right side as needed. It will then call more well-behaved ssl_set_rbio or ssl_set_wbio functions as necessary. Change-Id: I6b4b34e23ed01561a8c0aead8bb905363ee413bb Reviewed-on: https://boringssl-review.googlesource.com/8240 Reviewed-by: Adam Langley <agl@google.com> commit 5c0fb889a1348ecaa5691f6139f9d60a610f2129 Author: David Benjamin <davidben@google.com> Date: Tue Jun 14 14:03:51 2016 -0400 Add tests for SSL_set_fd and friends. Their implementations expose a lot of really weird SSL_set_bio behavior. Note that one test must be disabled as it doesn't even work. The subsequent commit will re-enable it. Change-Id: I4b7acadd710b3be056951886fc3e073a5aa816de Reviewed-on: https://boringssl-review.googlesource.com/8272 Reviewed-by: Adam Langley <agl@google.com> commit dfdd49c9612afb928b0275d7fad34da1803062d4 Author: Matt Braithwaite <mab@google.com> Date: Mon Jun 13 17:06:48 2016 -0700 generate_build_files: more flexible Bazel deps Include all internal headers in |test_support_sources|, since that's easier than enumerating the ones specifically required for each test. This incidentally removes test headers from |crypto_internal_headers| and |ssl_internal_headers|. Require the crypto and ssl libraries to be passed as arguments to create_tests(), rather than hardcoding the names :crypto and :ssl Change-Id: Idcc522298c5baca2a84635ad3a7fdcf6e4968a5a Reviewed-on: https://boringssl-review.googlesource.com/8260 Reviewed-by: David Benjamin <davidben@google.com> commit 7af3140a824a4a1763609a0107a918bde02bef04 Author: David Benjamin <davidben@google.com> Date: Sat Jun 11 19:37:21 2016 -0400 Remove ASN.1 BIOs. These are more remnants of CMS. Nothing uses them directly. Removing them means more code we don't have to think about when importing upstream patches. Also take out a bunch of dead prototypes nearby. Change-Id: Ife094d9d2078570006d1355fa4e3323f435be608 Reviewed-on: https://boringssl-review.googlesource.com/8244 Reviewed-by: David Benjamin <davidben@google.com> commit ae0bf3b7c15d20304279ca53550b4c75876651c1 Author: David Benjamin <davidben@google.com> Date: Sat Jun 11 19:13:58 2016 -0400 Remove ASN1_parse and ASN1_parse_dump. These are more pretty-printers for generic ASN.1 structures. They're never called externally and otherwise are only used in the X509V3_EXT_PARSE_UNKNOWN mode for the X509 pretty-print functions. That makes unknown extensions pretty-print as ASN.1 structures. This is a rather useless feature, so have that fall through to X509V3_EXT_DUMP_UNKNOWN which does a hexdump instead. (The immediate trigger is I don't know what |op| is in upstream's 8c918b7b9c93ba38790ffd1a83e23c3684e66f57 and don't think it is worth the time to puzzle that out and verify it. Better ditch this code completely.) Change-Id: I0217906367d83056030aea64ef344d4fedf74763 Reviewed-on: https://boringssl-review.googlesource.com/8243 Reviewed-by: David Benjamin <davidben@google.com> commit e77b16ef71a7669f166f0bdd153c512598694403 Author: David Benjamin <davidben@google.com> Date: Sat Jun 11 19:22:10 2016 -0400 Remove ASN.1 print hooks. These functions are never instantiated. (They're a remnant of the PKCS#7 and CMS bits.) Next time upstream touches this code, we don't have to puzzle through the diff and import it. Change-Id: I67c2102ae13e8e0527d858e1c63637dd442a4ffb Reviewed-on: https://boringssl-review.googlesource.com/8242 Reviewed-by: David Benjamin <davidben@google.com> commit 6278e24a62c613d8c23b70eec1142af7934b1900 Author: Matt Braithwaite <mab@google.com> Date: Tue Jun 14 08:18:22 2016 -0700 shim: fix var unused when asserts compiled out This is not very satisfactory. Change-Id: I7e7a86f921e66f8f830c72eac084e9fea5ffd4d9 Reviewed-on: https://boringssl-review.googlesource.com/8270 Reviewed-by: David Benjamin <davidben@google.com> commit 54217e4d85b7d7d3ba1cd3024c54615b7fa87f3c Author: Matt Braithwaite <mab@google.com> Date: Mon Jun 13 13:03:47 2016 -0700 newhope: test corrupt key exchange messages. By corrupting the X25519 and Newhope parts separately, the test shows that both are in use. Possibly excessive? Change-Id: Ieb10f46f8ba876faacdafe70c5561c50a5863153 Reviewed-on: https://boringssl-review.googlesource.com/8250 Reviewed-by: Adam Langley <agl@google.com> commit d0c677cd8e2fca7fce5d77090f3616ba1d59e0c9 Author: David Benjamin <davidben@google.com> Date: Sat Jun 11 19:12:10 2016 -0400 Avoid illegal pointers in asn1_string_canon. (Imported from upstream's 3892b95750b6aa5ed4328a287068f7cdfb9e55bc.) More reasonable would have been to drop |to| altogether and act on from[len-1], but I suppose this works. Change-Id: I280b4991042b4d330ba034f6a631f8421ddb2643 Reviewed-on: https://boringssl-review.googlesource.com/8241 Reviewed-by: Adam Langley <agl@google.com> commit 37e01b393cd4c4d2f8b2b48fe9b2a94907a495a9 Author: David Benjamin <davidben@google.com> Date: Mon Jun 13 13:42:04 2016 -0400 Spell C++11 as C++11, not C++0x. We already require GCC 4.8+, so -std=c++11 should work fine. Change-Id: I07d46d7dcccb695b5df97a702f0d5007fdff3385 Reviewed-on: https://boringssl-review.googlesource.com/8245 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit f6a74c61f7455885a514e577d69670f924b6cf6f Author: David Benjamin <davidben@google.com> Date: Fri Jun 10 13:12:20 2016 -0400 Document compiler and assembler requirements. The minimum version is purely based on what we've patched out of the perlasm files. I'm assuming they're accurate. Change-Id: I5ae176cf793512125fa78f203a1314396e8a14d7 Reviewed-on: https://boringssl-review.googlesource.com/8238 Reviewed-by: Adam Langley <agl@google.com> commit 171b5403ee767fa0f3aecd377867db6533c3eb8f Author: David Benjamin <davidben@google.com> Date: Thu Jun 9 19:01:11 2016 -0400 Fix ssl3_do_write error handling. The functions it calls all pass through <= 0 as error codes, not < 0. Change-Id: I9d0d6b1df0065efc63f2d3a5e7f3497b2c28453a Reviewed-on: https://boringssl-review.googlesource.com/8237 Reviewed-by: Adam Langley <agl@google.com> commit 166958944506f28a87a8577cd51394ee9a53a228 Author: Matt Braithwaite <mab@google.com> Date: Thu Jun 9 09:34:11 2016 -0700 Bazel: allow arbitrary path prefix before 'src' Change-Id: Ifd8e6466620a92f0d4b79c179bb21e634a930f52 Reviewed-on: https://boringssl-review.googlesource.com/8220 Reviewed-by: David Benjamin <davidben@google.com> commit a353cdb67191a6eacd3409cc642816574084b871 Author: David Benjamin <davidben@google.com> Date: Thu Jun 9 16:48:33 2016 -0400 Wrap MSVC-only warning pragmas in a macro. There's a __pragma expression which allows this. Android builds us Windows with MinGW for some reason, so we actually do have to tolerate non-MSVC-compatible Windows compilers. (Clang for Windows is much more sensible than MinGW and intentionally mimicks MSVC.) MinGW doesn't understand MSVC's pragmas and warns a lot. #pragma warning is safe to suppress, so wrap those to shush them. This also lets us do away with a few ifdefs. Change-Id: I1f5a8bec4940d4b2d947c4c1cc9341bc15ec4972 Reviewed-on: https://boringssl-review.googlesource.com/8236 Reviewed-by: Adam Langley <agl@google.com> commit 2e8ba2d25d18d37ac36f5aea07b546c7221d4d1c Author: David Benjamin <davidben@google.com> Date: Thu Jun 9 16:22:26 2016 -0400 Use one C99-style for loop. Switch one for loop to the new spelling as a canary. All our compilers seem to support it fine, except GCC needs to be told to build with -std=c99. (And, upon doing so, it'll require _XOPEN_SOURCE=700 for pthread_rwlock_t.) We'll let this sit for a bit until it's gotten into downstreams without issue and then open the floodgates. BUG=47 Change-Id: I1c69d4b2df8206e0b55f30aa59b5874d82fca893 Reviewed-on: https://boringssl-review.googlesource.com/8235 Reviewed-by: Adam Langley <agl@google.com> commit 95d7a498cceb6a1eff93b175cad10d97c1e9fb82 Author: David Benjamin <davidben@google.com> Date: Thu Jun 9 16:38:00 2016 -0400 Fix the alias checks in dtls_record.c. I forgot to save this file. Change-Id: I8540839fac2a7f426aebd7f2cb85baba337efd37 Reviewed-on: https://boringssl-review.googlesource.com/8234 Reviewed-by: Adam Langley <agl@google.com> commit bf1905a9106a1f1398c0c1509191f2767ad0709b Author: David Benjamin <davidben@google.com> Date: Thu Jun 9 13:32:25 2016 -0400 Revert "Import chacha-x86.pl fix." This reverts commit 762e1d039c1d85e4651700eed82801878a9a86bc. We no longer need to support out < in. Better to keep the assembly aligned with upstream. Change-Id: I345bf822953bd0e1e79ad5ab4d337dcb22e7676b Reviewed-on: https://boringssl-review.googlesource.com/8232 Reviewed-by: Adam Langley <agl@google.com> commit 2446db0f52b8697f3e131db3315de8a66fd9e0fe Author: David Benjamin <davidben@google.com> Date: Wed Jun 8 18:31:42 2016 -0400 Require in == out for in-place encryption. While most of OpenSSL's assembly allows out < in too, some of it doesn't. Upstream seems to not consider this a problem (or, at least, they're failing to make a decision on whether it is a problem, so we should assume they'll stay their course). Accordingly, require aliased buffers to exactly align so we don't have to keep chasing this down. Change-Id: I00eb3df3e195b249116c68f7272442918d7077eb Reviewed-on: https://boringssl-review.googlesource.com/8231 Reviewed-by: Adam Langley <agl@google.com> commit 1a01e1fc88968c4db023f38967f9e81a8c42a15d Author: David Benjamin <davidben@google.com> Date: Wed Jun 8 18:31:24 2016 -0400 Remove in-place TLS record assembly for now. Decrypting is very easy to do in-place, but encrypting in-place is a hassle. The rules actually were wrong due to record-splitting. The aliasing prefix and the alignment prefix actually differ by 1. Take it out for now in preparation for tightening the aliasing rules. If we decide to do in-place encrypt later, probably it'd be more useful to return header + in-place ciphertext + trailer. (That, in turn, needs a scatter/gather thing on the AEAD thanks to TLS 1.3's padding and record type construction.) We may also wish to rethink how record-splitting works here. Change-Id: I0187d39c541e76ef933b7c2c193323164fd8a156 Reviewed-on: https://boringssl-review.googlesource.com/8230 Reviewed-by: Adam Langley <agl@google.com> commit 67cb49d045f04973ddba0f92fe8a8ad483c7da89 Author: David Benjamin <davidben@google.com> Date: Thu Jun 9 18:57:56 2016 +0000 Fix BN_mod_word bug. On systems where we do not have BN_ULLONG (notably Win64), BN_mod_word() can return incorrect results if the supplied modulus is too big. (Imported from upstream's e82fd1b4574c8908b2c3bb68e1237f057a981820 and e4c4b2766bb97b34ea3479252276ab7c66311809.) Change-Id: Icee8a7c5c67a8ee14c276097f43a7c491e68c2f9 Reviewed-on: https://boringssl-review.googlesource.com/8233 Reviewed-by: Adam Langley <agl@google.com> commit 8f1e113a73e406db710479ea4d8478890c0514ea Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 12:49:36 2016 -0400 Ensure verify error is set when X509_verify_cert() fails. Set ctx->error = X509_V_ERR_OUT_OF_MEM when verification cannot continue due to malloc failure. Similarly for issuer lookup failures and caller errors (bad parameters or invalid state). Also, when X509_verify_cert() returns <= 0 make sure that the verification status does not remain X509_V_OK, as a last resort set it it to X509_V_ERR_UNSPECIFIED, just in case some code path returns an error without setting an appropriate value of ctx->error. Add new and some missing error codes to X509 error -> SSL alert switch. (Imported from upstream's 5553a12735e11bc9aa28727afe721e7236788aab.) Change-Id: I3231a6b2e72a3914cb9316b8e90ebaee009a1c5f Reviewed-on: https://boringssl-review.googlesource.com/8170 Reviewed-by: David Benjamin <davidben@google.com> commit 82d0ffbac1a892e23b63d055b67b7d93e489af3e Author: David Benjamin <davidben@google.com> Date: Wed Jun 8 19:19:58 2016 -0400 Use the new setter for CurrentTimeCallback in bssl_shim. Change-Id: I0aaf9d926a81c3a10e70ae3ae6605d4643419f89 Reviewed-on: https://boringssl-review.googlesource.com/8210 Reviewed-by: Taylor Brandstetter <deadbeef@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 9edb2c60559b2d1d35972de62f0d8d604c1d1e6d Author: Taylor Brandstetter <deadbeef@webrtc.org> Date: Wed Jun 8 15:26:59 2016 -0700 Adding function to set the "current time" callback used for DTLS. This callback is used by BoringSSL tests in order to simulate the time, so that the tests have repeatable results. This API will allow consumers of BoringSSL to write the same sort of tests. Change-Id: I79d72bce5510bbd83c307915cd2cc937579ce948 Reviewed-on: https://boringssl-review.googlesource.com/8200 Reviewed-by: David Benjamin <davidben@google.com> commit 2e045a980caba02868f6a1e5e29f7fff358873b1 Author: David Benjamin <davidben@google.com> Date: Wed Jun 8 13:09:56 2016 -0400 Add a deterministic PRNG for runner. It's useful, when combined with patching crypto/rand/deterministic.c in, for debugging things. Also if we want to record fuzzer transcripts again, this probably should be on. Change-Id: I109cf27ebab64f01a13466f0d960def3257d8750 Reviewed-on: https://boringssl-review.googlesource.com/8192 Reviewed-by: David Benjamin <davidben@google.com> commit 1e3376a790d044facd929205fcdf4eb30783e07f Author: David Benjamin <davidben@google.com> Date: Wed Jun 8 14:17:18 2016 -0400 Add missing copyright header. x25519-x86_64.c, like the rest of crypto/curve25519, is descended from SUPERCOP. Add the usual copyright header along with the SUPERCOP attribution. BUG=64 Change-Id: I43f3de0731f33ab2aa48492c4b742e9f23c87fe1 Reviewed-on: https://boringssl-review.googlesource.com/8195 Reviewed-by: Adam Langley <agl@google.com> commit 1c0e1e4a33249b8a64fdf1a6f6e31b8acc9c45e9 Author: David Benjamin <davidben@google.com> Date: Wed Jun 8 14:05:29 2016 -0400 Avoid overflow in newhope.go. Depending on bittedness of the runner, uint16 * uint16 can overflow an int. There's other computations that can overflow a uint32 as well, so I just made everything uint64 to avoid thinking about it too much. Change-Id: Ia3c976987f39f78285c865a2d7688600d73c2514 Reviewed-on: https://boringssl-review.googlesource.com/8193 Reviewed-by: Adam Langley <agl@google.com> commit 45d45c119475fe1601b2a19faf170cade262fffb Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 15:20:49 2016 -0400 Trim the DTLS write code slightly. Change-Id: I0fb4152ed656a60fae3aa7922652df766d4978d7 Reviewed-on: https://boringssl-review.googlesource.com/8178 Reviewed-by: David Benjamin <davidben@google.com> commit 936aada25a410cf87e0a8a4b700ea37cdb7dcbdf Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 19:09:22 2016 -0400 Move a bunch of public APIs from s3_lib.c to ssl_lib.c. The separation is purely historical (what happened to use an SSL_ctrl hook), so put them all in one place. Make a vague attempt to match the order of the header file, though we're still very far from matching. Change-Id: Iba003ff4a06684a6be342e438d34bc92cab1cd14 Reviewed-on: https://boringssl-review.googlesource.com/8189 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 01784b44b9096255a3ab7e33e7b24c4814c366f7 Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 18:00:52 2016 -0400 Rename -timeout to -idle-timeout. -timeout collides with go test's flags. Change-Id: Icfc954915a61f1bb4d0acc8f02ec8a482ea10158 Reviewed-on: https://boringssl-review.googlesource.com/8188 Reviewed-by: David Benjamin <davidben@google.com> commit 3dcec458f18eb0d8e463de254e71c252970d4cbc Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 17:13:28 2016 -0400 Rename SERVER_DONE to SERVER_HELLO_DONE. Match the actual name of the type. Change-Id: I0ad27196ee2876ce0690d13068fa95f68b05b0da Reviewed-on: https://boringssl-review.googlesource.com/8187 Reviewed-by: David Benjamin <davidben@google.com> commit cfec7c60b9eb2c403d923081ebc5158cc97e65e7 Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 17:05:07 2016 -0400 Rename s3_{clnt,srvr}.c Give them much more reasonable names. Change-Id: Id14d983ab3231da21a4f987e662c2e01af7a2cd6 Reviewed-on: https://boringssl-review.googlesource.com/8185 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 9f1dc8254effa6c430618020b08e04ab3ce8157c Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 17:03:46 2016 -0400 A bit of cleanup post state machine merging. Reorder states and functions by where they appear in the handshake. Remove unnecessary hooks on SSL_PROTOCOL_METHOD. Change-Id: I78dae9cf70792170abed6f38510ce870707e82ff Reviewed-on: https://boringssl-review.googlesource.com/8184 Reviewed-by: David Benjamin <davidben@google.com> commit df50eecfbce6c0f4614044e84869c3f43b78fc5b Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 16:49:42 2016 -0400 Fold DTLS server state machine into TLS state machine. Change-Id: I56d3d625dbe2e338f305bc1332fb0131a20e1c16 Reviewed-on: https://boringssl-review.googlesource.com/8183 Reviewed-by: David Benjamin <davidben@google.com> commit aa7734b81b5f4914829a25a4a798f22770de4bab Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 16:40:46 2016 -0400 Fold the DTLS client handshake into the TLS one. Change-Id: Ib8b1c646cf1652ee1481fe73589830be8263fc20 Reviewed-on: https://boringssl-review.googlesource.com/8182 Reviewed-by: David Benjamin <davidben@google.com> commit 0d21dcd9bb2cf06341369cfad94054af3e2aacd1 Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 16:17:06 2016 -0400 Remove unnecessary sectioning in ssl.h. There's only one thing under "SNI Extension". Change-Id: I8d8c54c286cb5775a20c4e2623896eb9be2f0009 Reviewed-on: https://boringssl-review.googlesource.com/8181 Reviewed-by: David Benjamin <davidben@google.com> commit 24fe4489d32e073e5fde1441e2073e52c06548bb Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 16:07:42 2016 -0400 Consolidate dtls1_start_timer calls. Rather than reset the timer on every message, start it up immediately after flushing one of our flights. Change-Id: I97f8b4f572ceff62c546c94933b2700975c50a02 Reviewed-on: https://boringssl-review.googlesource.com/8180 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 2a08c8d85d9c99d1548da67627e5320646eae44f Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 15:06:39 2016 -0400 Remove ssl3_do_write's 0 case. It's unreachable and wouldn't work anyway. We'd never bubble up to the caller to retry. As a consequence, the TLS side doesn't actually need to pay attention to init_off. (For now anyway. We'll probably need state of this sort once the write half is all reworked. All the craziness with wpend_buf ought to be limited to the SSL_write bits.) Change-Id: I951534f6bbeb547ce0492d5647aaf76be42108a3 Reviewed-on: https://boringssl-review.googlesource.com/8179 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit af62d61df37b50a902efb17f4ed147f6853c8bbe Author: David Benjamin <davidben@google.com> Date: Wed Jun 1 20:49:50 2016 -0400 Remove dtls1_read_bytes. It can be folded into dtls1_read_app_data. This code, since it still takes an output pointer, does not yet process records atomically. (Though, being DTLS, it probably should...) Change-Id: I57d60785c9c1dd13b5b2ed158a08a8f5a518db4f Reviewed-on: https://boringssl-review.googlesource.com/8177 Reviewed-by: David Benjamin <davidben@google.com> commit c660417bd7a7a438eddb0bc087931671b6a849e7 Author: David Benjamin <davidben@google.com> Date: Thu Jun 2 16:38:35 2016 -0400 Don't use dtls1_read_bytes to read messages. This was probably the worst offender of them all as read_bytes is the wrong abstraction to begin with. Note this is a slight change in how processing a record works. Rather than reading one fragment at a time, we process all fragments in a record and return. The intent here is so that all records are processed atomically since the connection eventually will not be able to retain a buffer holding the record. This loses a ton of (though not quite all yet) those a2b macros. Change-Id: Ibe4bbcc33c496328de08d272457d2282c411b38b Reviewed-on: https://boringssl-review.googlesource.com/8176 Reviewed-by: David Benjamin <davidben@google.com> commit 585320c9e9fc3396ffbc0d66d3c474cfdfa24607 Author: David Benjamin <davidben@google.com> Date: Tue May 10 20:46:16 2016 -0400 Don't call read_bytes in read_change_cipher_spec. Change-Id: If7d50e43c8ea28c5eed38209f31d481fb57bf225 Reviewed-on: https://boringssl-review.googlesource.com/8175 Reviewed-by: David Benjamin <davidben@google.com> commit 4aa4081e7f21916ad17e916f558a1c5dc8531830 Author: David Benjamin <davidben@google.com> Date: Wed Jun 1 19:40:23 2016 -0400 Don't use ssl3_read_bytes in ssl3_read_close_notify. read_close_notify is a very straight-forward hook and doesn't need much. Change-Id: I7407d842321ea1bcb47838424a0d8f7550ad71ca Reviewed-on: https://boringssl-review.googlesource.com/8174 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit a7810c12e99ed8cf2e3b2a049e124b4a3b1b274b Author: David Benjamin <davidben@google.com> Date: Mon Jun 6 18:54:51 2016 -0400 Make tls_open_record always in-place. The business with ssl_record_prefix_len is rather a hassle. Instead, have tls_open_record always decrypt in-place and give back a CBS to where the body is. This way the caller doesn't need to do an extra check all to avoid creating an invalid pointer and underflow in subtraction. Change-Id: I4e12b25a760870d8f8a503673ab00a2d774fc9ee Reviewed-on: https://boringssl-review.googlesource.com/8173 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 728f354a2ba5653d10ebededc5acaa5ab5c4becd Author: David Benjamin <davidben@google.com> Date: Thu Jun 2 15:42:01 2016 -0400 Push alert handling down into the record functions. Alert handling is more-or-less identical across all contexts. Push it down from read_bytes into the low-level record functions. This also deduplicates the code shared between TLS and DTLS. Now the only type mismatch managed by read_bytes is if we get handshake data in read_app_data. Change-Id: Ia8331897b304566e66d901899cfbf31d2870194e Reviewed-on: https://boringssl-review.googlesource.com/8124 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit ac2920200baec989553b145c26ed29b6807698c7 Author: David Benjamin <davidben@google.com> Date: Wed Jun 8 14:15:46 2016 -0400 Fix typo. Change-Id: I70499c686b955152840987ffe65d2d3436bf6f6d Reviewed-on: https://boringssl-review.googlesource.com/8194 Reviewed-by: David Benjamin <davidben@google.com> commit 4e9cc71a27234d8506c5b5987122188e34ece951 Author: David Benjamin <davidben@google.com> Date: Wed Jun 1 20:16:03 2016 -0400 Add helper functions for info_callback and msg_callback. This is getting a little repetitive. Change-Id: Ib0fa8ab10149557c2d728b88648381b9368221d9 Reviewed-on: https://boringssl-review.googlesource.com/8126 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: Adam Langley <agl@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 15aa895a0b6bb6d8f409cff8f1d6f47a069cd4b9 Author: David Benjamin <davidben@google.com> Date: Tue May 10 20:51:34 2016 -0400 Tidy up the DTLS code's blocking-mode retransmits. Move this logic out of dtls1_read_bytes and into dtls1_get_record. Only trigger it when reading from the buffer fails. The other one shouldn't be necessary. This exists to handle the blocking BIO case when the BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT signal triggers, so we only need to do it when timeouts actually trigger. There also doesn't seem to be a need for most of the machinery. The BIO_set_flags call seems to be working around a deficiency in the underlying BIO. There also shouldn't be a need to check the handshake state as there wouldn't be a timer to restart otherwise. Change-Id: Ic901ccfb5b82aeb409d16a9d32c04741410ad6d7 Reviewed-on: https://boringssl-review.googlesource.com/8122 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: Adam Langley <agl@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 585d7a4987126192d90d5e6d33fc400da00a863b Author: David Benjamin <davidben@google.com> Date: Thu Jun 2 14:58:00 2016 -0400 Test both synchronous and asynchronous DTLS retransmit. The two modes are quite different. One of them requires the BIO honor an extra BIO_ctrl. Also add an explanation at the top of addDTLSRetransmitTests for how these tests work. The description is scattered across many different places. BUG=63 Change-Id: Iff4cdd1fbf4f4439ae0c293f565eb6780c7c84f9 Reviewed-on: https://boringssl-review.googlesource.com/8121 Reviewed-by: David Benjamin <davidben@google.com> commit ed9c8fcb23877e647416768e741d50f36e1c170d Author: David Benjamin <davidben@google.com> Date: Wed Jun 8 09:40:32 2016 -0400 Honor exit codes in run_android_tests.go. adb kindly doesn't forward exit codes until N (https://code.google.com/p/android/issues/detail?id=3254), so we need to work around it. Otherwise all our test failures have been silently ignored (oops!). Change-Id: I03440db7dd77e6b9af5445b309b67dc719cea054 Reviewed-on: https://boringssl-review.googlesource.com/8190 Reviewed-by: David Benjamin <davidben@google.com> commit 0a45822afee4eb4a047c7b41ad1783f31a838820 Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 14:34:21 2016 -0400 Fix some missing inits (Imported from upstream's f792c663048f19347a1bb72125e535e4fb2ecf39.) Change-Id: If9bbb10de3ea858076bd9587d21ec331e837dd53 Reviewed-on: https://boringssl-review.googlesource.com/8171 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 26b7c35d8c78065a57c93a01d95b31eb85de51b9 Author: David Benjamin <davidben@google.com> Date: Tue Jun 7 14:38:01 2016 -0400 Fix DSA, preserve BN_FLG_CONSTTIME Operations in the DSA signing algorithm should run in constant time in order to avoid side channel attacks. A flaw in the OpenSSL DSA implementation means that a non-constant time codepath is followed for certain operations. This has been demonstrated through a cache-timing attack to be sufficient for an attacker to recover the private DSA key. CVE-2016-2178 (Imported from upstream's 621eaf49a289bfac26d4cbcdb7396e796784c534 and b7d0f2834e139a20560d64c73e2565e93715ce2b.) We should eventually not depend on BN_FLG_CONSTTIME since it's a mess (seeing as the original fix was wrong until we reported b7d0f2834e to them), but, for now, go with the simplest fix. Change-Id: I9ea15c1d1cc3a7e21ef5b591e1879ec97a179718 Reviewed-on: https://boringssl-review.googlesource.com/8172 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 0d275bdb32e22e5e75e30981976dbbc28c8805bc Author: David Benjamin <davidben@google.com> Date: Wed Jun 1 20:19:34 2016 -0400 Don't call ERR_clear_system_error in so many places. We've got it in entry points. That should be sufficient. (Do we even need it there?) Change-Id: I39b245a08fcde7b57e61b0bfc595c6ff4ce2a07a Reviewed-on: https://boringssl-review.googlesource.com/8127 Reviewed-by: David Benjamin <davidben@google.com> commit 4bea8509dacd4d637c5c77964d315172bf35d825 Author: David Benjamin <davidben@google.com> Date: Thu May 12 09:34:55 2016 -0400 Lift an impossible check to an assert. This cannot happen. Change-Id: Ib1b473aa91d6479eeff43f7eaf94906d0b2c2a8f Reviewed-on: https://boringssl-review.googlesource.com/8123 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit e90d004e007272df4dcc65a35138fe639635e5ab Author: David Benjamin <davidben@google.com> Date: Wed Jun 1 20:05:59 2016 -0400 Remove impossible condition. ssl->cert is never NULL. It gets created in SSL_new unconditionally. Change-Id: I5c54c9c73e281e61a554820d61421226d763d33a Reviewed-on: https://boringssl-review.googlesource.com/8125 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 83042a829260f53b0f0f49e06d33bc3a73401bf0 Author: David Benjamin <davidben@google.com> Date: Mon Jun 6 11:29:58 2016 -0400 Add a no-op OpenSSL_add_all_algorithms_conf. More spring-cleaning of unnecessary incompatibilities. Since OpenSSL_add_all_algorithms_conf doesn't specify a configuration file, it's perfectly sound to have such a function. Dear BoringSSL, please add all algorithms. Uh, sure. They were already all there, but I have added them! PS: Could you also load all your configuration files while you're at it. ...I don't have any. Fine. I have loaded all configuration files which I recognize. *mutters under breath* why does everyone ask all these strange questions... Change-Id: I57f956933d9e519445bf22f89853bd5f56904172 Reviewed-on: https://boringssl-review.googlesource.com/8160 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit adf27430efa4062ad4585d9cf788c9ab7a164e44 Author: Adam Langley <agl@google.com> Date: Sun Jun 5 11:01:20 2016 -0700 Be consistent about 𝑥_tests.txt Some files were named 𝑥_test.txt and some 𝑥_tests.txt. This change unifies around the latter. Change-Id: Id6f29bad8b998f3c3466655097ef593f7f18f82f Reviewed-on: https://boringssl-review.googlesource.com/8150 Reviewed-by: David Benjamin <davidben@google.com> commit bbc7859817e9e6d1fee989d7ded5d5836d7efded Author: David Benjamin <davidben@google.com> Date: Fri Jun 3 16:56:32 2016 -0400 Match OpenSSL's values for BIO_CTRL_*. The fake numbers collide with other numbers defined below. Also PUSH and POP are actually used. DUP legitimately isn't though. Change-Id: Iaa15a065d846b89b9b7958b78068393cfee2bd6f Reviewed-on: https://boringssl-review.googlesource.com/8143 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit f4978b78a0219c1846ad3d58a53250b827b4140a Author: David Benjamin <davidben@google.com> Date: Fri Jun 3 16:53:15 2016 -0400 Add some getters for the old lock callbacks. Some OpenSSL consumers use them, so provide no-op versions to make porting code easier. Change-Id: I4348568c1cb08d2b2c0a9ec9a17e2c0449260965 Reviewed-on: https://boringssl-review.googlesource.com/8142 Reviewed-by: David Benjamin <davidben@google.com> commit e7b3ce58ad100adbe738eae6b38e0fa72542663e Author: David Benjamin <davidben@google.com> Date: Fri Jun 3 16:45:30 2016 -0400 Add BIO_set_conn_int_port. Make building against software that expects OpenSSL easier. Change-Id: I1af090ae8208218d6e226ee0baf51053699d85cc Reviewed-on: https://boringssl-review.googlesource.com/8141 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit dbec90b62328e483323394f93e89fe657f4568c2 Author: David Benjamin <davidben@google.com> Date: Fri Jun 3 17:51:36 2016 -0400 Sort out signedness issues. Windows is, not unreasonably, complaining that taking abs() of an unsigned is ridiculous. But these values actually are signed and fit very easily in an int anyway. Change-Id: I34fecaaa3616732112e3eea105a7c84bd9cd0bae Reviewed-on: https://boringssl-review.googlesource.com/8144 Reviewed-by: Adam Langley <agl@google.com> commit d206dfa91fce51c8e454f2dd1e17da6afac76fb9 Author: David Benjamin <davidben@google.com> Date: Fri Jun 3 18:00:34 2016 -0400 Add missing newline in newhope.h. doc.go is still a little unhappy. Change-Id: I5a8f3da91dabb45d29d0e08f13b7dabdcd521c38 Reviewed-on: https://boringssl-review.googlesource.com/8145 Reviewed-by: David Benjamin <davidben@google.com> commit aa80ff50bf1467ed522a127ffb724864ac5d6d05 Author: Adam Langley <agl@google.com> Date: Fri Jun 3 14:45:18 2016 -0700 crypto/newhope: add OPENSSL_EXPORT to functions used by tests. Change-Id: Ie6701d6ea809f5c590f0773cb4b733a208553879 commit a34bd8e38cf3e6908b7a0c72ad9b78e119709ada Author: Adam Langley <agl@google.com> Date: Fri Jun 3 14:37:03 2016 -0700 crypto/newhope: fix comment typo. Change-Id: Ic7dc57680e8cc8306fb1541249fb356eece30999 commit 77fe71101bde819ea5e93eb2e3a8e1335548e210 Author: Adam Langley <agl@google.com> Date: Fri Jun 3 14:32:59 2016 -0700 crypto/newhope: print values as unsigneds. Otherwise builds fail with: crypto/newhope/newhope_statistical_test.cc:136:27: error: format specifies type 'long' but the argument has type 'uint64_t' (aka 'unsigned long long') [-Werror,-Wformat] Change-Id: I85d5816c1d7ee71eef362bffe983b2781ce310a4 commit 6b7436b0d29ac3018e23cfc0dd734dfd8024a80f Author: Matt Braithwaite <mab@google.com> Date: Thu Jun 2 17:23:29 2016 -0700 newhope: restore statistical tests. One of these tests the distribution of noise polynomials; the other tests that that agreed-upon keys (prior to whitening) have roughly equal numbers of 0s and 1s. Along the way, expose a few more API bits. Change-Id: I6b04708d41590de45d82ea95bae1033cfccd5d67 Reviewed-on: https://boringssl-review.googlesource.com/8130 Reviewed-by: Adam Langley <agl@google.com> commit 0fc7df55c04e439e765c32a4dd93e43387fe40be Author: David Benjamin <davidben@google.com> Date: Thu Jun 2 18:36:33 2016 -0400 Add SSL_CIPHER_is_DHE. Change-Id: I158d1fa1a6b70a278054862326562988c97911b5 Reviewed-on: https://boringssl-review.googlesource.com/8140 Reviewed-by: David Benjamin <davidben@google.com> commit 66af3b0ebc1ed1b4e6dba6c8d399096e21e68299 Author: Steven Valdez <svaldez@google.com> Date: Wed Jun 1 14:07:09 2016 -0400 Adding TLS 1.3 Record Layer. In TLS 1.3, the actual record type is hidden within the encrypted data and the record layer defaults to using a TLS 1.0 {3, 1} record version for compatibility. Additionally the record layer no longer checks the minor version of the record layer to maintain compatibility with the TLS 1.3 spec. Change-Id: If2c08e48baab170c1658e0715c33929d36c9be3a Reviewed-on: https://boringssl-review.googlesource.com/8091 Reviewed-by: David Benjamin <davidben@google.com> commit 1a88df13e51af83de8c1631327e942f3ca03fbe6 Author: David Benjamin <davidben@google.com> Date: Thu Jun 2 17:14:33 2016 -0400 Update style guide note on files which match OpenSSL. They match the new style not the old EAY style now. They're also not likely to be reformatted. It's just the legacy ASN.1 stuff now and we're intentionally not doing much with those. (The old text was written back before the SSL stack had been reformatted.) Change-Id: I4852761b013e8c2688ebc7eaf4970afbdc69e858 Reviewed-on: https://boringssl-review.googlesource.com/8129 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 3084e7b87ded165d3dab194f9b4666d02437cbb7 Author: Steven Valdez <svaldez@google.com> Date: Thu Jun 2 12:07:20 2016 -0400 Adding ECDHE-PSK GCM Ciphersuites. Change-Id: Iecf534ca0ebdcf34dbf4f922f5000c096a266862 Reviewed-on: https://boringssl-review.googlesource.com/8101 Reviewed-by: David Benjamin <davidben@google.com> commit 8ca0b4127da11d766067ea6ec4122017ba0edb0e Author: Piotr Sikora <piotrsikora@google.com> Date: Thu Jun 2 11:59:21 2016 -0700 Fix X25519 on OS X when using build systems other than CMake. Assembly code for X25519 wasn't included on OS X when built with build systems other than CMake, which lead to a SIGTRAP due to a missing x25519_x86_64. Reported by Gurgen Hrachyan. Change-Id: Ib6026f31cce0405ec3e75d8a52bf0940e57c62c8 Signed-off-by: Piotr Sikora <piotrsikora@google.com> Reviewed-on: https://boringssl-review.googlesource.com/8111 Reviewed-by: David Benjamin <davidben@google.com> commit 27e863e711408cb20daf1125be4519d465e48d4e Author: Matt Braithwaite <mab@google.com> Date: Wed Jun 1 16:28:48 2016 -0700 newhope: improve test vectors. This commit adds coverage of the "offer" (first) step, as well as testing all outputs of the "accept" (second) step, not just the shared key. Change-Id: Id11fe24029abc302442484a6c01fa496a1578b3a Reviewed-on: https://boringssl-review.googlesource.com/8100 Reviewed-by: Adam Langley <agl@google.com> commit 686bb19ba114b3b8c87264d9a5a7a4af32587756 Author: David Benjamin <davidben@google.com> Date: Tue May 10 15:15:41 2016 -0400 Add a unit test for one-sided shutdown. OpenSSL was actually super-buggy here (though known bugs on our end have been fixed), but pyOpenSSL was confused and incorrectly documented that callers call SSL_read after SSL_shutdown to do bidi shutdown, so we should probably support this. Add a test that it works. Change-Id: I2b6d012161330aeb4cf894bae3a0b6a55d53c70d Reviewed-on: https://boringssl-review.googlesource.com/8093 Reviewed-by: Adam Langley <agl@google.com> commit bbd43b5e90c073a3c8b719d538a273fe683b9944 Author: Steven Valdez <svaldez@google.com> Date: Wed Jun 1 11:46:58 2016 -0400 Renaming SSL3_MT_NEWSESSION_TICKET to SSL3_MT_NEW_SESSION_TICKET. This keeps the naming convention in line with the actual spec. Change-Id: I34673f78dbc29c1659b4da0e49677ebe9b79636b Reviewed-on: https://boringssl-review.googlesource.com/8090 Reviewed-by: David Benjamin <davidben@google.com> commit db207264ad69af640f6d1d60e6489ff2896e72b9 Author: Matt Braithwaite <mab@google.com> Date: Fri May 27 16:49:29 2016 -0700 newhope: refactor and add test vectors. The test vectors are taken from the reference implementation, modified to output the results of its random-number generator, and the results of key generation prior to SHA3. This allows the interoperability of the two implementations to be tested somewhat. To accomplish the testing, this commit creates a new, lower-level API that leaves the generation of random numbers and all wire encoding and decoding up to the caller. Change-Id: Ifae3517696dde4be4a0b7c1998bdefb789bac599 Reviewed-on: https://boringssl-review.googlesource.com/8070 Reviewed-by: Adam Langley <agl@google.com> commit 3995a38f3b8f8c944338e94bb63d04bc323b60b4 Author: David Benjamin <davidben@google.com> Date: Tue May 31 16:15:04 2016 -0400 Print out whether EMS was supported. Change-Id: I3c5aa418fe767bce883fcdd0a926f922f9f8bbd3 Reviewed-on: https://boringssl-review.googlesource.com/8082 Reviewed-by: Adam Langley <agl@google.com> commit 156edfe5361ad635c091265eb8035f2c310371d3 Author: David Benjamin <davidben@google.com> Date: Tue May 24 15:41:11 2016 +0000 Switch Windows CRYPTO_MUTEX implementation to SRWLOCK. Now that we no longer support Windows XP, this is available. Unfortunately, the public header version of CRYPTO_MUTEX means we still can't easily merge CRYPTO_MUTEX and CRYPTO_STATIC_MUTEX. BUG=37 Change-Id: If309de3f06e0854c505083b72fd64d1dbb3f4563 Reviewed-on: https://boringssl-review.googlesource.com/8081 Reviewed-by: Adam Langley <agl@google.com> commit 29270dea85741f69bd080bea6b28a83476c2bc91 Author: David Benjamin <davidben@google.com> Date: Tue May 24 15:28:36 2016 +0000 Split unlock functions into read/write variants. Windows SRWLOCK requires you call different functions here. Split them up in preparation for switching Windows from CRITICAL_SECTION. BUG=37 Change-Id: I7b5c6a98eab9ae5bb0734b805cfa1ff334918f35 Reviewed-on: https://boringssl-review.googlesource.com/8080 Reviewed-by: Adam Langley <agl@google.com> commit 053931e74e42bebd129d9b35d9aceb986e873a8f Author: Matt Braithwaite <mab@google.com> Date: Wed May 25 12:06:05 2016 -0700 CECPQ1: change from named curve to ciphersuite. This is easier to deploy, and more obvious. This commit reverts a few pieces of e25775bc, but keeps most of it. Change-Id: If8d657a4221c665349c06041bb12fffca1527a2c Reviewed-on: https://boringssl-review.googlesource.com/8061 Reviewed-by: Adam Langley <agl@google.com> commit d09175ffe335d9be6846b4ac5e9e622d96213a00 Author: Adam Langley <alangley@gmail.com> Date: Fri May 20 10:51:48 2016 -0700 Replace base64 decoding. This code has caused a long history of problems. This change rewrites it completely with something that is, hopefully, much simplier and robust and adds more testing. Change-Id: Ibeef51f9386afd95d5b73316e451eb3a2d7ec4e0 Reviewed-on: https://boringssl-review.googlesource.com/8033 Reviewed-by: Adam Langley <agl@google.com> commit 1cb405d96b11db5767446766d76516534067bbd1 Author: Adam Langley <alangley@gmail.com> Date: Wed May 25 16:05:11 2016 -0700 Revert "Forbid calling SSL_read, SSL_peek, and SSL_do_handshake post-shutdown." This reverts commit c7eae5a3267dfc9557314a24cc8da77d287ae885. pyOpenSSL expects to be able to call |SSL_read| after a shutdown and get EOF. Change-Id: Icc5faa09d644ec29aac99b181dac0db197f283e3 Reviewed-on: https://boringssl-review.googlesource.com/8060 Reviewed-by: Adam Langley <agl@google.com> commit 494650cfcff2330652922ebd078066c2eff202cb Author: Steven Valdez <svaldez@google.com> Date: Tue May 24 12:43:04 2016 -0400 Adding TLS 1.3 AEAD construction. The TLS 1.3 spec has an explicit nonce construction for AEADs that requires xoring the IV and sequence number. Change-Id: I77145e12f7946ffb35ebeeb9b2947aa51058cbe9 Reviewed-on: https://boringssl-review.googlesource.com/8042 Reviewed-by: Adam Langley <agl@google.com> commit 4f94b1c19f8520273fa7751687b6daab82e02bc3 Author: Steven Valdez <svaldez@google.com> Date: Tue May 24 12:31:07 2016 -0400 Adding TLS 1.3 constants. Constants representing TLS 1.3 are added to allow for future work to be flagged on TLS1_3_VERSION. To prevent BoringSSL from negotiating the non-existent TLS 1.3 version, it is explicitly disabled using SSL_OP_NO_TLSv1_3. Change-Id: Ie5258a916f4c19ef21646c4073d5b4a7974d6f3f Reviewed-on: https://boringssl-review.googlesource.com/8041 Reviewed-by: Adam Langley <agl@google.com> commit 1eca1d3816df495e83e0d22edfbb2d380dda6984 Author: Steven Valdez <svaldez@google.com> Date: Mon May 23 16:29:25 2016 -0400 Renaming Channel ID Encrypted Extensions. This renames the Channel ID EncryptedExtensions message to allow for compatibility with TLS 1.3 EncryptedExtensions. Change-Id: I5b67d00d548518045554becb1b7213fba86731f2 Reviewed-on: https://boringssl-review.googlesource.com/8040 Reviewed-by: Adam Langley <agl@google.com> commit 2f87112b963fe9dee6a75b23a8dae45000001063 Author: David Benjamin <davidben@google.com> Date: Fri May 20 14:27:17 2016 -0400 Never expose ssl->bbio in the public API. OpenSSL's bbio logic is kind of crazy. It would be good to eventually do the buffering in a better way (notably, bbio is fragile, if not outright broken, for DTLS). In the meantime, this fixes a number of bugs where the existence of bbio was leaked in the public API and broke things. - SSL_get_wbio returned the bbio during the handshake. It must always return the BIO the consumer configured. In doing so, internal accesses of SSL_get_wbio should be switched to ssl->wbio since those want to see bbio. For consistency, do the same with rbio. - The logic in SSL_set_rfd, etc. (which I doubt is quite right since SSL_set_bio's lifetime is unclear) would get confused once wbio got wrapped. Those want to compare to SSL_get_wbio. - If SSL_set_bio was called mid-handshake, bbio would get disconnected and lose state. It forgets to reattach the bbio afterwards. Unfortunately, Conscrypt does this a lot. It just never ended up calling it at a point where the bbio would cause problems. - Make more explicit the invariant that any bbio's which exist are always attached. Simplify a few things as part of that. Change-Id: Ia02d6bdfb9aeb1e3021a8f82dcbd0629f5c7fb8d Reviewed-on: https://boringssl-review.googlesource.com/8023 Reviewed-by: Kenny Root <kroot@google.com> Reviewed-by: Adam Langley <agl@google.com> commit 7e7a82d962d84b5dea95bb5dfe82616b3551e3bc Author: David Benjamin <davidben@google.com> Date: Fri May 20 20:12:42 2016 -0400 Rename GetConfigPtr to GetTestConfig. GetConfigPtr was a silly name. GetTestConfig matches the type and GetTestState. Change-Id: I9998437a7be35dbdaab6e460954acf1b95375de0 Reviewed-on: https://boringssl-review.googlesource.com/8024 Reviewed-by: Adam Langley <agl@google.com> commit 7fcfd3b37a73ca3efde348b8bb41f37052cdd959 Author: Adam Langley <alangley@gmail.com> Date: Fri May 20 11:02:50 2016 -0700 Add ISC license to Go files that were missing a license. Change-Id: I1fe3bed7d5c577748c9f4c3ccd5c1b90fec3d7d7 Reviewed-on: https://boringssl-review.googlesource.com/8032 Reviewed-by: David Benjamin <davidben@google.com> commit ce902a9bcd59c8a3ef33900d39eeb431365c34bc Author: Steven Valdez <svaldez@google.com> Date: Tue May 17 11:47:53 2016 -0400 Generalizing curves to groups in preparation for TLS 1.3. The 'elliptic_curves' extension is being renamed to 'supported_groups' in the TLS 1.3 draft, and most of the curve-specific methods are generalized to groups/group IDs. Change-Id: Icd1a1cf7365c8a4a64ae601993dc4273802610fb Reviewed-on: https://boringssl-review.googlesource.com/7955 Reviewed-by: David Benjamin <davidben@google.com> commit f1012b5c31c8dce14a0adf1566c14a87e1889ba8 Author: Steven Valdez <svaldez@google.com> Date: Fri May 20 11:40:31 2016 -0400 Fix HKDF leak. Change-Id: Ia83935420d38ededa699aa7f8011a2e358f6c4d3 Reviewed-on: https://boringssl-review.googlesource.com/8022 Reviewed-by: David Benjamin <davidben@google.com> commit 2b1ca80e0908dac5f69aa12a2ec180c62004d6fa Author: David Benjamin <davidben@google.com> Date: Fri May 20 11:28:59 2016 -0400 Link back to the main page in documentation. Also give the main page a title. Change-Id: I6db588a9454d90a5974de5446d58d709f84d1906 Reviewed-on: https://boringssl-review.googlesource.com/8020 Reviewed-by: Adam Langley <agl@google.com> commit 1aa03f07450da091b440b1f14937aa44bab4e428 Author: Adam Langley <agl@google.com> Date: Fri May 20 08:22:33 2016 -0700 Add |EVP_dss1| as an alias for |EVP_sha1| in decrepit. Change-Id: I51fa744c367d1f0c7044050f99c4992778e649bd Reviewed-on: https://boringssl-review.googlesource.com/8030 Reviewed-by: David Benjamin <davidben@google.com> commit 7cb920b6acbbddf281d9eb77ef785ec63fde3843 Author: Adam Langley <agl@google.com> Date: Fri May 20 08:28:56 2016 -0700 Include crypto.h from pem.h. open_iscsi assumes that it can get |OPENSSL_malloc| after including only pem.h and err.h. Since pem.h already includes quite a lot, this change adds crypto.h to that set so that open_iscsi is happy. Change-Id: I6dc06c27088ce3ca46c1ab53bb29650033cba267 Reviewed-on: https://boringssl-review.googlesource.com/8031 Reviewed-by: David Benjamin <davidben@google.com> commit 3686584d16dc5141dfab8510b116527c463d4b56 Author: Steven Valdez <svaldez@google.com> Date: Thu May 19 12:26:42 2016 -0400 Separating HKDF into HKDFExtract and HKDFExpand. The key schedule in TLS 1.3 requires a separate Extract and Expand phase for the cryptographic computations. Change-Id: Ifdac1237bda5212de5d4f7e8db54e202151d45ec Reviewed-on: https://boringssl-review.googlesource.com/7983 Reviewed-by: David Benjamin <davidben@google.com> commit e25775bcacb120f7f501a61d78a622ba429ba5d9 Author: Matt Braithwaite <mab@google.com> Date: Mon May 16 16:31:05 2016 -0700 Elliptic curve + post-quantum key exchange CECPQ1 is a new key exchange that concatenates the results of an X25519 key agreement and a NEWHOPE key agreement. Change-Id: Ib919bdc2e1f30f28bf80c4c18f6558017ea386bb Reviewed-on: https://boringssl-review.googlesource.com/7962 Reviewed-by: David Benjamin <davidben@google.com> commit 61d4cdc03dd7e6920d74070a8d10a6db58c044db Author: David Benjamin <davidben@google.com> Date: Thu May 19 17:55:36 2016 -0400 No-op change to kick the bots. Let's see if the Android bots work! Change-Id: Ic4a52edcb441c26bc87d776984466e04cff93ae3 commit f0322b2abce91458f62db44dc6b777fc5e0323d9 Author: nmittler <nathanmittler@google.com> Date: Thu May 19 08:49:59 2016 -0700 Use non-deprecated methods on windows. Use of strdup, close, lseek, read, and write prevent linking statically againt libcmt.lib. Change-Id: I04f7876ec0f03f29f000bbcc6b2ccdec844452d2 Reviewed-on: https://boringssl-review.googlesource.com/8010 Reviewed-by: David Benjamin <davidben@google.com> commit e09e579603bf7d05b5160bb9bd53eacea6cff47d Author: Matt Braithwaite <mab@google.com> Date: Thu May 19 10:30:52 2016 -0700 Rename NEWHOPE functions to offer/accept/finish. This is consistent with the new convention in ssl_ecdh.c. Along the way, change newhope_test.c to not iterate 1000 times over each test. Change-Id: I7a500f45b838eba8f6df96957891aa8e880ba089 Reviewed-on: https://boringssl-review.googlesource.com/8012 Reviewed-by: David Benjamin <davidben@google.com> commit 1147be052c4e8b8a9b9ed1057e786eba5d58ba56 Author: David Benjamin <davidben@google.com> Date: Thu May 19 13:23:11 2016 -0400 Inherit the parent environment when shelling out to Go. The recipes need to run with a funny GOROOT and we were clearing the environment. BUG=26 Change-Id: If233a16e060533ad3fa6f215ce596456c2d7afa5 Reviewed-on: https://boringssl-review.googlesource.com/7988 Reviewed-by: Adam Langley <agl@google.com> commit 3ccf4d6d652fb26b9fb2f0db519d68050d7867d7 Author: David Benjamin <davidben@google.com> Date: Thu May 19 00:33:41 2016 -0400 Pull Chromium's android_tools as an android-only dependency. This will be used by the bots to get adb and the NDK. BUG=26 Change-Id: Iae07a380c49b4990f0aa7d73c4f0b399924b9784 Reviewed-on: https://boringssl-review.googlesource.com/7986 Reviewed-by: Adam Langley <agl@google.com> commit 75021b747f2d1547553ee4f9c14e4be350c198c6 Author: David Benjamin <davidben@google.com> Date: Thu Apr 28 14:51:36 2016 -0400 Update Android build instructions. We now have a copy of android-cmake. Also remove the mention of running cmake twice. It seems to work fine once? The API level also got specified twice somehow. BUG=26 Change-Id: I1331b079a4d8531cd53f7de3605ac318c14b3e26 Reviewed-on: https://boringssl-review.googlesource.com/7985 Reviewed-by: Adam Langley <agl@google.com> commit f07ba17942eaffe52763ff75487acab5d2f2d5c1 Author: David Benjamin <davidben@google.com> Date: Thu Apr 28 14:38:20 2016 -0400 Check in a copy of android-cmake. BUG=26 Change-Id: I2f95740afdbc3bdb0676626679a30f1e1cc307d6 Reviewed-on: https://boringssl-review.googlesource.com/7984 Reviewed-by: Adam Langley <agl@google.com> commit 00b1069a6b22d8ea0dc6c682b5edb39297e62398 Author: David Benjamin <davidben@google.com> Date: Thu May 19 00:13:22 2016 -0400 Add an option to pick a different adb binary. This will let the recipes use the copy pulled from Chromium's android_tools. BUG=26 Change-Id: Ica6519223b9fb6daef30f3e14c72ef6422de0f6c Reviewed-on: https://boringssl-review.googlesource.com/7982 Reviewed-by: Adam Langley <agl@google.com> commit 5693e42ae4f8e9beb712fd0c551cc4109639e85f Author: Tamas Berghammer <tberghammer@google.com> Date: Thu May 19 14:28:14 2016 +0100 Fix discovery rule for perl and go for Android We don't use find_package/find_program on android to find go/perl because the android toolchain reconfigure the $PATH. The pervious way of solving this was to let ninja look for go/perl on the $PATH but this approach prevented us from specifying explicit go/perl executables what is needed for hermetic build using prebuilts. This CL changes the Android specific discovery rule to only set GO_EXECUTABLE and PERL_EXECUTABLE if they are not specified on the command line or inside the toolchain file. Change-Id: Ib6ef69707749073f2b79244ebb301502b2a5a34a Reviewed-on: https://boringssl-review.googlesource.com/8000 Reviewed-by: David Benjamin <davidben@google.com> commit ea77107e9ad507708b592b64a1fb406115d9abcf Author: David Benjamin <davidben@google.com> Date: Wed May 18 17:40:04 2016 -0400 Remove references to non-existent BIO functions. We don't have any of these. Change-Id: I8d12284fbbab0ff35ac32d35a5f2eba326ab79f8 Reviewed-on: https://boringssl-review.googlesource.com/7981 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit c82b70155d9139e56190c004b257c4882ee7ea15 Author: Matt Braithwaite <mab@google.com> Date: Tue May 17 13:06:03 2016 -0700 Go version of New Hope post-quantum key exchange. (Code mostly due to agl.) Change-Id: Iec77396141954e5f8e845cc261eadab77f551f08 Reviewed-on: https://boringssl-review.googlesource.com/7990 Reviewed-by: Adam Langley <agl@google.com> commit 54092ffeaa80ed032a50b914f14e3aa41de763df Author: David Benjamin <davidben@google.com> Date: Tue May 10 18:09:40 2016 -0400 Remove dead checks. Those checks contradict an assert up in read_app_data. This is part of shrinking read_bytes further into get_record and its callers until it goes away. Here, this kind of policy should be controlled by the callers. Change-Id: If8f9a45b8b95093beab1b3d4abcd31da55c65322 Reviewed-on: https://boringssl-review.googlesource.com/7954 Reviewed-by: Adam Langley <agl@google.com> commit fce37b0debf158b5d09f8d6a2fc09c6f680d2f32 Author: David Benjamin <davidben@google.com> Date: Sun May 15 13:51:35 2016 -0400 Add a TODO for why init_buf isn't released post-handshake. There is no good reason why this needs to be this way. Later work should make this all use a much more appropriate design. In the meantime, leave a note here so this does not look accidental. Change-Id: I7599dea7a474f54e26d9ab175b0e3cada99a974d Reviewed-on: https://boringssl-review.googlesource.com/7951 Reviewed-by: Adam Langley <agl@google.com> commit 1d64afda449ff63b8bd99172ed58549c8099ca81 Author: David Benjamin <davidben@google.com> Date: Sun May 15 13:46:07 2016 -0400 Stop reseting init_num everywhere in the handshake loop. This was needed because ssl3_get_message would get confused if init_num were not set back to zero when reading the next message. However, ssl3_get_message now treats init_num only as an output, not an input. (The message sending logic and the individual handshake states still use it, so we can't get rid of it altogether yet.) I've kept the init_num reset at the start and end of the handshake loop alone for now since that's more about initialization and cleanup. Though I believe they too do not do anything. Change-Id: I64bbdd82122498de32364e7edb3b00b166059ecd Reviewed-on: https://boringssl-review.googlesource.com/7950 Reviewed-by: Adam Langley <agl@google.com> commit 1e6d6df943a681eb8454cf40b9cd554519156e16 Author: David Benjamin <davidben@google.com> Date: Fri May 13 18:28:17 2016 -0400 Remove state parameters to ssl3_get_message. They're completely unused now. The handshake message reassembly logic should not depend on the state machine. This should partially free it up (ugly as it is) to be shared with a future TLS 1.3 implementation while, in parallel, it and the layers below, get reworked. This also cuts down on the number of states significantly. Partially because I expect we'd want to get ssl_hash_message_t out of there too. Having it in common code is fine, but it needs to be in the (supposed to be) protocol-agnostic handshake state machine, not the protocol-specific handshake message layer. Change-Id: I12f9dc57bf433ceead0591106ab165d352ef6ee4 Reviewed-on: https://boringssl-review.googlesource.com/7949 Reviewed-by: Adam Langley <agl@google.com> commit a6338be3fa1a08f53d6d5f80aa4f26629fd047ab Author: David Benjamin <davidben@google.com> Date: Fri May 13 18:12:19 2016 -0400 Simplify ssl3_get_message. Rather than this confusing coordination with the handshake state machine and init_num changing meaning partway through, use the length field already in BUF_MEM. Like the new record layer parsing, is no need to keep track of whether we are reading the header or the body. Simply keep extending the handshake message until it's far enough along. ssl3_get_message still needs tons of work, but this allows us to disentangle it from the handshake state. Change-Id: Ic2b3e7cfe6152a7e28a04980317d3c7c396d9b08 Reviewed-on: https://boringssl-review.googlesource.com/7948 Reviewed-by: Adam Langley <agl@google.com> commit 1f9329aaf55f9beb7c95550f5f1fffc395a5f859 Author: David Benjamin <davidben@google.com> Date: Fri May 13 17:00:49 2016 -0400 Add BUF_MEM_reserve. BUF_MEM is actually a rather silly API for the SSL stack. There's separate length and max fields, but init_buf effectively treats length as max and max as nothing. We possibly don't want to be using it long-term anyway (if nothing else, the char*/uint8_t* thing is irritating), but in the meantime, it'll be easier to separately fix up get_message's book-keeping and state tracking from where the handshake gets its messages from. Change-Id: I9e56ea008173991edc8312ec707505ead410a9ee Reviewed-on: https://boringssl-review.googlesource.com/7947 Reviewed-by: Adam Langley <agl@google.com> commit 4d559617cd9c0fe5c047bad610be9f6ebbbb19c9 Author: David Benjamin <davidben@google.com> Date: Wed May 18 14:31:51 2016 -0400 Unflake Unclean-Shutdown-Alert on Windows. On Windows, if we write to our socket and then close it, the peer sometimes doesn't get all the data. This was working for our shimShutsDown tests because we send close_notify in parallel with the peer and sendAlert(alertCloseNotify) did not internally return an error. For convenience, sendAlert returns a local error for non-close_notify alerts. Suppress that error to avoid the race condition. This makes it behave like the other shimShutsDown tests. Change-Id: Iad256e3ea5223285793991e2eba9c7d61f2e3ddf Reviewed-on: https://boringssl-review.googlesource.com/7980 Reviewed-by: Adam Langley <agl@google.com> commit f4ce8e532476a26ba18459cbd3622f50258969fe Author: Matt Braithwaite <mab@google.com> Date: Mon May 16 14:27:14 2016 -0700 Refactor ECDH key exchange to make it asymmetrical Previously, SSL_ECDH_METHOD consisted of two methods: one to produce a public key to be sent to the peer, and another to produce the shared key upon receipt of the peer's message. This API does not work for NEWHOPE, because the client-to-server message cannot be produced until the server's message has been received by the client. Solve this by introducing a new method which consumes data from the server key exchange message and produces data for the client key exchange message. Change-Id: I1ed5a2bf198ca2d2ddb6d577888c1fa2008ef99a Reviewed-on: https://boringssl-review.googlesource.com/7961 Reviewed-by: David Benjamin <davidben@google.com> commit 68a533c0ef70596032e724fa6762f816e20c17dd Author: David Benjamin <davidben@google.com> Date: Tue May 17 17:36:47 2016 -0400 Fix line-number counting in doc.go. There's an off-by-one when skipping blank lines. The initial logic also has an off-by-one but since it starts lineNo 0-based and then switches to 1-based, it cancels out. The decl error line number also was not of where the decl began. Change-Id: I58fd157dad3276cb9de52ac48ff8c7c73e40f337 Reviewed-on: https://boringssl-review.googlesource.com/7959 Reviewed-by: Adam Langley <agl@google.com> commit 7f6706ce64bff23d29cdf8e1fb48e8c56f464050 Author: David Benjamin <davidben@google.com> Date: Tue May 17 17:49:49 2016 -0400 MSVC doesn't like C bitfields. Change-Id: I88a415e3dd7ac9ea2fa83ca3e4d835efefa7fcc6 Reviewed-on: https://boringssl-review.googlesource.com/7970 Reviewed-by: David Benjamin <davidben@google.com> commit 47f5a1feca50e3e524ff91528e629f8d16e19309 Author: David Benjamin <davidben@google.com> Date: Tue May 17 17:31:53 2016 -0400 Allow documentation comments to begin with A/An. This aligns with Go style. Change-Id: I773c6a2e8ddd8d40a8480efae86736c4b338d203 Reviewed-on: https://boringssl-review.googlesource.com/7958 Reviewed-by: Adam Langley <agl@google.com> commit c7eae5a3267dfc9557314a24cc8da77d287ae885 Author: David Benjamin <davidben@google.com> Date: Tue May 10 18:00:03 2016 -0400 Forbid calling SSL_read, SSL_peek, and SSL_do_handshake post-shutdown. This explicitly forbids an API pattern which formerly kind of worked, but was extremely buggy (see preceding commits). Depending on how one interprets close_notify and our API, one might wish to call SSL_shutdown only once (morally shutdown(SHUT_WR)) and then SSL_read until EOF. However, this exposes additional confusing states where we might try to send an alert post-SHUT_WR, etc. Early commits made us more robust here (whether one is allowed to touch the SSL* after an operattion failed because it read an alert is... unclear), so we could support it if we wanted to, but this doesn't seem worth the additional statespace. See if we can get away with not allowing it. Change-Id: Ie7a7e5520b464360b1e6316c34ec9854b571782f Reviewed-on: https://boringssl-review.googlesource.com/7433 Reviewed-by: David Benjamin <davidben@google.com> commit ea65e100c7b5dc5cb44bd68fae64e67d19bde8f2 Author: David Benjamin <davidben@google.com> Date: Tue May 10 17:57:32 2016 -0400 Condition the read_close_notify check on type, not shutdown state. The logic to drop records really should be in the caller. Unless ssl3_read_bytes is broken apart, condition on the type field which is more robust. If we manage to call, say, SSL_read after SSL_shutdown completes at 0 (instead of 1), this logic can incorrectly cause unknown record types to be dropped. Change-Id: Iab90e5d9190fcccbf6ff55e17079a2704ed99901 Reviewed-on: https://boringssl-review.googlesource.com/7953 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit fa214e4a18785a4281375b56c00732b470e9cd5b Author: David Benjamin <davidben@google.com> Date: Tue May 10 17:03:10 2016 -0400 Tidy up shutdown state. The existing logic gets confused in a number of cases around close_notify vs. fatal alert. SSL_shutdown, while still pushing to the error queue, will fail to notice alerts. We also get confused if we try to send a fatal alert when we've already sent something else. Change-Id: I9b1d217fbf1ee8a9c59efbebba60165b7de9689e Reviewed-on: https://boringssl-review.googlesource.com/7952 Reviewed-by: David Benjamin <davidben@google.com> commit 8f73135485f376f0a08c8d54c0c0e12a5fb9a7d7 Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 01:15:15 2016 -0500 Consolidate SSL_RECEIVED_SHUTDOWN checks. SSL_RECEIVED_SHUTDOWN checks in the record layer happen in two different places. Some operations (but not all) check it, and so does read_bytes. Move it to get_record. This check should be at a low-level since it is otherwise duplicated in every operation. It is also a signal which originates from around the peer's record layer, so it makes sense to check it near the same code. (This one's in get_record which is technically lower-level than read_bytes, but we're trying to get rid of read_bytes. They're very coupled functions.) Also, if we've seen a fatal alert, replay an error, not an EOF. Change-Id: Idec35c5068ddabe5b1a9145016d8f945da2421cf Reviewed-on: https://boringssl-review.googlesource.com/7436 Reviewed-by: David Benjamin <davidben@google.com> commit f448c609035d5afb83d5de4c2b3f619f793cd832 Author: Adam Langley <agl@google.com> Date: Tue May 17 12:33:27 2016 -0700 Update INCORPORATING.md to clarify one point. In practice it seems that it's not clear that consumers of BoringSSL generally check in the generated files. Change-Id: Iaa03aa62139bbcf3e7e7f68662073854954b835f Reviewed-on: https://boringssl-review.googlesource.com/7956 Reviewed-by: David Benjamin <davidben@google.com> commit 4fac8d0eae6eaddb45f2eef7fbe978894b96b8dd Author: Adam Langley <agl@google.com> Date: Mon May 16 13:44:40 2016 -0700 Add CRYPTO_has_asm. This function will return whether BoringSSL was built with OPENSSL_NO_ASM. This will allow us to write a test in our internal codebase which asserts that normal builds should always have assembly code included. Change-Id: Ib226bf63199022f0039d590edd50c0cc823927b9 Reviewed-on: https://boringssl-review.googlesource.com/7960 Reviewed-by: David Benjamin <davidben@google.com> commit c032dfa27ec8a9f286e3ae7e545932aac13b87d6 Author: David Benjamin <davidben@google.com> Date: Thu May 12 14:54:57 2016 -0400 Client auth is only legal in certificate-based ciphers. OpenSSL used to only forbid it on the server in plain PSK and allow it on the client. Enforce it properly on both sides. My read of the rule in RFC 5246 ("A non-anonymous server can optionally request a certificate") and in RFC 4279 ("The Certificate and CertificateRequest payloads are omitted from the response.") is that client auth happens iff we're certificate-based. The line in RFC 4279 is under the plain PSK section, but that doesn't make a whole lot of sense and there is only one diagram. PSK already authenticates both sides. I think the most plausible interpretation is that this is for certificate-based ciphers. Change-Id: If195232c83f21e011e25318178bb45186de707e6 Reviewed-on: https://boringssl-review.googlesource.com/7942 Reviewed-by: David Benjamin <davidben@google.com> commit 060cfb091194edf7341d91009764c64096a87157 Author: David Benjamin <davidben@google.com> Date: Thu May 12 00:43:05 2016 -0400 Simplify handshake message size limits. A handshake message can go up to 2^24 bytes = 16MB which is a little large for the peer to force us to buffer. Accordingly, we bound the size of a handshake message. Rather than have a global limit, the existing logic uses a different limit at each state in the handshake state machine and, for certificates, allows configuring the maximum certificate size. This is nice in that we engage larger limits iff the relevant state is reachable from the handshake. Servers without client auth get a tighter limit "for free". However, this doesn't work for DTLS due to out-of-order messages and we use a simpler scheme for DTLS. This scheme also is tricky on optional messages and makes the handshake <-> message layer communication complex. Apart from an ignored 20,000 byte limit on ServerHello, the largest non-certificate limit is the common 16k limit on ClientHello. So this complexity wasn't buying us anything. Unify everything on the DTLS scheme except, so as not to regress bounds on client-auth-less servers, also correctly check for whether client auth is configured. The value of 16k was chosen based on this value. (The 20,000 byte ServerHello limit makes no sense. We can easily bound the ServerHello because servers may not send extensions we don't implement. But it gets overshadowed by the certificate anyway.) Change-Id: I00309b16d809a3c2a1543f99fd29c4163e3add81 Reviewed-on: https://boringssl-review.googlesource.com/7941 Reviewed-by: David Benjamin <davidben@google.com> commit 4e7a1ff055b987c9f900a2279380290cb8d9e939 Author: Brian Smith <brian@briansmith.org> Date: Thu Apr 21 17:10:09 2016 -1000 Remove unuseful comments in |BN_mod_exp|. The performance measurements seem to be very out-of-date. Also, the idea for optimizing the case of an even modulus is interesting, but it isn't useful because we never use an even modulus. Change-Id: I012eb37638cda3c63db0e390c8c728f65b949e54 Reviewed-on: https://boringssl-review.googlesource.com/7733 Reviewed-by: David Benjamin <davidben@google.com> commit 448fa427795c5e8a447b18a05600ad19961acf94 Author: Brian Smith <brian@briansmith.org> Date: Thu Apr 21 17:08:29 2016 -1000 Deprecate |BN_mod_exp2_mont| and simplify its implementation. This function is only really useful for DSA signature verification, which is something that isn't performance-sensitive. Replace its optimized implementation with a naïve implementation that's much simpler. Note that it would be simpler to use |BN_mod_mul| in the new implementation; |BN_mod_mul_montgomery| is used instead only to be consistent with other work being done to replace uses of non-Montgomery modular reduction with Montgomery modular reduction. Change-Id: If587d463b73dd997acfc5b7ada955398c99cc342 Reviewed-on: https://boringssl-review.googlesource.com/7732 Reviewed-by: David Benjamin <davidben@google.com> commit ada97998f270ad45d46a986723852db0af54736f Author: David Benjamin <davidben@google.com> Date: Fri May 13 13:14:28 2016 -0400 Fix stack macro const-ness. sk_FOO_num may be called on const stacks. Given that was wrong, I suspect no one ever uses a const STACK_OF(T)... Other macros were correctly const, but were casting the constness a way (only to have it come back again). Also remove the extra newline after a group. It seems depending on which version of clang-format was being used, we'd either lose or keep the extra newline. The current file doesn't have them, so settle on that. Change-Id: I19de6bc85b0a043d39c05ee3490321e9f0adec60 Reviewed-on: https://boringssl-review.googlesource.com/7946 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit c6cc6e76a6919769977046df6a72a5bd8a171cef Author: David Benjamin <davidben@google.com> Date: Tue May 10 17:19:00 2016 -0400 Make kSRTPProfiles static. It's only used in one file. Change-Id: I5d60cbc02799b22317f5f7593faf25eb8eea0a24 Reviewed-on: https://boringssl-review.googlesource.com/7943 Reviewed-by: David Benjamin <davidben@google.com> commit ef2dc61edd4f5bedcefd88703c4eb5786f01a0a1 Author: David Benjamin <davidben@google.com> Date: Tue May 10 16:08:57 2016 -0400 Remove invalid comment for alert_dispatch. The array is of size two for the level and description, not because we allow two alerts outstanding; we don't. Change-Id: I25e42c059ce977a947397a3dc83e9684bc8f0595 Reviewed-on: https://boringssl-review.googlesource.com/7940 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 8de8b3d23ced19c9e1fadfd31a9ada172909ca2a Author: David Benjamin <davidben@google.com> Date: Thu May 12 23:07:47 2016 -0400 Revise run_android_tests.go for use in recipes. Allow running only one of the test suites. The recipe expects these happen in two separate steps (it wants only one JSON results file per "step"). Also add an option to extract the results file. BUG=26 Change-Id: I0cda19bd9643b66f40a30bc8410a357da33baacc Reviewed-on: https://boringssl-review.googlesource.com/7945 Reviewed-by: Adam Langley <agl@google.com> commit 641f42b1a2c54f5eb2512a6d970b7b783eac7688 Author: David Benjamin <davidben@google.com> Date: Thu May 12 23:05:57 2016 -0400 Make i2d_X509_AUX work if *pp = NULL. When *pp is NULL, don't write garbage, return an unexpected pointer or leak memory on error. (Imported from upstream's 36c37944909496a123e2656ad1f651769a7cc72f.) This calling convention... Change-Id: Ic733092cfb942a3e1d3ceda6797222901ad55bef Reviewed-on: https://boringssl-review.googlesource.com/7944 Reviewed-by: Adam Langley <agl@google.com> commit 80d1b35520127a83cde953249c4533360c27a5df Author: David Benjamin <davidben@google.com> Date: Wed May 4 19:19:06 2016 -0400 Add a test for SCTs sent on resume. The specification, sadly, did not say that servers MUST NOT send it, only that they are "not expected to" do anything with the client extension. Accordingly, we decided to tolerate this. Add a test for this so that we check this behavior. This test also ensures that the original session's value for it carries over. Change-Id: I38c738f218a09367c9d8d1b0c4d68ab5cbec730e Reviewed-on: https://boringssl-review.googlesource.com/7860 Reviewed-by: Adam Langley <agl@google.com> commit e31d103a0ae334d0dc1de348e8177ae984d169f0 Author: Brian Smith <brian@briansmith.org> Date: Thu Apr 21 17:08:13 2016 -1000 Deprecate |BN_mod_exp_mont_word| and simplify its implementation. |BN_mod_exp_mont_word| is only useful when the base is a single word in length and timing side channel protection of the exponent is not needed. That's never the case in real life. Keep the function in the API, but removes its single-word-base optimized implementation with a call to |BN_mod_exp_mont|. Change-Id: Ic25f6d4f187210b681c6ee6b87038b64a5744958 Reviewed-on: https://boringssl-review.googlesource.com/7731 Reviewed-by: David Benjamin <davidben@google.com> commit 376a0fed24cad21752357add314f3c43e39c3bcc Author: Taylor Brandstetter <deadbeef@google.com> Date: Tue May 10 19:30:28 2016 -0700 Adding a method to change the initial DTLS retransmission timer value. This allows an application to override the default of 1 second, which is what's instructed in RFC 6347 but is not an absolute requirement. Change-Id: I0bbb16e31990fbcab44a29325b6ec7757d5789e5 Reviewed-on: https://boringssl-review.googlesource.com/7930 Reviewed-by: David Benjamin <davidben@google.com> commit 0e01eb534c25ccd5ce59917cd5ef37c059a94ebb Author: Brian Smith <brian@briansmith.org> Date: Thu Apr 21 16:30:37 2016 -1000 Call |BN_mod_exp_mont_consttime| in crypto/dh. |BN_mod_exp_mont| will forward to |BN_mod_exp_mont_consttime|, so this is a no-op semantically. However, this allows the linker to drop the implementation of |BN_mod_exp_mont| even when the DH code is in use. Change-Id: I0cb8b260224ed661ede74923bd134acb164459c1 Reviewed-on: https://boringssl-review.googlesource.com/7730 Reviewed-by: David Benjamin <davidben@google.com> commit d229433d7537dae5723a168c64ed8c70719d3f24 Author: David Benjamin <davidben@google.com> Date: Mon May 9 13:27:01 2016 -0400 Free any existing SRTP connection profile. When setting a new SRTP connection profile using SSL_CTX_set_tlsext_use_srtp() or SSL_set_tlsext_use_srtp() we should free any existing profile first to avoid a memory leak. (Imported from upstream's fbdf0299dc98bc611d854c0a62c6ab1810d856fc.) Change-Id: I738e711f1c23ed4a8ac97486d94c08cc0db7aea7 Reviewed-on: https://boringssl-review.googlesource.com/7910 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 347331541536b616bf5147d6f8093a1541b77da7 Author: David Benjamin <davidben@google.com> Date: Sat May 7 17:40:02 2016 -0400 Reimplement PKCS #3 DH parameter parsing with crypto/bytestring. Also add a test. This is the last of the openssl/asn1.h includes from the directories that are to be kept in the core libcrypto library. (What remains is to finish sorting out the crypto/obj stuff. We'll also want to retain a decoupled version of the PKCS#12 stuff.) Functions that need to be audited for reuse: i2d_DHparams BUG=54 Change-Id: Ibef030a98d3a93ae26e8e56869f14858ec75601b Reviewed-on: https://boringssl-review.googlesource.com/7900 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit e72df93461c6d9d2b5698f10e16d3ab82f5adde3 Author: David Benjamin <davidben@google.com> Date: Fri May 6 02:12:26 2016 -0400 Add a README.md for ssl/test. The SSL tests are fairly different from most test suites. Add some high-level documentation so people know where to start. Change-Id: Ie5ea108883dca82675571a3025b3fbc4b9d66da9 Reviewed-on: https://boringssl-review.googlesource.com/7890 Reviewed-by: Adam Langley <agl@google.com> commit e9a36421266fccc28506b1b0d2f8b0bd9b7f04f7 Author: David Benjamin <davidben@google.com> Date: Thu May 5 21:53:00 2016 -0400 Don't reset ssl->shutdown in the state machine. This is particularly questionable with ClientHello encompassing several states. ssl->shutdown is already initialized to zero and further reset in SSL_set_{connect,accept}_state. At any other state, if it manages to not be a no-op, it will erase a close_notify we have sent or received, neither of which is okay. (I don't think this is possible, but I'm not positive.) This dates to the initial commit in OpenSSL, so git is not enlightening. The state machine logic historically reset many fields it had no reason to reset, so this is likely more of that. Change-Id: Ie872316701720cb8ef2cfcb67b7f07a9fea3620f Reviewed-on: https://boringssl-review.googlesource.com/7874 Reviewed-by: Adam Langley <agl@google.com> commit b095f0f0ca4ef08de8c5b48045e20206d55173bf Author: David Benjamin <davidben@google.com> Date: Thu May 5 21:50:24 2016 -0400 Remove the push argument to ssl_init_wbio_buffer. Having bbio be tri-state (not allocated, allocated but not active, and allocated and active) is confusing. The extra state is only used in the client handshake, where ClientHello is special-cased to not go through the buffer while everything else is. This dates to OpenSSL's initial commit and doesn't seem to do much. I do not believe it can affect renego as the buffer only affects writes; although OpenSSL accepted interleave on read (though this logic predates it slightly), it never sent application data while it believed a handshake was active. The handshake would always be driven to completion first. My guess is this was to save a copy since the ClientHello is a one-message flight so it wouldn't need to be buffered? This is probably not worth the extra variation in the state. (Especially with the DTLS state machine going through ClientHello twice and pushing the BIO in between the two. Though I suspect that was a mistake in itself. If the optimization guess is correct, there was no need to do that.) Change-Id: I6726f866e16ee7213cab0c3e6abb133981444d47 Reviewed-on: https://boringssl-review.googlesource.com/7873 Reviewed-by: Adam Langley <agl@google.com> commit 2730955e7449989bb982092d3301f89340dbc189 Author: David Benjamin <davidben@google.com> Date: Thu May 5 21:17:53 2016 -0400 Check BIO_flush return value. That we're ignoring the return value is clearly wrong when dtls1_retransmit_message has other code that doesn't ignore it, by way of dtls1_do_handshake_write. Change-Id: Ie3f8c0defdf1f5e709d67af4ca6fa4f0d83c76c9 Reviewed-on: https://boringssl-review.googlesource.com/7872 Reviewed-by: Adam Langley <agl@google.com> commit 30152fdfc116d9ef328661b59a306d6b591243af Author: David Benjamin <davidben@google.com> Date: Thu May 5 20:45:48 2016 -0400 Always buffer DTLS retransmits. The DTLS bbio logic is rather problematic, but this shouldn't make things worse. In the in-handshake case, the new code merges the per-message (unchecked) BIO_flush calls into one call at the end but otherwise the BIO is treated as is. Otherwise any behavior around non-block writes should be preserved. In the post-handshake case, we now install the buffer when we didn't previously. On write error, the buffer will have garbage in it, but it will be discarded, so that will preserve any existing retry behavior. (Arguably the existing retry behavior is a bug, but that's another matter.) Add a test for all this, otherwise it is sure to regress. Testing for record-packing is a little fuzzy, but we can assert ChangeCipherSpec always shares a record with something. BUG=57 Change-Id: I8603f20811d502c71ded2943b0e72a8bdc4e46f2 Reviewed-on: https://boringssl-review.googlesource.com/7871 Reviewed-by: Adam Langley <agl@google.com> commit 9d908ba519f2cfe5e21561bdee3e224b94d14a89 Author: David Benjamin <davidben@google.com> Date: Thu May 5 18:54:33 2016 -0400 Add BORINGSSL_API_VERSION. The BORINGSSL_YYYYMM #defines have served well to coordinate short-term skews in BoringSSL's public API, but some consumers (notably wpa_supplicant in Android) wish to build against multiple versions for an extended period of time. Consumers should not do this unless there is no alternative, but to accommodate this, start a BORINGSSL_API_VERSION counter. In future, instead of BORINGSSL_YYYYMM #defines, we'll simply increment the number. This is specifically called an "API version" rather than a plain "version" as this number does not denote any particular point in development or stability. It purely counts how many times we found it convenient to let the preprocessor observe a public API change up to now. Change-Id: I39f9740ae8e793cef4c2b5fb5707b9763b3e55ce Reviewed-on: https://boringssl-review.googlesource.com/7870 Reviewed-by: Adam Langley <agl@google.com> commit 598e55a795fa206571f94a7cb2e5834728b85c98 Author: Brian Smith <brian@briansmith.org> Date: Sat Mar 26 20:17:37 2016 -1000 Do RSA blinding unless |e| is NULL and specifically requested not to. Change-Id: I189db990df2a3cbf68f820a8f9f16142ccd7070f Reviewed-on: https://boringssl-review.googlesource.com/7595 Reviewed-by: David Benjamin <davidben@google.com> commit 86080c336fc9a71d600abc67ba3185390e005061 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 25 12:23:16 2016 -1000 Verify RSA private key operation regardless of whether CRT is used. Previously, the verification was only done when using the CRT method, as the CRT method has been shown to be extremely sensitive to fault attacks. However, there's no reason to avoid doing the verification when the non-CRT method is used (performance-sensitive applications should always be using the CRT-capable keys). Previously, when we detected a fault (attack) through this verification, libcrypto would fall back to the non-CRT method and assume that the non-CRT method would give a correct result, despite having just detecting corruption that is likely from an attack. Instead, just give up, like NSS does. Previously, the code tried to handle the case where the input was not reduced mod rsa->n. This is (was) not possible, so avoid trying to handle that. This simplifies the equality check and lets us use |CRYPTO_memcmp|. Change-Id: I78d1e55520a1c8c280cae2b7256e12ff6290507d Reviewed-on: https://boringssl-review.googlesource.com/7582 Reviewed-by: David Benjamin <davidben@google.com> commit 8107e92a1aa71cee717450c25dace2a32233a917 Author: Adam Langley <agl@google.com> Date: Wed May 4 10:32:37 2016 -0700 Add a comment with an SMT verification of the Barrett reductions. Change-Id: I32dc13b16733fc09e53e3891ca68f51df6c1624c Reviewed-on: https://boringssl-review.googlesource.com/7850 Reviewed-by: David Benjamin <davidben@google.com> commit f0bba6166356a4dac6c1cef7a693c96cb1e3f567 Author: David Benjamin <davidben@google.com> Date: Tue May 3 11:35:23 2016 -0400 Fix ASN1_INTEGER handling. Only treat an ASN1_ANY type as an integer if it has the V_ASN1_INTEGER tag: V_ASN1_NEG_INTEGER is an internal only value which is never used for on the wire encoding. (Imported from upstream's d4b25980020821d4685752ecb9105c0902109ab5.) This is redundant with our fb2c6f8c8565e1e2d85c24408050c96521acbcdc which I think is a much better fix (having two notions of "type" depending on whether we're in an ASN1_TYPE or an ASN1_STRING is fragile), so I think we should keep our restriction too. Still, this is also worth doing. Change-Id: I6ea54aae7b517a59c6e563d8c993d0ee22e25bee Reviewed-on: https://boringssl-review.googlesource.com/7848 Reviewed-by: Adam Langley <agl@google.com> commit de2cf273d76e94ee47cb4ed7e9826f68175ec217 Author: David Benjamin <davidben@google.com> Date: Tue May 3 09:19:36 2016 -0400 Avoid theoretical overflows in EVP_EncodeUpdate. See also upstream's 172c6e1e14defe7d49d62f5fc9ea6a79b225424f, but note our values have different types. In particular, because we put in_len in a size_t and C implicitly requires that all valid buffers' lengths fit in a ptrdiff_t (signed), the overflow was impossible, assuming EVP_ENCODE_CTX::length is untouched externally. More importantly, this function is stuck taking an int output and has no return value, so the only plausible contract is the caller is responsible for ensuring the length fits anyway. Indeed, callers all call EVP_EncodeUpdate in bounded chunks, so upstream's analysis is off. Anyway, in theory that logic could locally overflow, so tweak it slightly. Tidy up some of the variable names while I'm here. Change-Id: Ifa78707cc26c11e0d67019918a028531b3d6738c Reviewed-on: https://boringssl-review.googlesource.com/7847 Reviewed-by: Adam Langley <agl@google.com> commit e31e0123ea331f640852dac55c072b4cec3e3ff8 Author: David Benjamin <davidben@google.com> Date: Tue May 3 07:55:29 2016 -0400 Add size limit to X509_NAME structure. This adds an explicit limit to the size of an X509_NAME structure. Some part of OpenSSL (e.g. TLS) already effectively limit the size due to restrictions on certificate size. See also upstream's 65cb92f4da37a3895437f0c9940ee0bcf9f28c8a, although this is different from upstream's. Upstream's version bounds both the X509_NAME *and* any data after it in the immediately containing structure. While adding a bound on all of crypto/asn1 is almost certainly a good idea (will look into that for a follow-up), it seems bizarre and unnecessary to have X509_NAME affect its parent. Change-Id: Ica2136bcd1455d7c501ccc6ef2a19bc5ed042501 Reviewed-on: https://boringssl-review.googlesource.com/7846 Reviewed-by: Adam Langley <agl@google.com> commit 204dea8daeee9935b2b08da2c2dfe7b890ed36a7 Author: David Benjamin <davidben@google.com> Date: Tue May 3 07:42:19 2016 -0400 Fix encrypt overflow An overflow can occur in the EVP_EncryptUpdate function. If an attacker is able to supply very large amounts of input data after a previous call to EVP_EncryptUpdate with a partial block then a length check can overflow resulting in a heap corruption. Following an analysis of all OpenSSL internal usage of the EVP_EncryptUpdate function all usage is one of two forms. The first form is like this: EVP_EncryptInit() EVP_EncryptUpdate() i.e. where the EVP_EncryptUpdate() call is known to be the first called function after an EVP_EncryptInit(), and therefore that specific call must be safe. The second form is where the length passed to EVP_EncryptUpdate() can be seen from the code to be some small value and therefore there is no possibility of an overflow. [BoringSSL: We also have code that calls EVP_CIPHER functions by way of the TLS/SSL3 "AEADs". However, there we know the inputs are bounded by 2^16.] Since all instances are one of these two forms, I believe that there can be no overflows in internal code due to this problem. It should be noted that EVP_DecryptUpdate() can call EVP_EncryptUpdate() in certain code paths. Also EVP_CipherUpdate() is a synonym for EVP_EncryptUpdate(). Therefore I have checked all instances of these calls too, and came to the same conclusion, i.e. there are no instances in internal usage where an overflow could occur. This could still represent a security issue for end user code that calls this function directly. CVE-2016-2106 Issue reported by Guido Vranken. (Imported from upstream's 3ab937bc440371fbbe74318ce494ba95021f850a.) Change-Id: Iabde896555c39899c7f0f6baf7a163a7b3c2f3d6 Reviewed-on: https://boringssl-review.googlesource.com/7845 Reviewed-by: Adam Langley <agl@google.com> commit a43fd90c5ddd85604f308d1664e8f2cedca28b92 Author: David Benjamin <davidben@google.com> Date: Tue May 3 07:40:09 2016 -0400 Sync with upstream on i2d_X509_AUX. Upstream decided to reset *pp on error and to later fix up the other i2d functions to behave similarly. See upstream's c5e603ee182b40ede7713c6e229c15a8f3fdb58a. Change-Id: I01f82b578464060d0f2be5460fe4c1b969124c8e Reviewed-on: https://boringssl-review.googlesource.com/7844 Reviewed-by: Adam Langley <agl@google.com> commit eb3257211e3bd7dbdbe636144b6838dd20c37ef3 Author: David Benjamin <davidben@google.com> Date: Tue May 3 07:38:54 2016 -0400 Don't free ret->data if malloc fails. Issue reported by Guido Vranken. (Imported from upstream's 64eaf6c928f4066d62aa86f805796ef05bd0b1cc.) Change-Id: I99793abb4e1b5da5b70468b207ec03013fff674a Reviewed-on: https://boringssl-review.googlesource.com/7843 Reviewed-by: Adam Langley <agl@google.com> commit 52a3bf2835200a7beabe349a85cb2355e42ab599 Author: David Benjamin <davidben@google.com> Date: Tue May 3 07:50:44 2016 -0400 Add checks to X509_NAME_oneline() Sanity check field lengths and sums to avoid potential overflows and reject excessively large X509_NAME structures. Issue reported by Guido Vranken. (Imported from upstream's 9b08619cb45e75541809b1154c90e1a00450e537.) Change-Id: Ib2e1e7cd086f9c3f0d689d61947f8ec3e9220049 Reviewed-on: https://boringssl-review.googlesource.com/7842 Reviewed-by: Adam Langley <agl@google.com> commit ddc69230f30ed53bf81e2e6755cb74f02f537b1a Author: David Benjamin <davidben@google.com> Date: Tue May 3 07:35:56 2016 -0400 Sanity check buffer length. Reject zero length buffers passed to X509_NAME_oneline(). Issue reported by Guido Vranken. (Imported from upstream's 66e731ab09f2c652d0e179df3df10d069b407604.) Tweaked slightly to use <= 0 instead of == 0 since the length is signed. Change-Id: I5ee54d77170845e4699fda7df5e94538c8e55ed9 Reviewed-on: https://boringssl-review.googlesource.com/7841 Reviewed-by: Adam Langley <agl@google.com> commit d230a0c8904c4a67ee24ead8951345042bb73979 Author: David Benjamin <davidben@google.com> Date: Tue May 3 07:33:29 2016 -0400 Reject inappropriate private key encryption ciphers. The traditional private key encryption algorithm doesn't function properly if the IV length of the cipher is zero. These ciphers (e.g. ECB mode) are not suitable for private key encryption anyway. (Imported from upstream's 4436299296cc10c6d6611b066b4b73dc0bdae1a6.) Change-Id: I218c9c1d11274ef11b7c0cfce380521efa415215 Reviewed-on: https://boringssl-review.googlesource.com/7840 Reviewed-by: Adam Langley <agl@google.com> commit b83c680d03b302a88fefcddbdce1b753c4c54ca6 Author: Adam Langley <agl@google.com> Date: Tue May 3 09:16:21 2016 -0700 Add |CRYPTO_is_confidential_build|. In the past we have needed the ability to deploy security fixes to our frontend systems without leaking them in source code or in published binaries. This change adds a function that provides some infrastructure for supporting this in BoringSSL while meeting our internal build needs. We do not currently have any specific patch that requires this—this is purely preparation. Change-Id: I5c64839e86db4e5ea7419a38106d8f88b8e5987e Reviewed-on: https://boringssl-review.googlesource.com/7849 Reviewed-by: David Benjamin <davidben@google.com> commit 8368050fa9371840d76ea53ed38c3e5a1cb5e3bc Author: David Benjamin <davidben@google.com> Date: Mon May 2 13:15:52 2016 -0400 Clean up ssl_get_compatible_server_ciphers. The logic is a little hairy, partly because we used to support multiple certificate slots. Change-Id: Iee8503e61f5e0e91b7bcb15f526e9ef7cc7ad860 Reviewed-on: https://boringssl-review.googlesource.com/7823 Reviewed-by: David Benjamin <davidben@google.com> commit 7acd6bc07a25e85d784106fcdfda52809c09699f Author: David Benjamin <davidben@google.com> Date: Mon May 2 12:57:01 2016 -0400 Start assuming MSVC 2015. BUG=43 Change-Id: I46ad1ca62b8921a03fae51f5d7bbe1c68fc0b170 Reviewed-on: https://boringssl-review.googlesource.com/7821 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 8861daa5a9f3ed85500aebcde10278f604e673ac Author: David Benjamin <davidben@google.com> Date: Mon May 2 15:22:34 2016 -0400 Fix vs_toolchain.py, possibly. Sync a few changes with the upstream one, notably get_toolchain_if_necessary.py needs GYP_MSVS_VERSION set. Also pull the variables that change up to the top. This diverges a bit more from the upstream one, but we're already heavily diverged. If we ever need to support two concurrent toolchains, I'll bring us closer to parity. Change-Id: I6db7fbaccd5dddd92ad2deee15bd6dd3e28841f7 Reviewed-on: https://boringssl-review.googlesource.com/7830 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit bbe6af0e2ab5b80de6f9cb8ebe8571a5c4b48dbb Author: David Benjamin <davidben@google.com> Date: Fri Apr 29 14:15:39 2016 -0400 Bump requirements to MSVC 2015. Track the Chromium requirements. This makes our bots build with 2015 instead of 2013. BUG=43 Change-Id: Id5329900a5d1d5fae4b5b22299ed47bc1b947dd8 Reviewed-on: https://boringssl-review.googlesource.com/7820 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 9e7efdb008f98c0e311af37ee7193de4e54dcf75 Author: David Benjamin <davidben@google.com> Date: Mon May 2 13:03:34 2016 -0400 Update the various pinned revisions in util/bot. See util/bot/UPDATING for where they come from. Change-Id: Ib2eae6efc737dd8c4e5fb001fd4b478102e0ad6a Reviewed-on: https://boringssl-review.googlesource.com/7822 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit d18cb77864dcc4b5c7cb08c2331008c01165f34f Author: David Benjamin <davidben@google.com> Date: Fri Apr 29 16:22:40 2016 -0400 Fix d2i_X509_AUX. The logic to reset *pp doesn't actually work if pp is NULL. (It also doesn't work if *pp is NULL, but that didn't work before either.) Don't bother resetting it. This is consistent with the template-based i2d functions which do not appear to leave *pp alone on error. Will send this upstream. Change-Id: I9fb5753e5d36fc1d490535720b8aa6116de69a70 Reviewed-on: https://boringssl-review.googlesource.com/7812 Reviewed-by: Adam Langley <agl@google.com> commit 176dbf04b725b1ee53415fb84720935491c6b989 Author: David Benjamin <davidben@google.com> Date: Thu Apr 28 20:30:03 2016 -0400 Check for malloc failure in r2i_certpol. See upstream's 34b9acbd3f81b46967f692c0af49020c8c405746. Change-Id: I88d5b3cfbbe87e883323a9e6e1bf85227ed9576e Reviewed-on: https://boringssl-review.googlesource.com/7811 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 3bb5a77205b1ea66fd7ad3d103ff15cb752fe0bd Author: David Benjamin <davidben@google.com> Date: Thu Apr 28 20:28:11 2016 -0400 Fix memory leak on error in BN_mpi2bn. See also upstream's 91fb42ddbef7a88640d1a0f853c941c20df07de7, though that has a bug if |out| was non-NULL on entry. (I'll send them a patch.) Change-Id: I807f23007b89063c23e02dac11c4ffb41f847fdf Reviewed-on: https://boringssl-review.googlesource.com/7810 Reviewed-by: David Benjamin <davidben@google.com> commit 6f621bd8f7a4fa348bc2dec62c3b5870d6708fa7 Author: Nick Harper <nharper@chromium.org> Date: Thu Apr 28 12:13:42 2016 -0700 Merge documentation from chromium's net/der into cbs.c Change-Id: Icfd959a168e3fce423b10dd0dcb1312ec03f0623 Reviewed-on: https://boringssl-review.googlesource.com/7800 Reviewed-by: David Benjamin <davidben@google.com> commit 992c20aedc0e5206bfa2b6bc032fbff570c6deb3 Author: David Benjamin <davidben@google.com> Date: Thu Apr 28 12:56:35 2016 -0400 Another OPENSSL_NO_THREADS build fix. GCC gets unhappy if we don't initialize the padding. Change-Id: I084ffee1717d9025dcb10d8f32de0da2339c7f01 Reviewed-on: https://boringssl-review.googlesource.com/7797 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 0a63b96535dff86fc226e3a13e34252e702a45d0 Author: David Benjamin <davidben@google.com> Date: Thu Apr 28 12:17:55 2016 -0400 Make CRYPTO_is_NEON_capable aware of the buggy CPU. If we're to allow the buggy CPU workaround to fire when __ARM_NEON__ is set, CRYPTO_is_NEON_capable also needs to be aware of it. Also add an API to export this value out of BoringSSL, so we can get some metrics on how prevalent this chip is. BUG=chromium:606629 Change-Id: I97d65a47a6130689098b32ce45a8c57c468aa405 Reviewed-on: https://boringssl-review.googlesource.com/7796 Reviewed-by: Adam Langley <agl@google.com> commit b3be1cf97da6c0c796f0ab9aebe7232b030d32b0 Author: David Benjamin <davidben@google.com> Date: Wed Apr 27 19:15:06 2016 -0400 Add a 'configs_exclude' option to the generated GN 'create_tests' template. Chromium uses GN's default configs feature which makes all targets default to a set of configs. It then expects third_party code to take one of them (chromium_code) out and put in a different one (no_chromium_code). Because of that, we need a way to tell the template to emit -= lines. Add a separate option for that. (It may be worth making us clean against the chromium_code config rather than the no_chromium_code one, but I'll explore that separately in case making the C code clean ends up being a rabbithole.) BUG=chromium:607294 Change-Id: I2aa179665ab17439cc123fc86a7af9690cd4bcd6 Reviewed-on: https://boringssl-review.googlesource.com/7795 Reviewed-by: Adam Langley <agl@google.com> commit 2b4820bd523c7ee7406537bfad1bde9bb29673bb Author: David Benjamin <davidben@google.com> Date: Wed Apr 27 18:27:11 2016 -0400 Don't set a default armcap state in dynamic armcap modes. The getauxval (and friends) code would be filling that in anyway. The default only serves to enable NEON even if the OS is old enough to be missing getauxval (and everything else). Notably, this unbreaks the has_buggy_neon code when __ARM_NEON__ is set, as is the case in Chrome for Android, as of M50. Before, the default OPENSSL_armcap_P value was getting in the way. Arguably, this doesn't make a whole lot of sense. We're saying we'll let the CPU run compiler-generated NEON code, but not our hand-crafted stuff. But, so far, we only have evidence of the hand-written NEON tickling the bug and not the compiler-generated stuff, so avoid the unintentional regression. (Naively, I would expect the hand-crafted NEON is better at making full use of the pipeline and is thus more likely to tickle the CPU bug.) This is not the fix for M50, as in the associated Chromium bug, but it will fix master and M51. M50 will instead want to revert https://codereview.chromium.org/1730823002. BUG=chromium:606629 Change-Id: I394f97fea2f09891dd8fa30e0ec6fc6b1adfab7a Reviewed-on: https://boringssl-review.googlesource.com/7794 Reviewed-by: Adam Langley <agl@google.com> commit 9478f321753fcb9b1f495abab4e57aa8f6bfce15 Author: Matt Braithwaite <mab@google.com> Date: Wed Apr 27 11:53:18 2016 -0700 newhope: use less stack to compute client key Change-Id: Idf500545317242c8855e67b897975e54969fea10 Reviewed-on: https://boringssl-review.googlesource.com/7782 Reviewed-by: Adam Langley <agl@google.com> commit 862c0aa8806b226286205a3ce2482840721173d6 Author: David Benjamin <davidben@google.com> Date: Wed Apr 27 14:59:12 2016 -0400 Revert md_len removal from SHA256_CTX and SHA512_CTX. This reverts commits: - 91586371422dae70481c39752e55f01f50e9a93a - a90aa643024459c1698dbec84f4c79a3238b3db8 - c0d8b83b4462a0eb1889f32dbd7f46e83f4dbc81 It turns out code outside of BoringSSL also mismatches Init and Update/Final functions. Since this is largely cosmetic, it's probably not worth the cost to do this. Change-Id: I14e7b299172939f69ced2114be45ccba1dbbb704 Reviewed-on: https://boringssl-review.googlesource.com/7793 Reviewed-by: Adam Langley <agl@google.com> commit 88e27bcbe08210666b1e05c3daa12ff9faed2564 Author: David Benjamin <davidben@google.com> Date: Wed Apr 27 14:51:17 2016 -0400 Don't mismatch Init and Update/Final hash functions. Fixes the ASan bot. Change-Id: I29b9b98680b634c5e486a734afa38f9d4e458518 Reviewed-on: https://boringssl-review.googlesource.com/7792 Reviewed-by: Adam Langley <agl@google.com> commit 91586371422dae70481c39752e55f01f50e9a93a Author: David Benjamin <davidben@google.com> Date: Tue Apr 19 23:56:41 2016 -0400 Make SHA256_Final actually only return one. As with SHA512_Final, use the different APIs rather than store md_len. Change-Id: Ie1150de6fefa96f283d47aa03de0f18de38c93eb Reviewed-on: https://boringssl-review.googlesource.com/7722 Reviewed-by: Adam Langley <agl@google.com> commit a90aa643024459c1698dbec84f4c79a3238b3db8 Author: David Benjamin <davidben@google.com> Date: Tue Apr 19 23:51:11 2016 -0400 Pull HASH_MAKE_STRING out of md32_common.h. This is in preparation for taking md_len out of SHA256_CTX by allowing us to do something similar to SHA512_CTX. md32_common.h now emits a static "finish" function which Final composes with the extraction step. Change-Id: I314fb31e2482af642fd280500cc0e4716aef1ac6 Reviewed-on: https://boringssl-review.googlesource.com/7721 Reviewed-by: Adam Langley <agl@google.com> commit e3118b8dc4c05abc8ed822a181e81a2a070ebe61 Author: David Benjamin <davidben@google.com> Date: Wed Apr 27 14:44:22 2016 -0400 Fix Windows build. Change-Id: Ie35b8d0e2da0f7d2588c4a436fc4b2b2596aaf18 Reviewed-on: https://boringssl-review.googlesource.com/7791 Reviewed-by: David Benjamin <davidben@google.com> commit c0d8b83b4462a0eb1889f32dbd7f46e83f4dbc81 Author: David Benjamin <davidben@google.com> Date: Tue Apr 19 17:39:28 2016 -0400 Make SHA512_Final actually only return one. Rather than store md_len, factor out the common parts of SHA384_Final and SHA512_Final and then extract the right state. Also add a missing SHA384_Transform and be consistent about "1" vs "one" in comments. This also removes the NULL output special-case which no other hash function had. Change-Id: If60008bae7d7d5b123046a46d8fd64139156a7c5 Reviewed-on: https://boringssl-review.googlesource.com/7720 Reviewed-by: Adam Langley <agl@google.com> commit 3baee2a495df5aa212b13c5948da829332b75b24 Author: David Benjamin <davidben@google.com> Date: Fri Apr 1 18:37:07 2016 -0400 Banish SSL_add_dir_cert_subjects_to_stack and OPENSSL_DIR_CTX to decrepit. There was only one function that required BoringSSL to know how to read directories. Unfortunately, it does have some callers and it's not immediately obvious whether the code is unreachable. Rather than worry about that, just toss it all into decrepit. In doing so, do away with the Windows and PNaCl codepaths. Only implement OPENSSL_DIR_CTX on Linux. Change-Id: Ie64d20254f2f632fadc3f248bbf5a8293ab2b451 Reviewed-on: https://boringssl-review.googlesource.com/7661 Reviewed-by: Adam Langley <agl@google.com> commit 724dcbf5e209f118b9e6af82997d144b9c692b19 Author: Adam Langley <agl@google.com> Date: Wed Apr 27 11:08:13 2016 -0700 Correct markdown misinterpretation. The term “#define”, when the line breaking happens to put at the beginning of a line, confuses markdown. This change escapes the '#'. Change-Id: I8300324f9e8c7561f32aba6fa29c0132a188a58b commit a08142380981b366fb4f5eb61f9888f49342d388 Author: Adam Langley <agl@google.com> Date: Wed Apr 27 10:24:11 2016 -0700 Add document about incorporating BoringSSL into a project. Change-Id: Ia825300bae236e3133dd9a19313b7f5450f0c8e2 Reviewed-on: https://boringssl-review.googlesource.com/7781 Reviewed-by: David Benjamin <davidben@google.com> commit a9959f2f5083ed72a80800d7c8f8287122473be6 Author: David Benjamin <davidben@google.com> Date: Tue Apr 26 20:12:52 2016 -0400 Work around Android mingw issues. The copy of mingw-w64 used by Android isn't new enough and is missing half of the INIT_ONCE definitions. (But not the other half, strangely.) Work around this for now. Change-Id: I5c7e89db481f932e03477e50cfb3cbacaeb630e6 Reviewed-on: https://boringssl-review.googlesource.com/7790 Reviewed-by: Adam Langley <agl@google.com> commit 7909aa7c23f04dc5dd471824ea04443d96189618 Author: Adam Langley <agl@google.com> Date: Tue Apr 26 16:31:38 2016 -0700 Pass array by reference in newhope speed test. This is another thing that MSVC can't cope with: ..\tool\speed.cc(537) : error C2536: 'SpeedNewHope::<⋯>::SpeedNewHope::<⋯>::clientmsg' : cannot specify explicit initializer for arrays Change-Id: I6b4cb430895f7794e9cef1b1c12b57ba5d537c64 commit e75f0530a009efac5519053ff6c342ad0da50eea Author: Adam Langley <agl@google.com> Date: Tue Apr 26 16:25:31 2016 -0700 More fixes for MSVC. Change-Id: I2cde4d99974a28126452bb66c6e176b92b7f0bc9 commit bc57d55c9fe88d3c4f41dd204ec25a8dcf606a5e Author: Adam Langley <agl@google.com> Date: Tue Apr 26 16:10:53 2016 -0700 Corrupt the newhope secret key directly. Rather than use an internal function in a test (which would need an OPENSSL_EXPORT to work in a shared-library build), this change corrupts the secret key directly. Change-Id: Iee501910b23a0affaa0639dcc773d6ea2d0c5a82 Reviewed-on: https://boringssl-review.googlesource.com/7780 Reviewed-by: Matt Braithwaite <mab@google.com> Reviewed-by: Adam Langley <agl@google.com> commit 945cf9a131d52069dfec6488f901cef475732584 Author: Matt Braithwaite <mab@google.com> Date: Tue Apr 26 16:03:47 2016 -0700 newhope: MSVC can't size array using static size_t Change-Id: I5060b1a3e800db21d2205f11951b4ad8a5986133 Reviewed-on: https://boringssl-review.googlesource.com/7770 Reviewed-by: Adam Langley <agl@google.com> commit 045a0ffe358b81609e5b93e1f02e948b581304a3 Author: Matt Braithwaite <mab@google.com> Date: Mon Apr 18 11:30:19 2016 -0700 Import `newhope' (post-quantum key exchange). This derives from the reference implementation: Source: https://github.com/tpoeppelmann/newhope/tree/master/ref at bc06c1ac Paper: https://eprint.iacr.org/2015/1092 However, it does not interoperate, due to the replacement of SHAKE-128 with AES-CTR (for polynomial generation) and the replacement of SHA-3 with SHA-256 (for key whitening). Change-Id: I6a55507aea85331245e2fbd41bae5cc049fdca3c Reviewed-on: https://boringssl-review.googlesource.com/7690 Reviewed-by: Adam Langley <agl@google.com> commit c25d2e63795f7af7db5b1ca120f3f158a357f014 Author: David Benjamin <davidben@google.com> Date: Tue Apr 26 18:04:36 2016 -0400 Resolve -Wextern-c-compat warnings with OPENSSL_NO_THREADS. C and C++ disagree on the sizes of empty structs, which can be rather bad for structs embedded in public headers. Stick a char in them to avoid issues. (It doesn't really matter for CRYPTO_STATIC_MUTEX, but it's easier to add a char in there too.) Thanks to Andrew Chi for reporting this issue. Change-Id: Ic54fff710b688decaa94848e9c7e1e73f0c58fd3 Reviewed-on: https://boringssl-review.googlesource.com/7760 Reviewed-by: David Benjamin <davidben@google.com> commit ede2e2c5cec6a4ac40a247f7588fd8ccf625d182 Author: Steven Valdez <svaldez@google.com> Date: Tue Apr 26 12:51:18 2016 -0400 Fix buffer overrun in ASN1_parse() and signed/unsigned warning. (Imported from upstream's 2442382e11c022aaab4fdc6975bd15d5a75c4db2 and 0ca67644ddedfd656d43a6639d89a6236ff64652) Change-Id: I601ef07e39f936e8f3e30412fd90cd339d712dc4 Reviewed-on: https://boringssl-review.googlesource.com/7742 Reviewed-by: David Benjamin <davidben@google.com> commit b32a9151da35c12136299a3bf4e21c8c77d13866 Author: Steven Valdez <svaldez@google.com> Date: Tue Apr 26 12:57:22 2016 -0400 Ensure we check i2d_X509 return val The i2d_X509() function can return a negative value on error. Therefore we should make sure we check it. Issue reported by Yuan Jochen Kang. (Imported from upstream's 8f43c80bfac15544820739bf035df946eeb603e8) Change-Id: If247d5bf1d792eb7c6dc179b606ed21ea0ccdbb8 Reviewed-on: https://boringssl-review.googlesource.com/7743 Reviewed-by: David Benjamin <davidben@google.com> commit 14b07a02a6b16f24e6bd6cbb11f9904e9ee50442 Author: Steven Valdez <svaldez@google.com> Date: Tue Apr 26 12:43:39 2016 -0400 Harden ASN.1 BIO handling of large amounts of data. If the ASN.1 BIO is presented with a large length field read it in chunks of increasing size checking for EOF on each read. This prevents small files allocating excessive amounts of data. CVE-2016-2109 Thanks to Brian Carpenter for reporting this issue. (Imported from upstream's f32774087f7b3db1f789688368d16d917757421e) Change-Id: Id1b0d4436c4879d0ba7d3b7482b937cafffa28f7 Reviewed-on: https://boringssl-review.googlesource.com/7741 Reviewed-by: David Benjamin <davidben@google.com> commit f040d3c7e1a2da2cd1902ef90fd4b6daed061296 Author: David Benjamin <davidben@google.com> Date: Tue Apr 26 11:52:29 2016 -0400 Fix build. Forgot to mark something static. Change-Id: I497075d0ad27e2062f84528fb568b333e72a7d3b Reviewed-on: https://boringssl-review.googlesource.com/7753 Reviewed-by: David Benjamin <davidben@google.com> commit dc9194f78b120fddb6a63daa2ce53d48381b545a Author: David Benjamin <davidben@google.com> Date: Sun Apr 24 12:17:46 2016 -0400 Fix a bug in obj_dat.pl and add basic crypto/obj tests. It's not possible to encode an OID with only one component, so some of the NIDs do not have encodings. The logic to actually encode OIDs checks for this (before calling der_it), but not the logic to compute the sorted OID list. Without this, OBJ_obj2nid, when given an empty OID, returns something arbitrary based on the binary search implementation instead of NID_undef. Change-Id: Ib68bae349f66eff3d193616eb26491b6668d4b0a Reviewed-on: https://boringssl-review.googlesource.com/7752 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit f13444a5ad92974005df38c4344c922af2449ca3 Author: David Benjamin <davidben@google.com> Date: Mon Apr 25 13:22:22 2016 -0400 Use different bit tricks to extend the LSB. C gets grumpy when you shift into a sign bit. Replace it with a different bit trick. BUG=chromium:603502 Change-Id: Ia4cc2e2d68675528b7c0155882ff4d6230df482b Reviewed-on: https://boringssl-review.googlesource.com/7740 Reviewed-by: Adam Langley <agl@google.com> commit 1fc7564ba7dd985f311d5fccd1de4b01ee368b43 Author: David Benjamin <davidben@google.com> Date: Fri Apr 22 00:43:20 2016 -0400 Add standalone PKCS#8 and SPKI fuzzers. We already had coverage for our new EVP_PKEY parsers, but it's good to have some that cover them directly. The initial corpus was generated manually with der-ascii and should cover most of the insanity around EC key serialization. BUG=15 Change-Id: I7aaf56876680bfd5a89f5e365c5052eee03ba862 Reviewed-on: https://boringssl-review.googlesource.com/7728 Reviewed-by: Adam Langley <agl@google.com> commit af18cdd733a05a088518e5adb01704c1980fff3b Author: David Benjamin <davidben@google.com> Date: Sat Apr 23 01:40:03 2016 -0400 Add a copyright header to run_android_tests.go. Change-Id: Ifd60964e4074fa7900e9ebfbb669864bae0821dd Reviewed-on: https://boringssl-review.googlesource.com/7729 Reviewed-by: Adam Langley <agl@google.com> commit 6e96d2be3d86f81abc230309821691c0cf48343c Author: David Benjamin <davidben@google.com> Date: Mon Apr 25 15:07:53 2016 -0400 Remove stale wpa_supplicant hacks. aosp-master has been updated past the point that this is necessary. Sadly, all the other hacks still are. I'll try to get things rolling so we can ditch the others in time. Change-Id: If7b3aad271141fb26108a53972d2d3273f956e8d Reviewed-on: https://boringssl-review.googlesource.com/7751 Reviewed-by: Adam Langley <agl@google.com> commit 1be6a7e4428181e750bf00955df52a8155578ef0 Author: David Benjamin <davidben@google.com> Date: Mon Apr 25 14:41:19 2016 -0400 Add another temporary hack for wpa_supplicant. Due to Android's complex branching scheme, we have to keep building against a snapshotted version of wpa_supplicant. wpa_supplicant, in preparation for OpenSSL 1.1.0, added compatibility versions of some accessors that we, in working towards opaquification, have imported. This causes a conflict (C does not like having static and non-static functions share a name). Add a hack in the headers to suppress the conflicting accessors when BORINGSSL_SUPPRESS_ACCESSORS is defined. Android releases which include an updated BoringSSL will also locally carry this #define in wpa_supplicant build files. Once we can be sure releases of BoringSSL will only see a new enough wpa_supplicant (one which includes a to-be-submitted patch), we can ditch this. Change-Id: I3e27fde86bac1e59077498ee5cbd916cd880821e Reviewed-on: https://boringssl-review.googlesource.com/7750 Reviewed-by: Adam Langley <agl@google.com> commit b70cd92c82b4626b8ea69e22e8044fc486fe17bd Author: Adam Langley <agl@google.com> Date: Mon Apr 25 10:48:19 2016 -0700 Add licenses to fuzz tests. These source files previously didn't have the ISC license on them. Change-Id: Ic0a2047d23b28d9d7f0a85b2fedb67574bdcab25 Reviewed-on: https://boringssl-review.googlesource.com/7735 Reviewed-by: David Benjamin <davidben@google.com> commit 3d907ed964c721a395c82c5733e7d6dd7fcdd1fb Author: Adam Langley <agl@google.com> Date: Fri Apr 22 14:06:50 2016 -0700 Remove RC4_options from rc4-586.pl. The x86-64 version of this assembly doesn't include this function. It's in decrepit/rc4 as a compatibility backfill but that means that 32-bit builds end up with two definitions of this symbol. Change-Id: Ib6da6b91aded8efc679ebbae6d60c96a78f3dc4e Reviewed-on: https://boringssl-review.googlesource.com/7734 Reviewed-by: David Benjamin <davidben@google.com> commit 38d01c6b95df135875c2b2d50448c068e5b090e8 Author: David Benjamin <davidben@google.com> Date: Thu Apr 21 18:47:57 2016 -0400 Improve generate_build_files.py gn support. Split gn and gyp generators apart. Since we're pre-generating files, there's no need to make BoringSSL's build depend on the gypi_to_gn.py script. Also emit the tests and a list of fuzzers so we don't need to manually update BUILD.gn each time. The new gn generator is based on the bazel one since they're fairly similar. BUG=chromium:429246 Change-Id: I5a819a964d6ac6e56e9251bb3fd3de1db08214a4 Reviewed-on: https://boringssl-review.googlesource.com/7726 Reviewed-by: Adam Langley <agl@google.com> commit 818aff01fb41b1e46aed9b9ec3bcfc76ae6cf0dd Author: David Benjamin <davidben@google.com> Date: Thu Apr 21 16:58:49 2016 -0400 Add SSL_SESSION_get_master_key. Opaquifying SSL_SESSION is less important than the other structs, but this will cause less turbulence in wpa_supplicant if we add this API too. Semantics and name taken from OpenSSL 1.1.0 to match. BUG=6 Change-Id: Ic39f58d74640fa19a60aafb434dd2c4cb43cdea9 Reviewed-on: https://boringssl-review.googlesource.com/7725 Reviewed-by: Adam Langley <agl@google.com> commit 7fadfc6135aecb4ae44543bf94950593979c3547 Author: David Benjamin <davidben@google.com> Date: Thu Apr 21 16:28:19 2016 -0400 Move TLS-specific "AEAD" functions to the bottom of aead.h. Probably better to keep it out of the way for someone just trying to figure out how to use the library. Notably, we don't really want people to think they need to use the directioned init function. Change-Id: Icacc2061071581abf46e38eb1d7a52e7b1f8361b Reviewed-on: https://boringssl-review.googlesource.com/7724 Reviewed-by: Adam Langley <agl@google.com> commit 325664eec4f33b8adecdeb6f151d10d2c57689c9 Author: David Benjamin <davidben@google.com> Date: Thu Apr 21 16:07:49 2016 -0400 Add hkdf.h to doc.config. It has all of one function in there. Change-Id: I86f0fbb76d267389c62b63ac01df685acb70535e Reviewed-on: https://boringssl-review.googlesource.com/7723 Reviewed-by: Adam Langley <agl@google.com> commit f01fb5dc0e9d2227a20fe33f7bf76c2160ecf9c9 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 25 14:34:03 2016 -1000 Avoid minor waste in |ec_GFp_nistp256_point_get_affine_coordinates|. Avoid calculating the affine Y coordinate when the caller didn't ask for it, as occurs, for example, in ECDH. For symmetry and clarity, avoid calculating the affine X coordinate in the hypothetical case where the caller only asked for the Y coordinate. Change-Id: I69f5993fa0dfac8b010c38e695b136cefc277fed Reviewed-on: https://boringssl-review.googlesource.com/7590 Reviewed-by: David Benjamin <davidben@google.com> commit 3f3358ac150465fafffaf1c51c2928dd2b2018a9 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 25 14:29:52 2016 -1000 Save one call to |ecp_nistz256_from_mont| in |ecp_nistz256_get_affine|. Change-Id: I38faa5c4e9101c100614ebadf421bde0a05af360 Reviewed-on: https://boringssl-review.googlesource.com/7589 Reviewed-by: David Benjamin <davidben@google.com> commit a7aa2bb8f86f9891bba9d05544e2b9796b2da864 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 25 14:22:40 2016 -1000 Avoid a multiplication in |ecp_nistz256_get_affine| when |x| is NULL. This is purely hypothetical, as in real life nobody cares about the |y| component without also caring about the |x| component, but it clarifies the code and makes a future change clearer. Change-Id: Icaa4de83c87b82a8e68cd2942779a06e5db300c3 Reviewed-on: https://boringssl-review.googlesource.com/7588 Reviewed-by: David Benjamin <davidben@google.com> commit d860b7b1cdefa22b2d42074aa5c8ce2a8ec1da5c Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 25 14:19:42 2016 -1000 Set output coordinates' |neg| field in |ecp_nistz256_get_affine|. The result would not be correct if, on input, |x->neg != 0| or |y->neg != 0|. Change-Id: I645566a78c2e18e42492fbfca1df17baa05240f7 Reviewed-on: https://boringssl-review.googlesource.com/7587 Reviewed-by: David Benjamin <davidben@google.com> commit 97770d17d8dad60295cf0090f498472907ffd738 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 11 14:04:14 2016 -1000 Use only Montgomery math in |ec_GFp_mont_point_get_affine_coordinates|. Use only Montgomery math in |ec_GFp_mont_point_get_affine_coordinates|. In particular, avoid |BN_mod_sqr| and |BN_mod_mul|. Change-Id: I05c8f831d2865d1b105cda3871e9ae67083f8399 Reviewed-on: https://boringssl-review.googlesource.com/7586 Reviewed-by: David Benjamin <davidben@google.com> commit f3835839b1f3f7a922748153ca5aa17132220407 Author: David Benjamin <davidben@google.com> Date: Tue Apr 19 17:48:11 2016 -0400 Use nanosleep instead of usleep. usleep is guarded by feature macro insanity. Use nanosleep which looks to be less unfriendly. Change-Id: I75cb2284f26cdedabb19871610761ec7440b6ad3 Reviewed-on: https://boringssl-review.googlesource.com/7710 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 9dadc3b6e1c2d5e2e8a3b1188c905d5541a75df7 Author: David Benjamin <davidben@google.com> Date: Wed Mar 30 19:04:28 2016 -0400 Replace CRYPTO_once_t on Windows with INIT_ONCE. Now that we no longer support Windows XP, this function is available. In doing so, remove the odd run_once_arg_t union and pass in a pointer to a function pointer which is cleaner and still avoids C's silly rule where function pointers can't be placed in a void*. BUG=37 Change-Id: I44888bb3779dacdb660706debd33888ca389ebd5 Reviewed-on: https://boringssl-review.googlesource.com/7613 Reviewed-by: David Benjamin <davidben@google.com> commit 3ed24f0502ea3f38fa79306dfe263527f0491230 Author: David Benjamin <davidben@google.com> Date: Wed Mar 30 19:03:45 2016 -0400 Test CRYPTO_once_t collisions. The existing tests never actually tested this case. Change-Id: Idb9cf0cbbe32fdf5cd353656a95fbedbaac09376 Reviewed-on: https://boringssl-review.googlesource.com/7612 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 582d2847eda65671883649347f60f6916838a3d1 Author: David Benjamin <davidben@google.com> Date: Sat Apr 16 17:10:01 2016 -0400 Reimplement PKCS#12 key derivation. This is avoids pulling in BIGNUM for doing a straight-forward addition on a block-sized value, and avoids a ton of mallocs. It's also -Wconversion-clean, unlike the old one. In doing so, this replaces the HMAC_MAX_MD_CBLOCK with EVP_MAX_MD_BLOCK_SIZE. By having the maximum block size available, most of the temporary values in the key derivation don't need to be malloc'd. BUG=22 Change-Id: I940a62bba4ea32bf82b1190098f3bf185d4cc7fe Reviewed-on: https://boringssl-review.googlesource.com/7688 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 0e21f41fe884bedf708d3d4d6ab2ce9f53712bb8 Author: David Benjamin <davidben@google.com> Date: Sat Apr 16 15:20:07 2016 -0400 Switch all 'num' parameters in crypto/modes to unsigned. Also switch the EVP_CIPHER copy to cut down on how frequently we need to cast back and forth. BUG=22 Change-Id: I9af1e586ca27793a4ee6193bbb348cf2b28a126e Reviewed-on: https://boringssl-review.googlesource.com/7689 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 1a0a8b6760a9bc21c1c14a07c88fe63d637464ea Author: David Benjamin <davidben@google.com> Date: Sat Apr 16 15:23:54 2016 -0400 Make EVP_MD_CTX size functions return size_t. The EVP_MD versions do, so the types should bubble up. BUG=22 Change-Id: Ibccbc9ff35bbfd3d164fc28bcdd53ed97c0ab338 Reviewed-on: https://boringssl-review.googlesource.com/7687 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 86361a391062e02012c92d1eefa20df3deb897f3 Author: Brian Smith <brian@briansmith.org> Date: Sat Mar 26 19:42:31 2016 -1000 Require the public exponent to be available in RSA blinding. Require the public exponent to be available unless |RSA_FLAG_NO_BLINDING| is set on the key. Also, document this. If the public exponent |e| is not available, then we could compute it from |p|, |q|, and |d|. However, there's no reasonable situation in which we'd have |p| or |q| but not |e|; either we have all the CRT parameters, or we have (e, d, n), or we have only (d, n). The calculation to compute |e| exposes the private key to risk of side channel attacks. Also, it was particularly wasteful to compute |e| for each |BN_BLINDING| created, instead of just once before the first |BN_BLINDING| was created. |BN_BLINDING| now no longer needs to contain a duplicate copy of |e|, so it is now more space-efficient. Note that the condition |b->e != NULL| in |bn_blinding_update| was always true since commit cbf56a5683ddda831ff91c46ea48d1fba545db66. Change-Id: Ic2fd6980e0d359dcd53772a7c31bdd0267e316b4 Reviewed-on: https://boringssl-review.googlesource.com/7594 Reviewed-by: David Benjamin <davidben@google.com> commit d035730ac7ebb82fbf1895fea50c29048bb6edb2 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 25 10:11:04 2016 -1000 Make return value of |BN_MONT_CTX_set_locked| int. This reduces the chance of double-frees. BUG=10 Change-Id: I11a240e2ea5572effeddc05acb94db08c54a2e0b Reviewed-on: https://boringssl-review.googlesource.com/7583 Reviewed-by: David Benjamin <davidben@google.com> commit 51b0d5b1e86590c6e828b11ede90db04916e9ff1 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 25 13:15:39 2016 -1000 Do not use the CRT when |rsa->e == NULL|. When |rsa->e == NULL| we cannot verify the result, so using the CRT would leave the key too vulnerable to fault attacks. Change-Id: I154622cf6205ba4d5fb219143db6072a787c2d1f Reviewed-on: https://boringssl-review.googlesource.com/7581 Reviewed-by: David Benjamin <davidben@google.com> commit 69f0532c8530ef3b26a63f6fbf819bb006c13222 Author: Brian Smith <brian@briansmith.org> Date: Tue Mar 15 12:44:36 2016 -1000 Use |memcmp| instead of |CRYPTO_memcmp| in |RSA_verify|. |CRYPTO_memcmp| isn't necessary because there is no secret data being acted on here. Change-Id: Ib678d5d4fc16958aca409a93df139bdff8cb73fb Reviewed-on: https://boringssl-review.googlesource.com/7465 Reviewed-by: David Benjamin <davidben@google.com> commit 2a92031bb4dceef47b8ee49a9184d7e572fb841b Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 4 13:42:47 2016 -1000 Clarify |RSA_verify_raw| error handling & cleanup. Use the common pattern of returning early instead of |goto err;| when there's no cleanup to do yet. Also, move the error checking of |BN_CTX_get| failure closer to the the calls to |BN_CTX_get|. Avoid calling |OPENSSL_cleanse| on public data. Clarify when/why |buf| is not freed. Change-Id: I9df833db7eb7041c5af9349c461297372b988f98 Reviewed-on: https://boringssl-review.googlesource.com/7464 Reviewed-by: David Benjamin <davidben@google.com> commit 9902262af6fa38acd9bf4e55f2a6d3389faba7e8 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 4 09:20:07 2016 -1000 Remove redundant check of |sig_len| in |RSA_verify|. The same check is already done in |RSA_verify_raw|, so |RSA_verify| doesn't need to do it. Also, move the |RSA_verify_raw| check earlier. Change-Id: I15f7db0aad386c0f764bba53e77dfc46574f7635 Reviewed-on: https://boringssl-review.googlesource.com/7463 Reviewed-by: David Benjamin <davidben@google.com> commit c0b196d4ebc75c9f9cb61411b8fe291e70059d58 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 4 08:54:07 2016 -1000 Drop support for engines-provided signature verification. We do not need to support engine-provided verification methods. Change-Id: Iaad8369d403082b728c831167cc386fdcabfb067 Reviewed-on: https://boringssl-review.googlesource.com/7311 Reviewed-by: David Benjamin <davidben@google.com> commit 9b611e28e42761527c700506194a33b1dd1b90db Author: David Benjamin <davidben@google.com> Date: Thu Mar 3 08:48:30 2016 -0500 Simplify server_name extension parsing. Although the server_name extension was intended to be extensible to new name types, OpenSSL 1.0.x had a bug which meant different name types will cause an error. Further, RFC 4366 originally defined syntax inextensibly. RFC 6066 corrected this mistake, but adding new name types is no longer feasible. Act as if the extensibility does not exist to simplify parsing. This also aligns with OpenSSL 1.1.x's behavior. See upstream's 062178678f5374b09f00d70796f6e692e8775aca and https://www.ietf.org/mail-archive/web/tls/current/msg19425.html Change-Id: I5af26516e8f777ddc1dab5581ff552daf2ea59b5 Reviewed-on: https://boringssl-review.googlesource.com/7294 Reviewed-by: David Benjamin <davidben@google.com> commit 4c5ddb80477738d8063d3b65038b5879b20f8e84 Author: David Benjamin <davidben@google.com> Date: Fri Mar 11 22:56:19 2016 -0500 Set rwstate consistently. We reset it to SSL_NOTHING at the start of ever SSL_get_error-using operation. Then we only set it to a non-NOTHING value in the rest of the stack on error paths. Currently, ssl->rwstate is set all over the place. Sometimes the pattern is: ssl->rwstate = SSL_WRITING; if (BIO_write(...) <= 0) { goto err; } ssl->rwstate = SSL_NOTHING; Sometimes we only set it to the non-NOTHING value on error. if (BIO_write(...) <= 0) { ssl->rwstate = SSL_WRITING; } ssl->rwstate = SSL_NOTHING; Sometimes we just set it to SSL_NOTHING far from any callback in random places. The third case is arbitrary and clearly should be removed. But, in the second case, we sometimes forget to undo it afterwards. This is largely harmless since an error in the error queue overrides rwstate, but we don't always put something in the error queue (falling back to SSL_ERROR_SYSCALL for "I'm not sure why it failed. Perhaps it was one of your callbacks? Check your errno equivalent."), but in that case a stray rwstate value will cause it to be wrong. We could fix the cases where we fail to set SSL_NOTHING on success cases, but this doesn't account for there being multiple SSL_get_error operations. The consumer may have an SSL_read and an SSL_write running concurrently. Instead, it seems the best option is to lift the SSL_NOTHING reset to the operations and set SSL_WRITING and friends as in the second case. (Someday hopefully we can fix this to just be an enum that is internally returned. It can convert to something stateful at the API layer.) Change-Id: I54665ec066a64eb0e48a06e2fcd0d2681a42df7f Reviewed-on: https://boringssl-review.googlesource.com/7453 Reviewed-by: David Benjamin <davidben@google.com> commit c6972eb1f090adc26046859ce3424221de8e210e Author: David Benjamin <davidben@google.com> Date: Fri Mar 11 22:43:53 2016 -0500 Remove the no_renegotiation special case. The concern is if the peer denies our renegotiation attempt, but we will never initiate renegotiation. We only support server-initiated renegotiation when we are acting as the client. (Strictly speaking, only the client ever initiates renegotiation. The server sends a HelloRequest to ask the client to initiate it. But we forbid application data interleave as soon as we see the HelloRequest, so we treat it as part of the handshake.) Change-Id: I1a625130de32a7227e4471f2f889255aba962ce4 Reviewed-on: https://boringssl-review.googlesource.com/7452 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 0d3a8c6ac0f83bd38221bfbb4d83c3c315b5c4ce Author: David Benjamin <davidben@google.com> Date: Fri Mar 11 22:25:18 2016 -0500 Don't allow alert records with multiple alerts. This is just kind of a silly thing to do. NSS doesn't allow them either. Fatal alerts would kill the connection regardless and warning alerts are useless. We previously stopped accepting fragmented alerts but still allowed them doubled up. This is in preparation for pulling the shared alert processing code between TLS and DTLS out of read_bytes into some common place. Change-Id: Idbef04e39ad135f9601f5686d41f54531981e0cf Reviewed-on: https://boringssl-review.googlesource.com/7451 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 56703d91bf18f66867ed7f3fc8ed06fbf13fb18a Author: David Benjamin <davidben@google.com> Date: Mon Apr 18 15:39:33 2016 -0400 Make err_data_generator.go silent by default. I don't think I ever look at that output. This way our builds are nice and silent. Change-Id: Idb215e3702f530a8b8661622c726093530885c91 Reviewed-on: https://boringssl-review.googlesource.com/7700 Reviewed-by: Adam Langley <agl@google.com> commit 26993ad55eda0763990fdd11db929043761b56e1 Author: David Benjamin <davidben@google.com> Date: Fri Apr 15 16:12:19 2016 -0400 Only use recv/send for socket BIOs on Windows. In OpenSSL, socket BIOs only used recv/send on Windows and read/write on POSIX. Align our socket BIOs with that behavior. This should be a no-op, but avoids frustrating consumers overly sensitive to the syscalls used now that SSL_set_fd has switched to socket BIOs to align with OpenSSL. b/28138582. Change-Id: Id4870ef8e668e587d6ef51c5b5f21e03af66a288 Reviewed-on: https://boringssl-review.googlesource.com/7686 Reviewed-by: Adam Langley <agl@google.com> commit 919610b4c43ab394977eba70ceec66aaa0070472 Author: David Benjamin <davidben@google.com> Date: Fri Apr 15 15:34:30 2016 -0400 Fix memory leak on invalid ecPublicKey parameters. One of the codepaths didn't free the group. Found by libFuzzer. BUG=chromium:603893 Change-Id: Icb81f2f89a8c1a52e29069321498986b193a0e56 Reviewed-on: https://boringssl-review.googlesource.com/7685 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: Adam Langley <agl@google.com> commit 4365c3f522f2fc57fa0c87bde5f25ea98dd9a59c Author: Daniel Bathgate <dbathgate@google.com> Date: Thu Apr 14 17:18:02 2016 -0400 Send an error rather than assert when decrypt_len != rsa_size. With SSL_PRIVATE_KEY_METHOD, decryption can happen outside of BoringSSL. Rather than crash the process, it would be nicer if BoringSSL handled the error gracefully. Change-Id: I3f24d066f7a329d41420b208a7e13c82ec966710 Reviewed-on: https://boringssl-review.googlesource.com/7683 Reviewed-by: David Benjamin <davidben@google.com> commit 0fe4d8bef5918f84a7f260c34c26dd13c0d70ade Author: David Benjamin <davidben@google.com> Date: Wed Apr 13 17:28:35 2016 -0400 chacha/asm/chacha-armv8.pl: fix intermittent build failures. (Imported from b9077d85b0042d3d5d877d5cf7f06a8a8c035673.) Change-Id: I6df3b3d0913b001712a78671c69b9468e059047f Reviewed-on: https://boringssl-review.googlesource.com/7682 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 9980ce1dcd1a90990e7e922979ef4445032aa383 Author: Steven Valdez <svaldez@google.com> Date: Thu Apr 14 16:35:26 2016 -0400 Add BORINGSSL_PREFIX for prefixing symbols This currently doesn't prefix assembly symbols since they don't pull in openssl/base.h BUG=5 Change-Id: Ie0fdc79ae73099f84ecbf3f17604a1e615569b3b Reviewed-on: https://boringssl-review.googlesource.com/7681 Reviewed-by: David Benjamin <davidben@google.com> commit a82e8dd9d28705eef77e47762f06626c9134dd6a Author: David Benjamin <davidben@google.com> Date: Thu Apr 14 09:48:39 2016 -0400 Tweak X25519 documentation. Both the header-level and section-level documentation define curve25519 which is a little odd. Change-Id: I81aa2b74e8028d3cfd5635e1d3cfda402ba1ae38 Reviewed-on: https://boringssl-review.googlesource.com/7680 Reviewed-by: Adam Langley <agl@google.com> commit aaccbfec04a09d6711e0ead04e5bef612b8fa65e Author: Adam Langley <agl@google.com> Date: Wed Apr 13 08:19:03 2016 -0700 Export RSA_padding_add_PKCS1_OAEP[_mgf1] This is needed by trousers. As with the PSS function, the version that assumes SHA-1 is put into decrepit. Change-Id: I153e8ea0150e48061b978384b600a7b990d21d03 Reviewed-on: https://boringssl-review.googlesource.com/7670 Reviewed-by: David Benjamin <davidben@google.com> commit 188487faadcda73e80ce84a3e113d2c9de9bbb3b Author: Max Moroz <mmoroz@google.com> Date: Mon Apr 11 15:36:49 2016 +0200 Remove .options files for libFuzzers and update FUZZING.md documentation. Due to https://codereview.chromium.org/1867833002/ replacing .options files. Change-Id: I17f0d5b8b1784fdcf163791e72f6b58b29657e95 Reviewed-on: https://boringssl-review.googlesource.com/7640 Reviewed-by: David Benjamin <davidben@google.com> commit e4c678adda26367e1195cf1aca2af66cb7c3d650 Author: David Benjamin <davidben@google.com> Date: Mon Apr 11 18:04:18 2016 -0400 Revert "Banish SSL_add_dir_cert_subjects_to_stack and OPENSSL_DIR_CTX to decrepit." This reverts commit 112c4dd1ff895bf5af0d64488234b0fc40b616bc. Accidentally used the wrong push line. commit 112c4dd1ff895bf5af0d64488234b0fc40b616bc Author: David Benjamin <davidben@google.com> Date: Fri Apr 1 18:37:07 2016 -0400 Banish SSL_add_dir_cert_subjects_to_stack and OPENSSL_DIR_CTX to decrepit. There was only one function that required BoringSSL to know how to read directories. Unfortunately, it does have some callers and it's not immediately obvious whether the code is unreachable. Rather than worry about that, just toss it all into decrepit. In doing so, do away with the Windows and PNaCl codepaths. Only implement OPENSSL_DIR_CTX on Linux. Change-Id: I3eb55b098e3aa042b422bb7da115c0812685553e commit 2a187a43169ec4855f549972e01b7b34d704be41 Author: David Benjamin <davidben@google.com> Date: Mon Apr 11 17:26:50 2016 -0400 No-op change to test bugdroid. Making sure the BUG= line works correctly. BUG=41 Change-Id: Icedf5f1ec8211696c74d9e9f9d322483c43444fc commit 14420e91e0d6b5e2b5d2c39b2315151ae5837fb1 Author: David Benjamin <davidben@google.com> Date: Mon Apr 11 13:25:37 2016 -0400 Remove EVP_aead_chacha20_poly1305_rfc7539 alias. This slipped through, but all the callers are now using EVP_aead_chacha20_poly1305, so we can remove this version. Change-Id: I76eb3a4481aae4d18487ca96ebe3776e60d6abe8 Reviewed-on: https://boringssl-review.googlesource.com/7650 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit a13ad73cee6e7c490e91daba6971e45ea42ac8dd Author: Piotr Sikora <piotrsikora@google.com> Date: Fri Apr 8 17:23:10 2016 -0700 Use UINT64_C instead of unsigned long long integer constant. Change-Id: Id181957956ccaacc6c29b641a1f1144886d442c0 Signed-off-by: Piotr Sikora <piotrsikora@google.com> Reviewed-on: https://boringssl-review.googlesource.com/7630 Reviewed-by: David Benjamin <davidben@google.com> commit dcb3383463fa2c70bbafefff53004f6896dbc504 Author: Gabriel Redner <gredner@google.com> Date: Wed Apr 6 15:47:28 2016 -0400 Modify 'bssl client' to print the cert subject and issuer This is the one piece of functionality I miss from the openssl tool - the ability to see some basic information about the server cert. Sample output: ========== $ bssl client -connect www.google.com Connecting to [2607:f8b0:4006:80d::1010]:443 Connected. Version: TLSv1.2 Resumed session: no Cipher: ECDHE-RSA-AES128-GCM-SHA256 ECDHE curve: P-256 Secure renegotiation: yes Next protocol negotiated: ALPN protocol: Cert subject: /C=US/ST=California/L=Mountain View/O=Google Inc/CN=www.google.com Cert issuer: /C=US/O=Google Inc/CN=Google Internet Authority G2 ========== Change-Id: I758682784752a616628138e420f52586d5a1bb31 Reviewed-on: https://boringssl-review.googlesource.com/7620 Reviewed-by: David Benjamin <davidben@google.com> commit d44a9431112d37430b3a686bbf4fb6211be69848 Author: David Benjamin <davidben@google.com> Date: Thu Mar 31 18:15:27 2016 -0400 Fix docs typo. Change-Id: Idb786ee2ca6354dcf2f665e9229aef4a43e05dd4 Reviewed-on: https://boringssl-review.googlesource.com/7614 Reviewed-by: David Benjamin <davidben@google.com> commit 046b27815ec4804695f8eed093d4fe5b4589aabc Author: David Benjamin <davidben@google.com> Date: Fri Mar 25 18:07:16 2016 -0400 Decouple crypto/evp from the OID table. BUG=chromium:499653 Change-Id: I4e8d4af3129dbf61d4a8846ec9db685e83999d5e Reviewed-on: https://boringssl-review.googlesource.com/7565 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 0d76c402b81507e13ac628ee04990b1c5ce892e8 Author: David Benjamin <davidben@google.com> Date: Fri Mar 25 18:07:15 2016 -0400 Decouple crypto/ec from the OID table. Instead, embed the (very short) encoding of the OID into built_in_curve. BUG=chromium:499653 Change-Id: I0db36f83c71fbd3321831f54fa5022f8304b30cd Reviewed-on: https://boringssl-review.googlesource.com/7564 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 981936791eb76c52daedb18310fced187252ed30 Author: David Benjamin <davidben@google.com> Date: Fri Mar 25 18:07:11 2016 -0400 Remove some easy obj.h dependencies. A lot of consumers of obj.h only want the NID values. Others didn't need it at all. This also removes some OBJ_nid2sn and OBJ_nid2ln calls in EVP error paths which isn't worth pulling a large table in for. BUG=chromium:499653 Change-Id: Id6dff578f993012e35b740a13b8e4f9c2edc0744 Reviewed-on: https://boringssl-review.googlesource.com/7563 Reviewed-by: David Benjamin <davidben@google.com> commit 5d38f78e2987be876e3023808b4eed57c84ce23c Author: David Benjamin <davidben@google.com> Date: Fri Mar 25 18:07:08 2016 -0400 Rename obj_mac.h to nid.h and make it a multiply-includable header. obj_mac.h is missing #include guards, so one cannot use NIDs without pulling in the OBJ_* functions which depend on the giant OID table. Give it #include guards, tidy up the style slightly, and also rename it to nid.h which is a much more reasonable name. obj_mac.h is kept as a forwarding header as, despite it being a little screwy, some code #includes it anyway. BUG=chromium:499653 Change-Id: Iec0b3f186c02e208ff1f7437bf27ee3a5ad004b7 Reviewed-on: https://boringssl-review.googlesource.com/7562 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 66ec5c90667a32030d64af6d3da426924fbc732a Author: David Benjamin <davidben@google.com> Date: Wed Mar 30 14:26:46 2016 -0400 Also re-serialize X509 objects in fuzz/cert.cc. This is a fairly common operation on an X509. Change-Id: I1820f20b555f75c98ab7e3283b5530bc1c200e2a Reviewed-on: https://boringssl-review.googlesource.com/7611 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 20568e7a4f028782fb76df5407ca9ceaf16de59e Author: David Benjamin <davidben@google.com> Date: Wed Mar 30 14:23:31 2016 -0400 Remove inaccurate comments in fuzz/{client,server}.cc. They now fuzz a lot more than just the initial flow. Change-Id: Ib0b7eb66969442e539a937d7d87f5ba031fcbef3 Reviewed-on: https://boringssl-review.googlesource.com/7610 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 9e5eb63d011cbc6730b4fbc05c4dd3ae6021e97f Author: David Benjamin <davidben@google.com> Date: Sat Mar 26 00:58:38 2016 -0400 Document that CRYPTO_library_init may be called concurrently. This was fixed in 93a5b442964d9770b5faa0fb381a8c4f43e65abe, but it wasn't documented. Now that there are no pre-init functions to call like CRYPTO_set_neon_capable, one instance of BoringSSL may be safely shared between multiple consumers. As part of that, multiple consumers need to be able to call CRYPTO_library_init possibly redundantlyand possibly on different threads without synchronization. (Though there is still that static initializer nuisance. It would be nice to replace this with internal CRYPTO_once_t's and then CRYPTO_library_init need only be called to prime armcap for a sandbox. But one thing at a time.) Change-Id: I48430182d3649c8cf19082e34da24dee48e6119e Reviewed-on: https://boringssl-review.googlesource.com/7571 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit d879e299366895d7d80d83cfbbe05bc6a09e2a27 Author: Brian Smith <brian@briansmith.org> Date: Tue Mar 22 17:30:42 2016 -1000 Further optimize Montgomery math in RSA blinding. Change-Id: I830c6115ce2515a7b9d1dcb153c4cd8928fb978f Reviewed-on: https://boringssl-review.googlesource.com/7591 Reviewed-by: David Benjamin <davidben@google.com> commit bfefc27c2bb4af62e09569e36b018d60da98a680 Author: David Benjamin <davidben@google.com> Date: Tue Mar 29 19:00:33 2016 -0400 Avoid doing arithmetic on void pointers. Whatever compiler settings AOSP is using warns that this is a GNU extension. Change-Id: Ife395d2b206b607b14c713cbb5a94d479816dad0 Reviewed-on: https://boringssl-review.googlesource.com/7604 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 4b7b048417d8ff92c993da9dbb3d9df20455fc1d Author: David Benjamin <davidben@google.com> Date: Wed Mar 30 00:42:17 2016 -0400 Spell __attribute__((format(printf, ...))) with more underscores. They may be spelled with or without underscores. Alas, a lot of C code (adb, cURL) seems to find it a popular pasttime to #define printf *before* including external headers. This is completely nonsense and invalid, but working around it is easy and is what we (and OpenSSL) were doing before 061332f21643a910941c32cbfc40e577c380e342. I'll be sending a patch to cURL tomorrow to make them at least do their macro trickery after external #includes for sanity. adb's sysdeps.h is a lot longer and consistently #included first so I'll probably leave that be for lack of time. Change-Id: I03a0a253f2c902eb45f45faace1e5c5df4335ebf Reviewed-on: https://boringssl-review.googlesource.com/7605 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit aa0bea7bc1927b737f46c41ceb1f1508c9a3ff11 Author: David Benjamin <davidben@google.com> Date: Fri Mar 25 13:27:30 2016 -0400 Add additional poly1305 tests. Thanks to Hanno Boeck for reporting them in https://rt.openssl.org/Ticket/Display.html?id=4483 Change-Id: Ic902c0ceea32c76cad924a1ffc462d39ae6ca3de Reviewed-on: https://boringssl-review.googlesource.com/7603 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 3c4a5cbb71453c5d61314a3f76a5ca6f123dbf94 Author: David Benjamin <davidben@google.com> Date: Tue Mar 29 17:43:31 2016 -0400 Revert "Enable upstream's Poly1305 code." This reverts commit 6f0c4db90e47437ed87a2d385c7797e692a2cf65 except for the imported assembly files, which are left as-is but unused. Until upstream fixes https://rt.openssl.org/Ticket/Display.html?id=4483, we shouldn't ship this code. Once that bug has been fixed, we'll restore it. Change-Id: I74aea18ce31a4b79657d04f8589c18d6b17f1578 Reviewed-on: https://boringssl-review.googlesource.com/7602 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit f08c1c68957024ced93d35d757daeb373de8f073 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 25 13:24:46 2016 -1000 Drop support for custom |mod_exp| hooks in |RSA_METHOD|. The documentation in |RSA_METHOD| says that the |ctx| parameter to |mod_exp| can be NULL, however the default implementation doesn't handle that case. That wouldn't matter since internally it is always called with a non-NULL |ctx| and it is static, but an external application could get a pointer to |mod_exp| by extracting it from the default |RSA_METHOD|. That's unlikely, but making that impossible reduces the chances that future refactorings will cause unexpected trouble. Change-Id: Ie0e35e9f107551a16b49c1eb91d0d3386604e594 Reviewed-on: https://boringssl-review.googlesource.com/7580 Reviewed-by: David Benjamin <davidben@google.com> commit 3426d1011946b26ff1bb2fd98a081ba4753c9cc8 Author: Brian Smith <brian@briansmith.org> Date: Thu Mar 17 16:10:04 2016 -1000 Convert RSA blinding to use Montgomery multiplication. |BN_mod_mul_montgomery| has better constant-time behavior (usually) than |BN_mod_mul| and |BN_mod_sqr| and on platforms where we have assembly language optimizations (when |OPENSSL_BN_ASM_MONT| is set in crypto/bn/montgomery.c) it is faster. While doing so, reorder and rename the |BN_MONT_CTX| parameters of the blinding functions to match the order normally used in Montgomery math functions. As a bonus, remove a redundant copy of the RSA public modulus from the |BN_BLINDING| structure, which reduces memory usage. Change-Id: I70597e40246429c7964947a1dc46d0d81c7530ef Reviewed-on: https://boringssl-review.googlesource.com/7524 Reviewed-by: David Benjamin <davidben@google.com> commit feaa57d13daa0b5bf3c068ce18d24870d50bfae9 Author: David Benjamin <davidben@google.com> Date: Tue Mar 29 14:17:27 2016 -0400 Only call thread-local destructors on DLL_THREAD_DETACH. In VS2015's debug runtime, the C runtime has been unloaded by the time DLL_PROCESS_DETACH is called and things crash. Instead, don't run destructors at that point. This means we do *not* free memory associated with any remaining thread-locals on application shutdown, only shutdown of individual threads. This is actually desirable since it's consistent with pthreads. If an individual thread calls pthread_exit, destructors are run. If the entire process exits, they are not. (It's also consistent with thread_none.c which never bothers to free anything.) BUG=chromium:595795 Change-Id: I3e64d46ea03158fefff583c1e3e12dfa0c0e172d Reviewed-on: https://boringssl-review.googlesource.com/7601 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 1e4ae00ac2beb893aa59b9a98eb70908332904ba Author: David Benjamin <davidben@google.com> Date: Fri Mar 25 18:56:10 2016 -0400 Add a comment about final empty extension intolerance. We reordered extensions some time ago to ensure a non-empty extension was last, but the comment was since lost (or I forgot to put one in in the first place). Add one now so we don't regress. Change-Id: I2f6e2c3777912eb2c522a54bbbee579ee37ee58a Reviewed-on: https://boringssl-review.googlesource.com/7570 Reviewed-by: David Benjamin <davidben@google.com> commit 44477c03b96d2ca8f25111ef25e71e6405ee4f22 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 25 18:12:13 2016 -1000 Fix |BN_CTX_get| error checking in |BN_from_montgomery|. In the case |BN_CTX_get| failed, the function returned without calling |BN_CTX_end|. Fix that. Change-Id: Ia24cba3256e2cec106b539324e9679d690048780 Reviewed-on: https://boringssl-review.googlesource.com/7592 Reviewed-by: David Benjamin <davidben@google.com> commit 9d354693ff3365f2fb0a7848dc19c6a06db0cb4f Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 25 23:09:26 2016 -1000 Small tweak to P-256-x86-64 inversion. Change-Id: I2a55db93e6140a0adc741b4ee5ee090d524605e0 Reviewed-on: https://boringssl-review.googlesource.com/7593 Reviewed-by: David Benjamin <davidben@google.com> commit 040ff622dcf2e7cea2bc1f8d16f6e7a22500f758 Author: David Benjamin <davidben@google.com> Date: Mon Mar 28 13:54:48 2016 -0400 Remove duplicate BN_from_montgomery_word implementation. It looks like we started reformatting that function and adding curly braces, etc., but forget to finish it. This is corroborated by the diff. Although git thinks I removed the EAY-style one and tweaked the #if-0'd one, I actually clang-formatted the EAY-style one anew and deleted the #if-0'd one after tweaking the style to match. Only difference is the alignment stuff is uintptr_t rather than intptr_t since the old logic was using unsigned arithmetic. Change-Id: Ia244e4082a6b6aed3ef587d392d171382c32db33 Reviewed-on: https://boringssl-review.googlesource.com/7574 Reviewed-by: David Benjamin <davidben@google.com> commit 95cc3bea3b4817698ab0f62a29c906e7c85b8796 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 11 13:19:14 2016 -1000 Remove dead code from |ec_GFp_mont_point_get_affine_coordinates|. This code is only used in ec_montgomery.c, so |field_encode| and |field_decode| are never NULL. Change-Id: I42a3ad5744d4ed6f0be1707494411e7efcf930ff Reviewed-on: https://boringssl-review.googlesource.com/7585 Reviewed-by: David Benjamin <davidben@google.com> commit a00f8454341f9d089da96e8cd3960d926e8c6599 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 11 13:12:11 2016 -1000 Move & rename |ec_GFp_simple_point_get_affine_coordinates|. It is only used in ec_montgomery.c, so move it there. Change-Id: Ib189d5579d6363bdc1da89b775ad3df824129758 Reviewed-on: https://boringssl-review.googlesource.com/7584 Reviewed-by: David Benjamin <davidben@google.com> commit b7c5e84847f6b92aee8d5825cd46d316db318a00 Author: David Benjamin <davidben@google.com> Date: Mon Mar 28 09:59:10 2016 -0400 Fix some malloc test failures. These only affect the tests. Change-Id: If22d047dc98023501c771787b485276ece92d4a2 Reviewed-on: https://boringssl-review.googlesource.com/7573 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit e29ea166a6ec44bbfce81d1c93f064b9aca0f443 Author: David Benjamin <davidben@google.com> Date: Wed Mar 23 16:10:44 2016 -0400 Use ssl3_is_version_enabled to skip offering sessions. We do an ad-hoc upper-bound check, but if the version is too low, we also shouldn't offer the session. This isn't fatal to the connection and doesn't have issues (we'll check the version later regardless), but offering a session we're never going to accept is pointless. The check should match what we do in ServerHello. Credit to Matt Caswell for noticing the equivalent issue in an OpenSSL pull request. Change-Id: I17a4efd37afa63b34fca53f4c9b7ac3ae2fa3336 Reviewed-on: https://boringssl-review.googlesource.com/7543 Reviewed-by: David Benjamin <davidben@google.com> commit 762e1d039c1d85e4651700eed82801878a9a86bc Author: David Benjamin <davidben@google.com> Date: Thu Mar 24 20:40:22 2016 -0400 Import chacha-x86.pl fix. Patch from https://mta.openssl.org/pipermail/openssl-dev/2016-March/005625.html. Upstream has yet to make a decision on aliasing requirements for their assembly. If they choose to go with the stricter aliasing requirement rather than land this patch, we'll probably want to tweak EVP_AEAD's API guarantees accordingly and then undiverge. In the meantime, import this to avoid a regression on x86 from when we had compiler-vectorized code on GCC platforms. Per our assembly coverage tools and pending multi-CPU-variant tests, we have good coverage here. Unlike Poly1305 (which is currently waiting on yet another upstream bugfix), where there is risk of missed carries everywhere, it is much more difficult to accidentally make a ChaCha20 implementation that fails based on the data passed into it. This restores a sizeable speed improvement on x86. Before: Did 1131000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000205us (1130768.2 ops/sec): 18.1 MB/s Did 161000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1006136us (160018.1 ops/sec): 216.0 MB/s Did 28000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1023264us (27363.4 ops/sec): 224.2 MB/s Did 1166000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000447us (1165479.0 ops/sec): 18.6 MB/s Did 160000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1004818us (159232.8 ops/sec): 215.0 MB/s Did 30000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1016977us (29499.2 ops/sec): 241.7 MB/s After: Did 2208000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000031us (2207931.6 ops/sec): 35.3 MB/s Did 402000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1001717us (401310.9 ops/sec): 541.8 MB/s Did 97000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1005394us (96479.6 ops/sec): 790.4 MB/s Did 2444000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000089us (2443782.5 ops/sec): 39.1 MB/s Did 459000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1000563us (458741.7 ops/sec): 619.3 MB/s Did 97000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1007942us (96235.7 ops/sec): 788.4 MB/s Change-Id: I976da606dae062a776e0cc01229ec03a074035d1 Reviewed-on: https://boringssl-review.googlesource.com/7561 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 17d729e61b9193c16f45c344d96b8c3537a5aada Author: David Benjamin <davidben@google.com> Date: Fri Mar 25 18:07:18 2016 -0400 Remove unnecessary include. Change-Id: I24d0179ca5019e82ca1494c8773f373f8c09ce82 Reviewed-on: https://boringssl-review.googlesource.com/7566 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 2aca226412fd3b5f1bd0bb3daddfe6c89f0d05f0 Author: David Benjamin <davidben@google.com> Date: Sun Mar 27 10:34:01 2016 -0400 Fix typo in comment. Change-Id: I0effe99d244c4ccdbb0e34db6e01a59c9463cb15 Reviewed-on: https://boringssl-review.googlesource.com/7572 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit baca950e8e1de1399849d54a827b89fc24c1da14 Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 01:29:44 2016 -0500 Remove in_handshake. The removes the last of OpenSSL's variables that count occurrences of a function on the stack. Change-Id: I1722c6d47bedb47b1613c4a5da01375b5c4cc220 Reviewed-on: https://boringssl-review.googlesource.com/7450 Reviewed-by: David Benjamin <davidben@google.com> commit c79845c2a8c52c31ccf6ba2fa2a48f1814568fff Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 01:28:00 2016 -0500 Move implicit handshake driving out of read_bytes. This removes the final use of in_handshake. Note that there is still a rentrant call of read_bytes -> handshake_func when we see a HelloRequest. That will need to be signaled up to ssl_read_impl separately out of read_app_data. Change-Id: I823de243f75e6b73eb40c6cf44157b4fc21eb8fb Reviewed-on: https://boringssl-review.googlesource.com/7439 Reviewed-by: David Benjamin <davidben@google.com> commit b2a73188584b6555656c539137052420257c054f Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 01:25:26 2016 -0500 Switch some 0s to NULLs. Change-Id: Id89c982f8f524720f189b528c987c9e58ca06ddf Reviewed-on: https://boringssl-review.googlesource.com/7438 Reviewed-by: David Benjamin <davidben@google.com> commit d7ac1438140d3bb05376d57b0b5d73e53fa11cdc Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 00:41:25 2016 -0500 Lift the handshake driving in write_bytes up to SSL_write. This removes one use of in_handshake and consolidates some DTLS and TLS code. Change-Id: Ibbdd38360a983dabfb7b18c7bd59cb5e316b2adb Reviewed-on: https://boringssl-review.googlesource.com/7435 Reviewed-by: David Benjamin <davidben@google.com> commit 282511d7eb7ef506c68d21be483f888cac913bb9 Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 00:23:55 2016 -0500 Consolidate shutdown state. fatal_alert isn't read at all right now, and warn_alert is only checked for close_notify. We only need three states: - Not shutdown. - Got a fatal alert (don't care which). - Got a warning close_notify. Leave ssl->shutdown alone for now as it's tied up with SSL_set_shutdown and friends. To distinguish the remaining two, we only need a boolean. Change-Id: I5877723af82b76965c75cefd67ec1f981242281b Reviewed-on: https://boringssl-review.googlesource.com/7434 Reviewed-by: David Benjamin <davidben@google.com> commit a2d4c0c426caf2b212dea39d7bc05868d780eb34 Author: David Benjamin <davidben@google.com> Date: Sun Mar 20 17:53:34 2016 -0400 Work around Android devices without AT_HWCAP2. Some ARMv8 Android devices don't have AT_HWCAP2. This means, when running in 32-bit mode (ARM capability APIs on Linux are different between AArch32 and AArch64), we can't discover the various nice instructions. On a Nexus 6P, this gives a, uh, minor performance win when running in 32-bit mode. Before: Did 1085000 AES-128-GCM (16 bytes) seal operations in 1000003us (1084996.7 ops/sec): 17.4 MB/s Did 60000 AES-128-GCM (1350 bytes) seal operations in 1013416us (59205.7 ops/sec): 79.9 MB/s Did 11000 AES-128-GCM (8192 bytes) seal operations in 1019778us (10786.7 ops/sec): 88.4 MB/s Did 1009000 AES-256-GCM (16 bytes) seal operations in 1000650us (1008344.6 ops/sec): 16.1 MB/s Did 49000 AES-256-GCM (1350 bytes) seal operations in 1015698us (48242.7 ops/sec): 65.1 MB/s Did 9394 AES-256-GCM (8192 bytes) seal operations in 1071104us (8770.4 ops/sec): 71.8 MB/s Did 1557000 SHA-1 (16 bytes) operations in 1000317us (1556506.6 ops/sec): 24.9 MB/s Did 762000 SHA-1 (256 bytes) operations in 1000527us (761598.6 ops/sec): 195.0 MB/s Did 45000 SHA-1 (8192 bytes) operations in 1013773us (44388.6 ops/sec): 363.6 MB/s Did 1459000 SHA-256 (16 bytes) operations in 1000271us (1458604.7 ops/sec): 23.3 MB/s Did 538000 SHA-256 (256 bytes) operations in 1000990us (537467.9 ops/sec): 137.6 MB/s Did 26000 SHA-256 (8192 bytes) operations in 1008403us (25783.3 ops/sec): 211.2 MB/s After: Did 1890000 AES-128-GCM (16 bytes) seal operations in 1000068us (1889871.5 ops/sec): 30.2 MB/s Did 509000 AES-128-GCM (1350 bytes) seal operations in 1000112us (508943.0 ops/sec): 687.1 MB/s Did 110000 AES-128-GCM (8192 bytes) seal operations in 1007966us (109130.7 ops/sec): 894.0 MB/s Did 1960000 AES-256-GCM (16 bytes) seal operations in 1000303us (1959406.3 ops/sec): 31.4 MB/s Did 460000 AES-256-GCM (1350 bytes) seal operations in 1001873us (459140.0 ops/sec): 619.8 MB/s Did 97000 AES-256-GCM (8192 bytes) seal operations in 1005337us (96485.1 ops/sec): 790.4 MB/s Did 1927000 SHA-1 (16 bytes) operations in 1000429us (1926173.7 ops/sec): 30.8 MB/s Did 1151000 SHA-1 (256 bytes) operations in 1000425us (1150511.0 ops/sec): 294.5 MB/s Did 87000 SHA-1 (8192 bytes) operations in 1003089us (86732.1 ops/sec): 710.5 MB/s Did 2357390 SHA-256 (16 bytes) operations in 1000116us (2357116.6 ops/sec): 37.7 MB/s Did 1410000 SHA-256 (256 bytes) operations in 1000176us (1409751.9 ops/sec): 360.9 MB/s Did 101000 SHA-256 (8192 bytes) operations in 1007007us (100297.2 ops/sec): 821.6 MB/s BUG=chromium:596156 Change-Id: Iacc1f8d8a07e991d4615f2e12c5c54923fb31aa2 Reviewed-on: https://boringssl-review.googlesource.com/7507 Reviewed-by: David Benjamin <davidben@google.com> commit 054e151b16be6ada891ee8fd71915088dda30886 Author: David Benjamin <davidben@google.com> Date: Tue Mar 1 17:35:47 2016 -0500 Rewrite ARM feature detection. This removes the thread-unsafe SIGILL-based detection and the multi-consumer-hostile CRYPTO_set_NEON_capable API. (Changing OPENSSL_armcap_P after initialization is likely to cause problems.) The right way to detect ARM features on Linux is getauxval. On aarch64, we should be able to rely on this, so use it straight. Split this out into its own file. The #ifdefs in the old cpu-arm.c meant it shared all but no code with its arm counterpart anyway. Unfortunately, various versions of Android have different missing APIs, so, on arm, we need a series of workarounds. Previously, we used a SIGILL fallback based on OpenSSL's logic, but this is inherently not thread-safe. (SIGILL also does not tell us if the OS knows how to save and restore NEON state.) Instead, base the behavior on Android NDK's cpu-features library, what Chromium currently uses with CRYPTO_set_NEON_capable: - Android before API level 20 does not provide getauxval. Where missing, we can read from /proc/self/auxv. - On some versions of Android, /proc/self/auxv is also not readable, so use /proc/cpuinfo's Features line. - Linux only advertises optional features in /proc/cpuinfo. ARMv8 makes NEON mandatory, so /proc/cpuinfo can't be used without additional effort. Finally, we must blacklist a particular chip because the NEON unit is broken (https://crbug.com/341598). Unfortunately, this means CRYPTO_library_init now depends on /proc being available, which will require some care with Chromium's sandbox. The simplest solution is to just call CRYPTO_library_init before entering the sandbox. It's worth noting that Chromium's current EnsureOpenSSLInit function already depends on /proc/cpuinfo to detect the broken CPU, by way of base::CPU. android_getCpuFeatures also interally depends on it. We were already relying on both of those being stateful and primed prior to entering the sandbox. BUG=chromium:589200 Change-Id: Ic5d1c341aab5a614eb129d8aa5ada2809edd6af8 Reviewed-on: https://boringssl-review.googlesource.com/7506 Reviewed-by: David Benjamin <davidben@google.com> commit dc6c1b83819cb3788c60dd669241adc6752a4604 Author: Brian Smith <brian@briansmith.org> Date: Sun Jan 17 22:21:42 2016 -1000 Fix build when using Visual Studio 2015 Update 1. Many of the compatibility issues are described at https://msdn.microsoft.com/en-us/library/mt612856.aspx. The macros that suppressed warnings on a per-function basis no longer work in Update 1, so replace them with #pragmas. Update 1 warns when |size_t| arguments to |printf| are casted, so stop doing that casting. Unfortunately, this requires an ugly hack to continue working in MSVC 2013 as MSVC 2013 doesn't support "%zu". Finally, Update 1 has new warnings, some of which need to be suppressed. --- Updated by davidben to give up on suppressing warnings in crypto/x509 and crypto/x509v3 as those directories aren't changed much from upstream. In each of these cases, upstream opted just blindly initialize the variable, so do the same. Also switch C4265 to level 4, per Microsoft's recommendation and work around a bug in limits.h that happens to get fixed by Google include order style. (limits.h is sensitive to whether corecrt.h, pulled in by stddef.h and some other headers, is included before it. The reason it affected just one file is we often put the file's header first, which means base.h is pulling in stddef.h. Relying on this is ugly, but it's no worse than what everything else is doing and this doesn't seem worth making something as tame as limits.h so messy to use.) Change-Id: I02d1f935356899f424d3525d03eca401bfa3e6cd Reviewed-on: https://boringssl-review.googlesource.com/7480 Reviewed-by: David Benjamin <davidben@google.com> commit db50299b247bb7eab4df8c8fdd82fc727e8f67c8 Author: David Benjamin <davidben@google.com> Date: Fri Mar 25 16:18:19 2016 -0400 Add tests for RSA objects with only n and d. Conscrypt, thanks to Java's RSAPrivateKeySpec API, must be able to use RSA keys with only modulus and exponent. This is kind of silly and breaks the blinding code so they, both in OpenSSL and BoringSSL, had to explicitly turn blinding off. Add a test for this as we're otherwise sure to break it on accident. We may wish to avoid the silly rsa->flags modification, I'm not sure. For now, keep the requirement in so other consumers do not accidentally rely on this. (Also add a few missing ERR_clear_error calls. Functions which are expected to fail should be followed by an ERR_clear_error so later unexpected failures don't get confused.) BUG=boringssl:12 Change-Id: I674349821f1f59292b8edd085f21dc37e8bcaa75 Reviewed-on: https://boringssl-review.googlesource.com/7560 Reviewed-by: David Benjamin <davidben@google.com> commit cbf56a5683ddda831ff91c46ea48d1fba545db66 Author: Brian Smith <brian@briansmith.org> Date: Mon Mar 21 11:25:39 2016 -1000 Clarify lifecycle of |BN_BLINDING|. In |bn_blinding_update| the condition |b->e != NULL| would never be true (probably), but the test made reasoning about the correctness of the code confusing. That confusion was amplified by the circuitous and unusual way in which |BN_BLINDING|s are constructed. Clarify all this by simplifying the construction of |BN_BLINDING|s, making it more like the construction of other structures. Also, make counter unsigned as it is no longer ever negative. Change-Id: I6161dcfeae19a80c780ccc6762314079fca1088b Reviewed-on: https://boringssl-review.googlesource.com/7530 Reviewed-by: David Benjamin <davidben@google.com> commit 24493a4ff4909616b6d95ad1e968ff485af0d4c4 Author: Brian Smith <brian@briansmith.org> Date: Fri Mar 25 09:12:48 2016 -1000 Always cache Montgomery contexts in RSA. Simplify the code by always caching Montgomery contexts in the RSA structure, regardless of the |RSA_FLAG_CACHE_PUBLIC| and |RSA_FLAG_CACHE_PRIVATE| flags. Deprecate those flags. Now that we do this no more than once per key per RSA exponent, the private key exponents better because the initialization of the Montgomery contexts isn't perfectly side-channel protected. Change-Id: I4fbcfec0f2f628930bfeb811285b0ae3d103ac5e Reviewed-on: https://boringssl-review.googlesource.com/7521 Reviewed-by: David Benjamin <davidben@google.com> commit 4339552fbb2257156ce5c5bf49da2614d7c5a9a9 Author: David Benjamin <davidben@google.com> Date: Thu Mar 17 16:10:58 2016 -0400 Flip the arguments to ExpectBytesEqual in poly1305_test. The function wants the expected value first. Change-Id: I6d3e21ebfa55d6dd99a34fe8380913641b4f5ff6 Reviewed-on: https://boringssl-review.googlesource.com/7501 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 270f0a77617ef2a00eb3e3a50a00f2fe58827e38 Author: David Benjamin <davidben@google.com> Date: Thu Mar 17 14:41:36 2016 -0400 Print an error if no tests match in runner. Otherwise it's confusing if you mistype the test name. Change-Id: Idf32081958f85f3b5aeb8993a07f6975c27644f8 Reviewed-on: https://boringssl-review.googlesource.com/7500 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 4c34026d12eb92406d07ef15f9a151f3913098e9 Author: David Benjamin <davidben@google.com> Date: Thu Mar 17 16:27:41 2016 -0400 Fix poly1305-x86.pl. Imported from patch attached to https://rt.openssl.org/Ticket/Display.html?id=4439. But with the extra vs $extra typo fixed. The root problem appears to be that lazy_reduction tries to use paddd instead of paddq when they believe the sum will not overflow a u32. In the final call to lazy_reduction, this is not true. svaldez and I attempted to work through the bounds, but the bounds derived from the cited paper imply paddd is always fine. Empirically in a debugger, the bounds are exceeded in the test case. I requested more comments from upstream on the bug. When upstream lands their final fix (hopefully with comments), I will update this code. In the meantime, let's stop carrying known-broken stuff. (vlazy_reduction is probably something similar, but since we don't enable that code, we haven't bothered analyzing it.) Also add the smaller of the two test cases that catch the bug. (The other uses an update pattern which isn't quite what poly1305_test does.) Change-Id: I446ed47c21f10b41a0745de96ab119a3f6fd7801 Reviewed-on: https://boringssl-review.googlesource.com/7544 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit fdb88ba2e9ae9e4ebc8c2053ae53160e048efa57 Author: Piotr Sikora <piotrsikora@google.com> Date: Wed Mar 23 18:34:10 2016 -0700 Fix build with -Wwrite-strings. Change-Id: If76154c8d255600e925a408acdc674fc7dad0359 Signed-off-by: Piotr Sikora <piotrsikora@google.com> Reviewed-on: https://boringssl-review.googlesource.com/7526 Reviewed-by: David Benjamin <davidben@google.com> commit 897be6afe34d1c5839e5bba8f2c67d56485d6a5d Author: Matt Mueller <mattm@google.com> Date: Wed Mar 23 12:06:12 2016 -0700 Add CBS_ASN1_UTF8STRING define. Change-Id: I34384feb46c15c4f443f506d724ad500a4cf0f36 Reviewed-on: https://boringssl-review.googlesource.com/7525 Reviewed-by: David Benjamin <davidben@google.com> commit 0a0f83d308f30f71af115960af7dda064ad734a4 Author: Steven Valdez <svaldez@google.com> Date: Tue Mar 22 17:32:45 2016 -0400 Fixing assembly coverage We failed to correctly parse files that executed from the very start of the file due to a missing '- line XXX'. We now use the 'Ir' indicator to recognize the beginning of a file. Change-Id: I529fae9458ac634bf7bf8af61ef18f080e808535 Reviewed-on: https://boringssl-review.googlesource.com/7542 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit afd6d9d61aa27cdba0506f9525e32823e543ba6e Author: Brian Smith <brian@briansmith.org> Date: Tue Mar 15 13:32:46 2016 -1000 Use |size_t| and |int| consistently in p{224,256}-64.c. Use |size_t| for array indexes. Use |int| for boolean flags. Declare the variables that had their types changed closer to where they are used. Previously, some `for` loops depended on `i` being signed, so their structure had to be changed to work with the unsigned type. Change-Id: I247e4f04468419466733b6818d81d28666da0ad3 Reviewed-on: https://boringssl-review.googlesource.com/7468 Reviewed-by: David Benjamin <davidben@google.com> commit 9539ebbf7042f8eaf8c6ddac25ad01aa4017634e Author: David Benjamin <davidben@google.com> Date: Mon Mar 21 18:24:53 2016 -0400 Update FUZZING documentation about max_len. Maintain the max_len values in foo.options files which ClusterFuzz can process. Also recompute the recommended client and server lengths as they've since gotten much more extensive. Change-Id: Ie87a80d8a4a0c41e215f0537c8ccf82b38c4de09 Reviewed-on: https://boringssl-review.googlesource.com/7509 Reviewed-by: Mike Aizatsky <aizatsky@chromium.org> Reviewed-by: David Benjamin <davidben@google.com> commit 78f8aabe44da43d03ecf82d8d81f4251cd4bfe4a Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 16:33:58 2016 -0500 ssl->ctx cannot be NULL. Most code already dereferences it directly. Change-Id: I227fa91ecbf25a19077f7cfba21b0abd2bc2bd1d Reviewed-on: https://boringssl-review.googlesource.com/7422 Reviewed-by: David Benjamin <davidben@google.com> commit c087c332f89b86b7fc6768e461c97a5ef24b1670 Author: Steven Valdez <svaldez@google.com> Date: Tue Mar 22 11:14:22 2016 -0400 Fix potential double free in EVP_DigestInit_ex There is a potential double free in EVP_DigestInit_ex. This is believed to be reached only as a result of programmer error - but we should fix it anyway. (Imported from upstream's e78dc7e279ed98e1ab9845a70d14dafdfdc88f58) Change-Id: I1da7be7db7afcbe9f30f168df000d64ed73d7edd Reviewed-on: https://boringssl-review.googlesource.com/7541 Reviewed-by: David Benjamin <davidben@google.com> commit be1224882962b63b716ef717377db75f0a805de5 Author: David Benjamin <davidben@google.com> Date: Mon Mar 21 18:32:16 2016 -0400 Fix aarch64 build. We recently gained -Werror=missing-prototypes. (See also, we really need to get those Android bots...) Change-Id: I3962d3050bccf5f5a057d029b5cbff1695ca1a03 Reviewed-on: https://boringssl-review.googlesource.com/7540 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 95b97693403d5c8f09b2870ad9a6d7d198246da4 Author: Brian Smith <brian@briansmith.org> Date: Sun Mar 20 00:33:11 2016 -1000 Fix error handling in |bn_blinding_update|. The fields of the |bn_blinding_st| are not updated atomically. Consequently, one field (|A| or |Ai|) might get updated while the other field (|Ai| or |A|) doesn't get updated, if an error occurs in the middle of updating. Deal with this by reseting the counter so that |A| and |Ai| will both get recreated the next time the blinding is used. Fix a separate but related issue by resetting the counter to zero after calling |bn_blinding_create_param| only if |bn_blinding_create_param| succeeded. Previously, regardless of whether an error occured in |bn_blinding_create_param|, |b->counter| would get reset to zero. The consequence of this was that potentially-bad blinding values would get used 32 times instead of (32 - |b->counter|) times. Change-Id: I236cdb6120870ef06cba129ed86619f593cbcf3d Reviewed-on: https://boringssl-review.googlesource.com/7520 Reviewed-by: David Benjamin <davidben@google.com> commit e11988f5116831969af56d1ffeaa8b82ad19ef2e Author: David Benjamin <davidben@google.com> Date: Mon Mar 21 15:55:19 2016 -0400 Tweak FUZZING.md and minimise_corpuses.sh. Change-Id: If312ce3783bcc39ebd2047470251334aa0897d3d Reviewed-on: https://boringssl-review.googlesource.com/7508 Reviewed-by: David Benjamin <davidben@google.com> commit fdc955cf14c79fb5399652f3a166e7fc4dec0767 Author: Brian Smith <brian@briansmith.org> Date: Tue Mar 15 13:10:11 2016 -1000 Fix parameter type of p256-64.c's |select_point|. Make it match how it is done in p224-64.c. Note in particular that |size| may be 17, so presumably |pre_comp[16]| is accessed, which one would not expect when it was declared |precomp[16][3]|. Change-Id: I54c1555f9e20ccaacbd4cd75a7154b483b4197b7 Reviewed-on: https://boringssl-review.googlesource.com/7467 Reviewed-by: David Benjamin <davidben@google.com> commit df1201e6eefc920fd70d693db4bfb5f76f177b95 Author: Brian Smith <brian@briansmith.org> Date: Tue Mar 15 15:35:53 2016 -1000 Remove unnecessary |BN_CTX_start|/|BN_CTX_end| in |BN_mod_exp_mont_consttime|. Since the function doesn't call |BN_CTX_get|, it doesn't need to call |BN_CTX_start|/|BN_CTX_end|. Change-Id: I6cb954d3fee2959bdbc81b9b97abc52bb6f7704c Reviewed-on: https://boringssl-review.googlesource.com/7469 Reviewed-by: David Benjamin <davidben@google.com> commit 7cf6085b00e194877b88b72d710d1aea6cb03e20 Author: Brian Smith <brian@briansmith.org> Date: Sat Mar 19 22:39:37 2016 -1000 Check for |BN_CTX_new| failure in |mod_exp|. As far as I can tell, this is the last place within libcrypto where this type of check is missing. Change-Id: I3d09676abab8c9f6c4e87214019a382ec2ba90ee Reviewed-on: https://boringssl-review.googlesource.com/7519 Reviewed-by: David Benjamin <davidben@google.com> commit 35673b945dcbf240093f1f0b286e889d31c4d8f9 Author: Piotr Sikora <piotrsikora@google.com> Date: Fri Mar 18 18:25:28 2016 -0700 Build with -Wmissing-prototypes -Wmissing-declarations. Change-Id: Ieba81f114483095f3657e87f669c7562ff75b58c Signed-off-by: Piotr Sikora <piotrsikora@google.com> Reviewed-on: https://boringssl-review.googlesource.com/7516 Reviewed-by: David Benjamin <davidben@google.com> commit f932894c7f379a74327afca6bd283d842f2ebee2 Author: Piotr Sikora <piotrsikora@google.com> Date: Fri Mar 18 18:24:50 2016 -0700 Move function declarations to internal header. Partially fixes build with -Wmissing-declarations. Change-Id: Ia563063fb077cda79244c21f02fd1c0f550353c2 Signed-off-by: Piotr Sikora <piotrsikora@google.com> Reviewed-on: https://boringssl-review.googlesource.com/7515 Reviewed-by: David Benjamin <davidben@google.com> commit f188f9dce8878bd4ac7f1d792b34a15c1496ff3e Author: Piotr Sikora <piotrsikora@google.com> Date: Fri Mar 18 18:23:50 2016 -0700 Fix typo in function name. Partially fixes build with -Wmissing-prototypes. Change-Id: I828bcfb49b23c5a9ea403038bc3fb76750556ef8 Signed-off-by: Piotr Sikora <piotrsikora@google.com> Reviewed-on: https://boringssl-review.googlesource.com/7514 Reviewed-by: David Benjamin <davidben@google.com> commit cd4cf9a12eceaeb22460c3d45d53fd067508fc39 Author: David Benjamin <davidben@google.com> Date: Sun Mar 20 12:45:54 2016 -0400 Fix Windows build Change-Id: I66ecb9f89ec13e432e888e3825d01a015b117568 Reviewed-on: https://boringssl-review.googlesource.com/7505 Reviewed-by: David Benjamin <davidben@google.com> commit 8b0fe8c0ac629ed7b87755f2aebb4d07b78c24df Author: Piotr Sikora <piotrsikora@google.com> Date: Fri Mar 18 18:22:54 2016 -0700 Add missing prototypes. Partially fixes build with -Wmissing-prototypes. Change-Id: If04d8fe7cbf068883485e95bd5ea6cdab6743e46 Signed-off-by: Piotr Sikora <piotrsikora@google.com> Reviewed-on: https://boringssl-review.googlesource.com/7513 Reviewed-by: David Benjamin <davidben@google.com> commit c6d3029edaeeb6bab86fcba6ab31bdce77e2ec9c Author: Piotr Sikora <piotrsikora@google.com> Date: Fri Mar 18 17:28:36 2016 -0700 Add missing internal includes. Partially fixes build with -Wmissing-prototypes -Wmissing-declarations. Change-Id: I51209c30f532899f57cfdd9a50cff0a8ee3da5b5 Signed-off-by: Piotr Sikora <piotrsikora@google.com> Reviewed-on: https://boringssl-review.googlesource.com/7512 Reviewed-by: David Benjamin <davidben@google.com> commit 9bb8ba6ba1a865bd7e55ccf494d082b1bc027734 Author: Piotr Sikora <piotrsikora@google.com> Date: Fri Mar 18 18:19:04 2016 -0700 Make local functions static. Partially fixes build with -Wmissing-prototypes -Wmissing-declarations. Change-Id: I6048f5b7ef31560399b25ed9880156bc7d8abac2 Signed-off-by: Piotr Sikora <piotrsikora@google.com> Reviewed-on: https://boringssl-review.googlesource.com/7511 Reviewed-by: David Benjamin <davidben@google.com> commit 537cfc37b82f91f1006596317ba544e4be1a5c8e Author: Piotr Sikora <piotrsikora@google.com> Date: Fri Mar 18 15:53:29 2016 -0700 Use UINT64_C instead of unsigned long long integer constant. Change-Id: I44aa9be26ad9aea6771cb46a886a721b4bc28fde Signed-off-by: Piotr Sikora <piotrsikora@google.com> Reviewed-on: https://boringssl-review.googlesource.com/7510 Reviewed-by: David Benjamin <davidben@google.com> commit 594e7d2b7703a6c231264edf6b03460b018d2200 Author: David Benjamin <davidben@google.com> Date: Thu Mar 17 17:49:56 2016 -0400 Add a test that declining ALPN works. Inspired by https://mta.openssl.org/pipermail/openssl-dev/2016-March/006150.html Change-Id: I973b3baf054ed1051002f7bb9941cb1deeb36d78 Reviewed-on: https://boringssl-review.googlesource.com/7504 Reviewed-by: David Benjamin <davidben@google.com> commit f277add6c2de55286f0d13edebf41929e4970d5a Author: David Benjamin <davidben@google.com> Date: Wed Mar 9 14:38:24 2016 -0500 Run ripemd_test as part of all_tests.go. Change-Id: I9c5e66c34d0f1b735c69d033daee5d312e3c2fe7 Reviewed-on: https://boringssl-review.googlesource.com/7410 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 110fcc960757d7aeb7760359800b8f5646dc70ca Author: David Benjamin <davidben@google.com> Date: Wed Mar 16 15:43:15 2016 -0400 poly1305/asm/poly1305-x86_64.pl: make it work with linux-x32. (Imported from upstream's 2460c7f13389d766dd65fa4e14b69b6fbe3e4e3b.) This is a no-op for us, but avoid a diff with upstream. Change-Id: I6e875704a38dcd9339371393a4dd523647aeef44 Reviewed-on: https://boringssl-review.googlesource.com/7491 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit eebfd896fe178b4ca78bbd8064944a5b31a27667 Author: David Benjamin <davidben@google.com> Date: Mon Mar 14 19:23:58 2016 -0400 Don't shift serial number into sign bit (Imported from upstream's 01c32b5e448f6d42a23ff16bdc6bb0605287fa6f.) Change-Id: Ib52278dbbac1ed1ad5c80f0ad69e34584d411cec Reviewed-on: https://boringssl-review.googlesource.com/7461 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 8d5717b019b5540a72dceefd747d02a72d539dda Author: David Benjamin <davidben@google.com> Date: Mon Mar 14 19:18:14 2016 -0400 perlasm/x86_64-xlate.pl: handle binary constants early. Not all assemblers of "gas" flavour handle binary constants, e.g. seasoned MacOS Xcode doesn't, so give them a hand. (Imported from upstream's ba26fa14556ba49466d51e4d9e6be32afee9c465.) Change-Id: I35096dc8035e06d2fbef2363b869128da206ff9d Reviewed-on: https://boringssl-review.googlesource.com/7459 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 51545ceac659fe30e245c6e992e7fd45b00e8f16 Author: David Benjamin <davidben@google.com> Date: Wed Mar 16 19:53:34 2016 -0400 Remove a number of unnecessary stdio.h includes. Change-Id: I6267c9bfb66940d0b6fe5368514210a058ebd3cc Reviewed-on: https://boringssl-review.googlesource.com/7494 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit b371f1b9ddd8ed519b4ab74b8860aea317e943fa Author: David Benjamin <davidben@google.com> Date: Tue Mar 15 18:06:13 2016 -0400 Include time.h in time_support.h. For time_t and struct tm. BUG=595118 Change-Id: I6c7f05998887ed2bd3fb56c83ac543894ef27fe6 Reviewed-on: https://boringssl-review.googlesource.com/7462 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: Nico Weber <thakis@chromium.org> Reviewed-by: David Benjamin <davidben@google.com> commit 9aa1562843fbe63bc520c513222d0100a2085780 Author: Brian Smith <brian@briansmith.org> Date: Tue Mar 15 13:00:49 2016 -1000 Remove unnecessary type casts in crypto/rsa. Change-Id: I0b5c661674fbcaf6b4d5b0ce7944459cd45606b1 Reviewed-on: https://boringssl-review.googlesource.com/7466 Reviewed-by: David Benjamin <davidben@google.com> commit 6f7374b0edf3960eeb292b4af2a4003db395e22d Author: David Benjamin <davidben@google.com> Date: Fri Mar 11 16:08:39 2016 -0500 Restore EC_GROUP_new_by_curve_name and EC_GROUP_set_generator. Having a different API for this case than upstream is more trouble than is worth it. This is sad since the new API avoids incomplete EC_GROUPs at least, but I don't believe supporting this pair of functions will be significantly more complex than supporting EC_GROUP_new_arbitrary even when we have static EC_GROUPs. For now, keep both sets of APIs around, but we'll be able to remove the scar tissue once Conscrypt's complex dependencies are resolved. Make the restored EC_GROUP_set_generator somewhat simpler than before by removing the ability to call it multiple times and with some parameters set to NULL. Keep the test. Change-Id: I64e3f6a742678411904cb15c0ad15d56cdae4a73 Reviewed-on: https://boringssl-review.googlesource.com/7432 Reviewed-by: David Benjamin <davidben@google.com> commit 5c05648b8d048c33105c96a41c48c855c44291f5 Author: Emily Stark <estark@google.com> Date: Tue Mar 15 11:40:10 2016 -0700 Tiny documentation fix for EC_POINT_set_affine_coordinates_GFp Change-Id: Icfd9986272f6e1adba54aa7521c28901fa02dfb7 Reviewed-on: https://boringssl-review.googlesource.com/7470 Reviewed-by: David Benjamin <davidben@google.com> commit a2f2bc3a4062d755644adf0f6dca79903638a283 Author: David Benjamin <davidben@google.com> Date: Mon Mar 14 17:13:54 2016 -0400 Align with upstream's error strings, take two. I messed up a few of these. ASN1_R_UNSUPPORTED_ALGORITHM doesn't exist. X509_R_UNSUPPORTED_ALGORITHM does exist as part of X509_PUBKEY_set, but the SPKI parser doesn't emit this. (I don't mind the legacy code having really weird errors, but since EVP is now limited to things we like, let's try to keep that clean.) To avoid churn in Conscrypt, we'll keep defining X509_R_UNSUPPORTED_ALGORITHM, but not actually do anything with it anymore. Conscrypt was already aware of EVP_R_UNSUPPORTED_ALGORITHM, so this should be fine. (I don't expect EVP_R_UNSUPPORTED_ALGORITHM to go away. The SPKI parsers we like live in EVP now.) A few other ASN1_R_* values didn't quite match upstream, so make those match again. Finally, I got some of the rsa_pss.c values wrong. Each of those corresponds to an (overly specific) RSA_R_* value in upstream. However, those were gone in BoringSSL since even the initial commit. We placed the RSA <-> EVP glue in crypto/evp (so crypto/rsa wouldn't depend on crypto/evp) while upstream placed them in crypto/rsa. Since no one seemed to notice the loss of RSA_R_INVALID_SALT_LENGTH, let's undo all the cross-module errors inserted in crypto/rsa. Instead, since that kind of specificity is not useful, funnel it all into X509_R_INVALID_PSS_PARAMETERS (formerly EVP_R_INVALID_PSS_PARAMETERS, formerly RSA_R_INVALID_PSS_PARAMETERS). Reset the error codes for all affected modules. (That our error code story means error codes are not stable across this kind of refactoring is kind of a problem. Hopefully this will be the last of it.) Change-Id: Ibfb3a0ac340bfc777bc7de6980ef3ddf0a8c84bc Reviewed-on: https://boringssl-review.googlesource.com/7458 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit a5177cb319f5ed5cb28f72bd564b4d6d6d355975 Author: David Benjamin <davidben@google.com> Date: Fri Mar 11 19:38:17 2016 -0500 Use a less tedious pattern for X509_NAME. Also fix a long/unsigned-long cast. (ssl_get_message returns long. It really shouldn't, but ssl_get_message needs much more work than just a long -> size_t change, so leave it as long for now.) Change-Id: Ice8741f62a138c0f35ca735eedb541440f57e114 Reviewed-on: https://boringssl-review.googlesource.com/7457 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 6b6e0b20893e2be0e68af605a60ffa2cbb0ffa64 Author: David Benjamin <davidben@google.com> Date: Fri Mar 11 19:30:29 2016 -0500 Fix a memory leak in ssl3_get_certificate_request. Found by libFuzzer. Change-Id: Ifa343a184cc65f71fb6591d290b2d47d24a2be80 Reviewed-on: https://boringssl-review.googlesource.com/7456 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 15c1488b6177b269a311814b63e670df534549e3 Author: David Benjamin <davidben@google.com> Date: Mon Mar 14 14:25:46 2016 -0400 Clear the error queue on entry to core SSL operations. OpenSSL historically made some poor API decisions. Rather than returning a status enum in SSL_read, etc., these functions must be paired with SSL_get_error which determines the cause of the last error's failure. This requires SSL_read communicate with SSL_get_error with some stateful flag, rwstate. Further, probably as workarounds for bugs elsewhere, SSL_get_error does not trust rwstate. Among other quirks, if the error queue is non-empty, SSL_get_error overrides rwstate and returns a value based on that. This requires that SSL_read, etc., be called with an empty error queue. (Or we hit one of the spurious ERR_clear_error calls in the handshake state machine, likely added as further self-workarounds.) Since requiring callers consistently clear the error queue everywhere is unreasonable (crbug.com/567501), clear ERR_clear_error *once* at the entry point. Until/unless[*] we make SSL_get_error sane, this is the most reasonable way to get to the point that clearing the error queue on error is optional. With those in place, the calls in the handshake state machine are no longer needed. (I suspect all the ERR_clear_system_error calls can also go, but I'll investigate and think about that separately.) [*] I'm not even sure it's possible anymore, thanks to the possibility of BIO_write pushing to the error queue. BUG=567501,593963 Change-Id: I564ace199e5a4a74b2554ad3335e99cd17120741 Reviewed-on: https://boringssl-review.googlesource.com/7455 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit cfa9de85a3f1b5c09fe0087fb94b3b5f7210ba69 Author: David Benjamin <davidben@google.com> Date: Mon Mar 14 14:19:41 2016 -0400 Revert "Revert "Reduce maximum RSA public exponent size to 33 bits."" This reverts commit ba70118d8ea7bb0232554bbd70606703bde5bde3. Reverting this did not resolve the regression and the cause is now known. BUG=593963 Change-Id: Ic5e24b74e8f16b01d9fdd80f267a07ef026c82cf Reviewed-on: https://boringssl-review.googlesource.com/7454 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit fb8e67889792e2a5914bcfdc590c250141645a74 Author: David Benjamin <davidben@google.com> Date: Fri Mar 11 14:39:46 2016 -0500 Match upstream's error codes for the old sigalg code. People seem to condition on these a lot. Since this code has now been moved twice, just make them all cross-module errors rather than leave a trail of renamed error codes in our wake. Change-Id: Iea18ab3d320f03cf29a64a27acca119768c4115c Reviewed-on: https://boringssl-review.googlesource.com/7431 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 3f1904bee1f1a119e48b4827579955cc11733e39 Author: Brian Smith <brian@briansmith.org> Date: Thu Mar 10 17:16:02 2016 -1000 Set |bn->neg| to zero in |bn_set_words|. If the values of any of the coordinates in the output point |r| were negative during nistz256 multiplication, then the calls to |bn_set_word| would result in the wrong coordinates being returned (the negatives of the correct coordinates would be returned instead). Fix that. Change-Id: I6048e62f76dca18f625650d11ef5a051c9e672a4 Reviewed-on: https://boringssl-review.googlesource.com/7442 Reviewed-by: David Benjamin <davidben@google.com> commit 6603b76f7616fe781ec6dcf3d66c82f29d776697 Author: Brian Smith <brian@briansmith.org> Date: Thu Mar 10 16:50:25 2016 -1000 Remove reduction in |ec_GFp_simple_set_Jprojective_coordinates_GFp|. The (internal) constant-time callers of this function already do a constant-time reduction before calling. And, nobody should be calling this function with out-of-range coordinates anyway. So, just require valid coordinates as input. Further, this function is rarely called, so don't bother with the optimization to avoid encoding Montgomery encoding of 1 for the Z coordinate. Change-Id: I637ffaf4d39135ca17214915b9a8582ea052eea8 Reviewed-on: https://boringssl-review.googlesource.com/7441 Reviewed-by: David Benjamin <davidben@google.com> commit 8542daa22d2cade301dfada99748d872a1f577af Author: Brian Smith <brian@briansmith.org> Date: Thu Mar 10 16:46:15 2016 -1000 Require compressed x EC coordinate to be a field element. Don't try to fix a bad |x| coordinate by reducing it. Instead, just fail. This also makes the code clearer; in particular, it was confusing why |x_| was used for some calculations when it seems like |x| was just as good or better. Change-Id: I9a6911f0d2bd72852a26b46f3828eb5ba3ef924f Reviewed-on: https://boringssl-review.googlesource.com/7440 Reviewed-by: David Benjamin <davidben@google.com> commit df28c3acf120361f260c8a91b902e089ff213bb8 Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 16:11:51 2016 -0500 Tidy up the client Certificate message skipping slightly. Align all unexpected messages on SSL_R_UNEXPECTED_MESSAGE. Make the SSL 3.0 case the exceptional case. In doing so, make sure the SSL 3.0 SSL_VERIFY_FAIL_IF_NO_PEER_CERT case has its own test as that's a different handshake shape. Change-Id: I1a539165093fbdf33e2c1b25142f058aa1a71d83 Reviewed-on: https://boringssl-review.googlesource.com/7421 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 11d50f94d8742010520ecfc315534e9a39f71375 Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 15:55:45 2016 -0500 Include colons in expectedError matches. If we're doing substring matching, we should at least include the delimiter. Change-Id: I98bee568140d0304bbb6a2788333dbfca044114c Reviewed-on: https://boringssl-review.googlesource.com/7420 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 454aa4c25e0cc0a0e95781d715038a16be3c190d Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 08:43:27 2016 -0500 Rewrite ssl3_send_client_certificate. The old logic was quite messy and grew a number of no-ops over the years. It was also unreasonably fond of the variable name |i|. The current logic wasn't even correct. It's overly fond of sending no certificate, even when it pushes errors on the error queue for a fatal error. Change-Id: Ie5b2b38dd309f535af1d17fa261da7dc23185866 Reviewed-on: https://boringssl-review.googlesource.com/7418 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 0b7ca7dc0098f329d6348a45e372bd884f92bc97 Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 15:44:22 2016 -0500 Add tests for doing client auth with no certificates. In TLS, you never skip the Certificate message. It may be empty, but its presence is determined by CertificateRequest. (This is sensible.) In SSL 3.0, the client omits the Certificate message. This means you need to probe and may receive either Certificate or ClientKeyExchange (thankfully, ClientKeyExchange is not optional, or we'd have to probe at ChangeCipherSpec). We didn't have test coverage for this, despite some of this logic being a little subtle asynchronously. Fix this. Change-Id: I149490ae5506f02fa0136cb41f8fea381637bf45 Reviewed-on: https://boringssl-review.googlesource.com/7419 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit f41bb59703b5fed45209a608daac1d523072e4de Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 20:10:38 2016 -0500 Remove unused functions. We never heap-allocate a GCM128_CONTEXT. Change-Id: I7e89419ce4d81c1598a4b3a214c44dbbcd709651 Reviewed-on: https://boringssl-review.googlesource.com/7430 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit acb6dccf12f17545c219605d70e12c995018bdcd Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 09:15:01 2016 -0500 Add tests for the old client cert callback. Also add no-certificate cases to the state machine coverage tests. Change-Id: I88a80df6f3ea69aabc978dd356abcb9e309e156f Reviewed-on: https://boringssl-review.googlesource.com/7417 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit a857159dd61204bfe93bd8e2f00448434e8b0b99 Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 01:41:55 2016 -0500 Clean up some silly variable names. Change-Id: I5b38e2938811520f52ece6055245248c80308b4d Reviewed-on: https://boringssl-review.googlesource.com/7416 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 08791e6756c3fbee0ef1bdc104a74ab212501bb6 Author: David Benjamin <davidben@google.com> Date: Thu Mar 10 12:41:19 2016 -0500 Appease sanitizers in x25519_ge_scalarmult. Although exactly one iteration of cmov_cached will always initialize selected, it ends up messing with uninitialized memory. Initialize |selected| before the loop. BUG=593540 Change-Id: I5921843f68c6dd1dc7f752538825bc43ba75df4a Reviewed-on: https://boringssl-review.googlesource.com/7415 Reviewed-by: Arnar Birgisson <arnarb@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 97c80512afc7ff8d0afcc806ef6dd936cca752a2 Author: Adam Langley <agl@google.com> Date: Thu Mar 10 09:23:03 2016 -0800 Add |DH_generate_parameters| to decrepit. This makes building OpenLDAP easier. Change-Id: Id64699f95477fb8fb98957027c97070ebf41f4b1 Reviewed-on: https://boringssl-review.googlesource.com/7407 Reviewed-by: David Benjamin <davidben@google.com> commit b8b28a64ff45fd88fd51b7af78452da5b10288f3 Author: Adam Langley <agl@google.com> Date: Thu Mar 10 09:20:47 2016 -0800 Add CRYPTO_[malloc|free|realloc] as aliases for the OPENSSL_𝑥 names. This makes building OpenLDAP easier. Change-Id: Ic1c5bcb2ec35c61c048e780ebc56db033d8382d8 Reviewed-on: https://boringssl-review.googlesource.com/7406 Reviewed-by: David Benjamin <davidben@google.com> commit 8f307d3805db102a5f2afffed821acff6b30c98e Author: David Benjamin <davidben@google.com> Date: Wed Mar 9 18:40:04 2016 -0500 Update cmake-linux64.tar.gz and cmake-mac.tar.gz. Built from: 92c83ad8a4fd6224cf6319a60b399854f55b38ebe9d297c942408b792b1a9efa cmake-3.5.0.tar.gz Update instructions in the UPDATING file. Change-Id: I49d3f5ef353347c446a04797719227e9793e3e0d Reviewed-on: https://boringssl-review.googlesource.com/7414 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 8169df23ddff0169560583052492715590b5c9df Author: David Benjamin <davidben@google.com> Date: Wed Mar 9 18:05:12 2016 -0500 Update Windows tools for the bots. See 0d5e080ab948da74be68e5f9f6c002fedc99a3ec for the previous version. Include instructions on where to get the tools used. 807f96230c889b10f2957a47585426af4cdb116a8a77f1caecca83b7d7ab862b cmake-3.5.0-win32-x86.zip e6bb5c3e4d936bb1067560a58a21260693a0fbe34e55afb0111fe14f7eebc92c strawberry-perl-5.22.1.2-32bit-portable.zip Change-Id: I504cf779abce26087d09c0c974fb481886c9c459 Reviewed-on: https://boringssl-review.googlesource.com/7413 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 659b24d96108bbb45e6c41caef08ce5bfaa05f20 Author: David Benjamin <davidben@google.com> Date: Wed Mar 9 17:46:47 2016 -0500 Update versions of tools in util/bot. Update the easy ones here. Also include instructions on how to do this. The .sha1 files will be updated separately with instructions. Change-Id: I2a3aba43b8ffbdf930b8a2602dc1460077f6d0e7 Reviewed-on: https://boringssl-review.googlesource.com/7412 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 23afa689379b1b5a6a7a98327b847d323141930a Author: David Benjamin <davidben@google.com> Date: Wed Mar 9 15:11:12 2016 -0500 Fix the shared library build. libdecrepit wants some symbols visible. Also a build file typo. Change-Id: I670d2324ab9048f84e7f80afdefc98cbab80335d Reviewed-on: https://boringssl-review.googlesource.com/7411 Reviewed-by: Adam Langley <agl@google.com> commit f284a7dab6fe4fcc3b96a520f93cd79ec4cff2fd Author: Adam Langley <agl@google.com> Date: Wed Mar 9 12:09:00 2016 -0800 Fix Windows build. Windows doesn't like returning void values from void functions. Change-Id: I9fbcb26098a5434ff4e8980f3ed0cd7b2567d658 commit f202d96875d5d66eb8e64a8ed9fd7b0232c7797a Author: Adam Langley <agl@google.com> Date: Wed Mar 9 12:04:55 2016 -0800 Fix bug in obj_decrepit.c Interestingly, Windows caught this with: ..\decrepit\obj\obj_decrepit.c(33) : warning C4090: 'function' : different 'const' qualifiers However, the value of |name| isn't const, only the thing that it points to. So this seems like a bug in MSVC, but I'm ok with it this time. Change-Id: I076f98339cb0b669a4f592fba89aafc0a580efc4 Reviewed-on: https://boringssl-review.googlesource.com/7404 Reviewed-by: David Benjamin <davidben@google.com> commit ef18746ad4421273d051aa32953fe422d7713563 Author: Brian Smith <brian@briansmith.org> Date: Fri Feb 5 14:41:39 2016 -1000 Remove unused code for multiple-point ECC multiplication. The points are only converted to affine form when there are at least three points being multiplied (in addition to the generator), but there never is more than one point, so this is all dead code. Also, I doubt that the comments "...point at infinity (which normally shouldn't happen)" in the deleted code are accurate. And, the projective->affine conversions that were removed from p224-64.c and p256-64.c didn't seem to properly account for the possibility that any of those points were at infinity. Change-Id: I611d42d36dcb7515eabf3abf1857e52ff3b45c92 Reviewed-on: https://boringssl-review.googlesource.com/7100 Reviewed-by: David Benjamin <davidben@google.com> commit a7a226add9a3fb9efc2540d12635683150820f83 Author: Adam Langley <agl@google.com> Date: Tue Mar 8 15:00:18 2016 -0800 Add |OBJ_NAME_do_all_sorted|. This another of those functions that tries to turn C into Python. In this case, implement it in terms of the similar functions in EVP so that at least we only have one list of things. This makes life with nmap easier. Change-Id: I6d01c43f062748d4ba7d7020587c286322e610bb Reviewed-on: https://boringssl-review.googlesource.com/7403 Reviewed-by: David Benjamin <davidben@google.com> commit ff452c1d0e5bf389a112e35dba09a61b424a7d00 Author: Adam Langley <agl@google.com> Date: Tue Mar 8 14:17:02 2016 -0800 Add RIPEMD160 support in decrepit. This version is taken from OpenSSL 1.0.2 with tweaks to support the changes that we have made to md32_common.h. None of the assembly implementations have been imported. This makes supporting nmap easier. Change-Id: Iae9241abdbc9021cc6bc35a65b40c3d739011ccc Reviewed-on: https://boringssl-review.googlesource.com/7402 Reviewed-by: David Benjamin <davidben@google.com> commit d279a21d8c7c39e603dd3d7922afa219fbbc713b Author: Brian Smith <brian@briansmith.org> Date: Tue Mar 8 17:09:40 2016 -1000 Avoid potential uninitialized memory read in crypto/ec/p256-x86_64.c. If the function returns early due to an error, then the coordinates of the result will have their |top| value set to a value beyond what has actually been been written. Fix that, and make it easier to avoid such issues in the future by refactoring the code. As a bonus, avoid a false positive MSVC 64-bit opt build "potentially uninitialized value used" warning. Change-Id: I8c48deb63163a27f739c8797962414f8ca2588cd Reviewed-on: https://boringssl-review.googlesource.com/6579 Reviewed-by: David Benjamin <davidben@google.com> commit 081e3f34a2b324edce50b7a5df9b2e283781af7b Author: Brian Smith <brian@briansmith.org> Date: Wed Nov 25 14:19:21 2015 -1000 Remove |EC_POINT::Z_is_one|. Having |Z_is_one| be out of sync with |Z| could potentially be a very bad thing, and in the past there have been multiple bugs of this sort, including one currently in p256-x86_64.c (type confusion: Montgomery- encoded vs unencoded). Avoid the issue entirely by getting rid of |Z_is_one|. Change-Id: Icb5aa0342df41d6bc443f15f952734295d0ee4ba Reviewed-on: https://boringssl-review.googlesource.com/6576 Reviewed-by: David Benjamin <davidben@google.com> commit bfb38b1a3c5e37d43188bbd02365a87bebc8d122 Author: Adam Langley <agl@google.com> Date: Tue Mar 8 14:15:35 2016 -0800 Add |RC4_options| to decrepit. I've no idea who thought that this function was a good idea in the first place, but including it in decrepit makes supporting nmap easier. Change-Id: I7433cda6a6ddf1cc545126edf779625e9fc70ada Reviewed-on: https://boringssl-review.googlesource.com/7401 Reviewed-by: David Benjamin <davidben@google.com> commit a34a5aacffa98941fed0abe19dc1bb29e9c1c4ef Author: Adam Langley <agl@google.com> Date: Tue Mar 8 14:11:48 2016 -0800 Add one-shot |MD4| function. This could live in decrepit, but it's tiny and having it makes the interface more uniform that what we have for MD5 so I put it in the main code. This is to more easily support nmap. Change-Id: Ia098cc7ef6e00a90d2f3f56ee7deba8329c9a82e Reviewed-on: https://boringssl-review.googlesource.com/7400 Reviewed-by: David Benjamin <davidben@google.com> commit ba70118d8ea7bb0232554bbd70606703bde5bde3 Author: David Benjamin <davidben@google.com> Date: Tue Mar 8 18:03:31 2016 -0500 Revert "Reduce maximum RSA public exponent size to 33 bits." This reverts commit b944882f26d64881161622b6c708568ff67483dd. Recent Chrome canaries show a visible jump in ERR_SSL_PROTOCOL_ERROR which coincided with a DEPS roll that included this change. Speculatively revert it to see if they go back down afterwards. Change-Id: I067798db144c348d666985986dfb9720d1153b7a Reviewed-on: https://boringssl-review.googlesource.com/7391 Reviewed-by: David Benjamin <davidben@google.com> commit 617804adc5cd6760a3febcd9d4408fbfc6ebcd0c Author: Brian Smith <brian@briansmith.org> Date: Mon Feb 8 20:36:51 2016 -1000 Always use |BN_mod_exp_mont|/|BN_mod_exp_mont_consttime| in RSA. This removes a hard dependency on |BN_mod_exp|, which will allow the linker to drop it in programs that don't use other features that require it. Also, remove the |mont| member of |bn_blinding_st| in favor of having callers pass it when necssaary. The |mont| member was a weak reference, and weak references tend to be error-prone. Finally, reduce the scope of some parts of the blinding code to |static|. Change-Id: I16d8ccc2d6d950c1bb40377988daf1a377a21fe6 Reviewed-on: https://boringssl-review.googlesource.com/7111 Reviewed-by: David Benjamin <davidben@google.com> commit 3ed5977cbb14d82bc2c2e9b3cd717ba1235cdefd Author: David Benjamin <davidben@google.com> Date: Tue Mar 8 12:50:21 2016 -0500 Add an idle timeout to runner.go. If a Read or Write blocks for too long, time out the operation. Otherwise, some kinds of test failures result in hangs, which prevent the test harness from progressing. (Notably, OpenSSL currently has a lot of those failure modes and upstream expressed interest in being able to run the tests to completion.) Go's APIs want you to send an absolute timeout, to avoid problems when a Read is split into lots of little Reads. But we actively want the timer to reset in that case, so this needs a trivial adapter. The default timeout is set at 15 seconds for now. If this becomes a problem, we can extend it or build a more robust deadlock detector given an out-of-band channel (shim tells runner when it's waiting on data, abort if we're also waiting on data at the same time). But I don't think we'll need that complexity. 15 seconds appears fine for both valgrind and running tests on a Nexus 4. BUG=460189 Change-Id: I6463fd36058427d883b526044da1bbefba851785 Reviewed-on: https://boringssl-review.googlesource.com/7380 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 3d38c03a8e2011e1d2801c389fc481c8ba9841d6 Author: David Benjamin <davidben@google.com> Date: Tue Mar 8 16:04:50 2016 -0500 Fix a few more missing CBB_cleanups. See also 1b0c438e1a0e570de18ecc7aabda3be8dea4cfa0. Change-Id: Ifcfe15caa4d0db8ef725f8dacd0e8c5c94b00a09 Reviewed-on: https://boringssl-review.googlesource.com/7390 Reviewed-by: Emily Stark (Dunn) <estark@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit f945952d5779bf7e2b38297cad29d1efb61f5911 Author: David Benjamin <davidben@google.com> Date: Mon Mar 7 15:30:26 2016 -0500 Add a script to run tests on Android. The bots will likely use different infrastructure (I expect I'll need to write an isolate file and such). In the meantime, make it easier to run tests manually. BUG=487432 Change-Id: I0e10b23e5f3eb1c5cd60fb88f21ba4a8385b979e Reviewed-on: https://boringssl-review.googlesource.com/7334 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit dfd6fe4f9545a8fd55b65c99e5a04eb06f9f3600 Author: David Benjamin <davidben@google.com> Date: Mon Mar 7 21:41:13 2016 -0500 Add a PULL_REQUEST_TEMPLATE. Now that we have a GitHub mirror, set up a PULL_REQUEST_TEMPLATE so people know not to file pull requests against us. Text borrowed from Go's version of this file. Change-Id: I7da127fbf36eb3a7cb68e3a91cc9dfbb7fc92155 Reviewed-on: https://boringssl-review.googlesource.com/7370 Reviewed-by: Adam Langley <agl@google.com> commit cdd7048358b524567734eb5fc283cc9f42005686 Author: Adam Langley <agl@google.com> Date: Mon Mar 7 17:53:10 2016 -0800 Fix windows build. Windows doesn't like struct literals: ..\decrepit\dsa\dsa_decrepit.c(85) : warning C4204: nonstandard extension used : non-constant aggregate initializer Change-Id: I12541f2883ecbb10c85cddfae8d2adbbb1365ae3 Reviewed-on: https://boringssl-review.googlesource.com/7364 Reviewed-by: Adam Langley <agl@google.com> commit 6e96eaebe016804a96aa99c8a06a2654103f8de6 Author: Adam Langley <agl@google.com> Date: Mon Mar 7 17:07:54 2016 -0800 Add |X509_EXT_conf_nid| to decrepit. This function is a deprecated version of |X509_EXT_nconf_nid| that takes a hash of |CONF_VALUE|s directly rather than a |CONF|. Change-Id: I5fd1025b31d73b988d9298b2624453017dd34ff4 Reviewed-on: https://boringssl-review.googlesource.com/7363 Reviewed-by: David Benjamin <davidben@google.com> commit 8ba4b2d5bf812eae838796266b1d01aa363a8dcf Author: Adam Langley <agl@google.com> Date: Mon Mar 7 16:35:18 2016 -0800 Add |RSA_[padding_add|verify]_PKCS1_PSS to decrepit. These functions are just like the _mgf1 versions but omit one of the parameters. It's easier to add them than to patch the callers in some cases. Change-Id: Idee5b81374bf15f2ea89b7e0c06400c2badbb275 Reviewed-on: https://boringssl-review.googlesource.com/7362 Reviewed-by: David Benjamin <davidben@google.com> commit 4435e96b08c3cacdde5bb12a2f1aa82aa87a9516 Author: Adam Langley <agl@google.com> Date: Mon Mar 7 16:16:13 2016 -0800 Include buffer.h from bio.h. We shouldn't really have to do this, but there's a lot of code that doesn't always include what it uses. In this case, since bio.h references |BUF_MEM| in function signatures, it seems a little less distasteful. Change-Id: Ifb50f8bce40639f977b4447404597168a68c8388 Reviewed-on: https://boringssl-review.googlesource.com/7361 Reviewed-by: David Benjamin <davidben@google.com> commit 99a24ba0f14c1eb87b6ebc4c4de4dde5335534be Author: Adam Langley <agl@google.com> Date: Mon Mar 7 16:11:01 2016 -0800 Add DSA_generate_parameters to decrepit. This function was deprecated by OpenSSL in 0.9.8 but code that uses it still exists. This change adds an implementation of this function to decreipt/ to support these programs. Change-Id: Ie99cd00ff8b0ab2675f2b1c821c3d664b9811f16 Reviewed-on: https://boringssl-review.googlesource.com/7360 Reviewed-by: David Benjamin <davidben@google.com> commit 22ce9b2d08a52e399bf2ab86851952d727be034d Author: David Benjamin <davidben@google.com> Date: Sun Mar 6 19:26:52 2016 -0500 SSL_set_fd should create socket BIOs, not fd BIOs. In OpenSSL, they create socket BIOs. The distinction isn't important on UNIX. On Windows, file descriptors are provided by the C runtime, while sockets must use separate recv and send APIs. Document how these APIs are intended to work. Also add a TODO to resolve the SOCKET vs int thing. This code assumes that Windows HANDLEs only use the bottom 32 bits of precision. (Which is currently true and probably will continue to be true for the foreseeable future[*], but it'd be nice to do this right.) Thanks to Gisle Vanem and Daniel Stenberg for reporting the bug. [*] Both so Windows can continue to run 32-bit programs and because of all the random UNIX software, like OpenSSL and ourselves, out there which happily assumes sockets are ints. Change-Id: I67408c218572228cb1a7d269892513cda4261c82 Reviewed-on: https://boringssl-review.googlesource.com/7333 Reviewed-by: David Benjamin <davidben@google.com> commit 66b2fe8e0273d1f6cca5db95d4ac3979621dc4ce Author: Tom Thorogood <me+google@tomthorogood.co.uk> Date: Sun Mar 6 20:08:38 2016 +1030 Add |SSL_CTX_set_private_key_method| to parallel |SSL_set_private_key_method| This change adds a |SSL_CTX_set_private_key_method| method that sets key_method on a SSL_CTX's cert. It allows the private key method to be set once and inherited. A copy of key_method (from SSL_CTX's cert to SSL's cert) is added in |ssl_cert_dup|. Change-Id: Icb62e9055e689cfe2d5caa3a638797120634b63f Reviewed-on: https://boringssl-review.googlesource.com/7340 Reviewed-by: David Benjamin <davidben@google.com> commit 62e0219679f5a120445a95def01c7679f5eb1790 Author: Emily Stark <estark@google.com> Date: Sun Mar 6 23:41:16 2016 -0800 Handle empty keys in EVP_marshal_public_key() Instead of crashing when an empty key is passed to EVP_marshal_public_key(), return with an EVP_R_UNSUPPORTED_ALGORITHM_ERROR. This brings e.g. X509_PUBKEY_set() closer to how it behaved before 68772b31 (previously, it returned an error on an empty public key rather than dereferencing pkey->ameth). Change-Id: Ieac368725adb7f22329c035d9d0685b44b885888 Reviewed-on: https://boringssl-review.googlesource.com/7351 Reviewed-by: David Benjamin <davidben@google.com> commit ad004af661759cdc4bf486e81f70a350a3a0a5a9 Author: David Benjamin <davidben@google.com> Date: Sat Mar 5 14:35:35 2016 -0500 Rename NID_x25519 to NID_X25519. I went with NID_x25519 to match NID_sha1 and friends in being lowercase. However, upstream seems to have since chosen NID_X25519. Match their name. Change-Id: Icc7b183a2e2dfbe42c88e08e538fcbd242478ac3 Reviewed-on: https://boringssl-review.googlesource.com/7331 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 154c2f2b37b1acff8f033787072fe7f7bed82fa5 Author: David Benjamin <davidben@google.com> Date: Sat Mar 5 11:57:44 2016 -0500 Add some missing return false lines to test_config.cc. Change-Id: I9540c931b6cdd4d65fa9ebfc52e1770d2174abd2 Reviewed-on: https://boringssl-review.googlesource.com/7330 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit 1b0c438e1a0e570de18ecc7aabda3be8dea4cfa0 Author: Emily Stark <estark@google.com> Date: Sun Mar 6 23:11:31 2016 -0800 Fix i2d_RSAPrivateKey, i2d_RSAPublicKey memory leaks Change-Id: Id2678c20270f2f45efe56efd65caf23e0bb8c09e Reviewed-on: https://boringssl-review.googlesource.com/7350 Reviewed-by: David Benjamin <davidben@google.com> commit 05c7bb4565b1f099e3aceea3623c073003cf5ccd Author: David Benjamin <davidben@google.com> Date: Fri Mar 4 17:07:23 2016 -0500 Avoid shifting negative numbers in curve25519. C is still kind of unsure about the whole two's complement thing and leaves left-shifting of negative numbers undefined. Sadly, some sanitizers believe in teaching the controversy and complain when code relies on the theory of two's complement. Shushing these sanitizers in this case is easier than fighting with build configuration, so replace the shifts with masks. (This is equivalent as the left-shift was of a value right-shifted by the same amount. Instead, we store the unshifted value in carry0, etc., and mask off the bottom bits.) A few other places get casts to unsigned types which, by some miracle, C compilers are forbidden from miscompiling. This is imported from upstream's b95779846dc876cf959ccf96c49d4c0a48ea3082 and 5b7af0dd6c9315ca76fba16813b66f5792c7fe6e. Change-Id: I6bf8156ba692165940c0c4ea1edd5b3e88ca263e Reviewed-on: https://boringssl-review.googlesource.com/7320 Reviewed-by: Adam Langley <agl@google.com> commit 58218b63bc033782162168e1462c9c8890606885 Author: David Benjamin <davidben@google.com> Date: Fri Mar 4 12:44:35 2016 -0500 Regenerate server_corpus and client_corpus. Now that client.cc and server.cc run through application data, regenerate the corpus. Change-Id: I8278ebfe47fd2ba74f67db6f9b545aabf9fd1f84 Reviewed-on: https://boringssl-review.googlesource.com/7301 Reviewed-by: Adam Langley <agl@google.com> commit d86c8a400be34bd77d14448008e3985714654283 Author: David Benjamin <davidben@google.com> Date: Wed Mar 2 14:53:11 2016 -0500 Enable renegotiation in the client fuzzer and read app data. As long as the HTTP/1.1 client auth hack forces use to support renego, having it on seems much more useful than having it off for fuzzing purposes. Also read app data to exercise that code and, on the client, trigger renegotiations as needed. Change-Id: I1941ded6ec9bd764abd199d1518420a1075ed1b2 Reviewed-on: https://boringssl-review.googlesource.com/7291 Reviewed-by: Adam Langley <agl@google.com> commit 1d34e3c644cdafea4187002a8409895bbda31289 Author: David Benjamin <davidben@google.com> Date: Fri Mar 4 12:30:51 2016 -0500 Add an option to pick a different build directory in minimise_corpuses.sh. Also pass set -e instead of chaining things with &&. (One line was missing the &&.) Change-Id: Ia04e7f40f46688c9664101efefef1d1ea069de71 Reviewed-on: https://boringssl-review.googlesource.com/7300 Reviewed-by: Adam Langley <agl@google.com> commit d7166d07ade008390ac5d526ecc25e1ebd140ab1 Author: David Benjamin <davidben@google.com> Date: Thu Mar 3 20:03:55 2016 -0500 Add a standalone ChaCha test. The coverage tool revealed that we weren't testing all codepaths of the ChaCha assembly. Add a standalone test as it's much easier to iterate over all lengths when there isn't the entire AEAD in the way. I wasn't able to find a really long test vector, so I generated a random one with the Go implementation we have in runner. This test gives us full coverage on the ChaCha20_ssse3 variant. (We'll see how it fares on the other codepaths when the multi-variant test harnesses get in. I certainly hope there isn't a more novel way to call ChaCha20 than this...) Change-Id: I087e421c7351f46ea65dacdc7127e4fbf5f4c0aa Reviewed-on: https://boringssl-review.googlesource.com/7299 Reviewed-by: Adam Langley <agl@google.com> commit 433366587d6156c9660cc87a843e9dcef1a58917 Author: David Benjamin <davidben@google.com> Date: Thu Mar 3 15:32:29 2016 -0500 Move AES128 above AES256 by default. This is in preparation for adding AES_256_GCM in Chromium below AES_128_GCM. For now, AES_128_GCM is preferable over AES_256_GCM for performance reasons. While I'm here, swap the order of 3DES and RC4. Chromium has already disabled RC4, but the default order should probably reflect that until we can delete it altogether. BUG=591516 Change-Id: I1b4df0c0b7897930be726fb8321cee59b5d93a6d Reviewed-on: https://boringssl-review.googlesource.com/7296 Reviewed-by: Adam Langley <agl@google.com> commit bd30f480c5bf62444d350abd9a81958b0bb81ae8 Author: David Benjamin <davidben@google.com> Date: Thu Mar 3 15:36:33 2016 -0500 poly1305/asm/poly1305-*.pl: flip horizontal add and reduction. Only the 32-bit AVX2 code path needs this, but upstream choose to harmonize all vector code paths. RT#4346 (Imported from 1ea8ae5090f557fea2e5b4d5758b10566825d74b.) Tested the new code manually on arm and aarch64, NEON and non-NEON. Steven reports that all variants pass on x86 and x86-64 too. I've left the 32-bit x86 AVX2 code disabled since valgrind can't measure the code coverage, but this avoids diff with upstream. We can enable it if we ever end up caring. Change-Id: Id9becc2adfbe44b84764f8e9c1fb5e8349c4d5a8 Reviewed-on: https://boringssl-review.googlesource.com/7295 Reviewed-by: Adam Langley <agl@google.com> commit ab14a4a44042cc1623d287a4e8e3b88df752c344 Author: Steven Valdez <svaldez@google.com> Date: Mon Feb 29 16:58:26 2016 -0500 Adding scripts to generate line coverage. Uses LCOV for C(++) line coverage and Valgrind's Callgrind tool to generate assembly-level line coverage for the generated assembly code. BUG=590332 Change-Id: Ic70300a272c38f4fa6dd615747db568aa0853584 Reviewed-on: https://boringssl-review.googlesource.com/7251 Reviewed-by: David Benjamin <davidben@google.com> commit 80c0fd6746b601f274cd8815d1a9f4536ecc9423 Author: Adam Langley <agl@google.com> Date: Thu Mar 3 09:49:09 2016 -0800 Update fuzzing corpuses. This results from running the fuzzers for a little while with both the 8bit-counters change and after taking the transcripts from the runner tests as seeds for the `client` and `server` fuzzers. Change-Id: I545a89d8dccd7ef69dd97546ed61610eea4a27a3 Reviewed-on: https://boringssl-review.googlesource.com/7276 Reviewed-by: David Benjamin <davidben@google.com> commit fde5afcd887f682eccf3dc7fd6b6f7a31ecb5143 Author: David Benjamin <davidben@google.com> Date: Thu Mar 3 08:47:53 2016 -0500 Remove dead comment. EC point format negotiation is dead and gone. Change-Id: If13ed7c5f31b64df2bbe90c018b2683b6371a980 Reviewed-on: https://boringssl-review.googlesource.com/7293 Reviewed-by: Adam Langley <agl@google.com> commit ddcc186ef15a7739d370768327007d3259b77328 Author: Adam Langley <agl@google.com> Date: Thu Mar 3 09:50:25 2016 -0800 Document how to minimise corpuses. Change-Id: Ie487163787d78d867e34709fb34b4c6a836f668d Reviewed-on: https://boringssl-review.googlesource.com/7275 Reviewed-by: David Benjamin <davidben@google.com> commit de29f36cf4b538ac2027c36fc9d0ccf75a745320 Author: Adam Langley <agl@google.com> Date: Thu Mar 3 09:50:10 2016 -0800 Add `8bit-counters` option for fuzzing. This enables coverage counters[1] when fuzzing. [1] http://clang.llvm.org/docs/SanitizerCoverage.html#coverage-counters Change-Id: I33fca02d0406b75ac1f7598f41fe4c2ce43538d1 Reviewed-on: https://boringssl-review.googlesource.com/7274 Reviewed-by: David Benjamin <davidben@google.com> commit cf81b540ce938f43308eb37ab2ab6ee726c8f122 Author: Brian Smith <brian@briansmith.org> Date: Tue Dec 29 12:02:59 2015 -1000 Remove call to |fprintf| in |CRYPTO_once|. The |fprintf| dependency is quite heavyweight for small targets. Also, using |fprintf| on a closed file dsecriptor is undefined behavior, and there's no way that this code can know whether |stderr| has already been closed. So, just don't do it. Change-Id: I1277733afe0649ae1324d11cac84826a1056e308 Reviewed-on: https://boringssl-review.googlesource.com/6812 Reviewed-by: David Benjamin <davidben@chromium.org> Reviewed-by: David Benjamin <davidben@google.com> commit 9867b7dca287c8e74a5c48f20eec1cc6bc14d670 Author: David Benjamin <davidben@google.com> Date: Tue Mar 1 23:25:48 2016 -0500 Add an option to record transcripts from runner tests. This can be used to get some initial corpus for fuzzing. Change-Id: Ifcd365995b54d202c4a2674f49e7b28515f36025 Reviewed-on: https://boringssl-review.googlesource.com/7289 Reviewed-by: Adam Langley <agl@google.com> commit f2b8363578b289aee1fb1a2a6e6190b70801c600 Author: David Benjamin <davidben@google.com> Date: Tue Mar 1 22:57:46 2016 -0500 Fix the tests for the fuzzer mode. It's useful to make sure our fuzzer mode works. Not all tests pass, but most do. (Notably the negative tests for everything we've disabled don't work.) We can also use then use runner to record fuzzer-mode transcripts with the ciphers correctly nulled. Change-Id: Ie41230d654970ce6cf612c0a9d3adf01005522c6 Reviewed-on: https://boringssl-review.googlesource.com/7288 Reviewed-by: Adam Langley <agl@google.com> commit bc5b2a2e22b63f0f6f57cf067c3cdd23af785225 Author: David Benjamin <davidben@google.com> Date: Tue Mar 1 22:57:32 2016 -0500 Add a deterministic PRNG for fuzzing. If running the stack through a fuzzer, we would like execution to be completely deterministic. This is gated on a BORINGSSL_UNSAFE_FUZZER_MODE #ifdef. For now, this just uses the zero ChaCha20 key and a global counter. As needed, we can extend this to a thread-local counter and a separate ChaCha20 stream and counter per input length. Change-Id: Ic6c9d8a25e70d68e5dc6804e2c234faf48e51395 Reviewed-on: https://boringssl-review.googlesource.com/7286 Reviewed-by: Adam Langley <agl@google.com> commit 8b9e7802acde5e7d811ede05360b03fb4720e104 Author: David Benjamin <davidben@google.com> Date: Wed Mar 2 18:23:21 2016 -0500 Fix up all_tests.go parallelism support. A len(tests) should have been len(testCases), the code never added to the sync.WaitGroup, and feeding tests to the tests channel blocks on the tests completing, so with one worker the results didn't stream. (And if the results channel wasn't large enough, we'd deadlock.) Change-Id: Iee37507b9706b14cffddd9c1b55fc311ee9b666d Reviewed-on: https://boringssl-review.googlesource.com/7292 Reviewed-by: Adam Langley <agl@google.com> commit bf82aede675e343087ca9d31b53547d01c269be0 Author: David Benjamin <davidben@google.com> Date: Tue Mar 1 22:57:40 2016 -0500 Disable all TLS crypto in fuzzer mode. Both sides' signature and Finished checks still occur, but the results are ignored. Also, all ciphers behave like the NULL cipher. Conveniently, this isn't that much code since all ciphers and their size computations funnel into SSL_AEAD_CTX. This does carry some risk that we'll mess up this code. Up until now, we've tried to avoid test-only changes to the SSL stack. There is little risk that anyone will ship a BORINGSSL_UNSAFE_FUZZER_MODE build for anything since it doesn't interop anyway. There is some risk that we'll end up messing up the disableable checks. However, both skipped checks have negative tests in runner (see tests that set InvalidSKXSignature and BadFinished). For good measure, I've added a server variant of the existing BadFinished test to this CL, although they hit the same code. Change-Id: I37f6b4d62b43bc08fab7411965589b423d86f4b8 Reviewed-on: https://boringssl-review.googlesource.com/7287 Reviewed-by: Adam Langley <agl@google.com> commit 2477adcf6236c3040a291ad1bfd53f525e1af96d Author: Brian Smith <brian@briansmith.org> Date: Tue Mar 1 20:16:26 2016 -1000 Clarify use of |$end0| in stitched x86-64 AES-GCM code. There was some uncertainty about what the code is doing with |$end0| and whether it was necessary for |$len| to be a multiple of 16 or 96. Hopefully these added comments make it clear that the code is correct except for the caveat regarding low memory addresses. Change-Id: Iea546a59dc7aeb400f50ac5d2d7b9cb88ace9027 Reviewed-on: https://boringssl-review.googlesource.com/7194 Reviewed-by: Adam Langley <agl@google.com> commit 32223940f28dc55e2d875961bcd2b51b1685358f Author: Steven Valdez <svaldez@google.com> Date: Wed Mar 2 11:53:07 2016 -0500 Making all_tests.go parallelizable Use -num-workers to run multiple workers in parallel when running tests. Change-Id: Iee5554ee78ec8d77700a0df5a297bd2515d34dca Reviewed-on: https://boringssl-review.googlesource.com/7285 Reviewed-by: David Benjamin <davidben@google.com> commit 9bea349660c8230fe33f62a5c03e647854125afc Author: David Benjamin <davidben@google.com> Date: Wed Mar 2 10:59:16 2016 -0500 Account for Windows line endings in runner. Otherwise the split on "--- DONE ---\n" gets confused. Change-Id: I74561a99e52b98e85f67efd85523213ad443d325 Reviewed-on: https://boringssl-review.googlesource.com/7283 Reviewed-by: Adam Langley <agl@google.com> commit 29ec5d1fdab3286946a217878b0326af19f533f2 Author: Adam Langley <alangley@gmail.com> Date: Tue Mar 1 16:12:28 2016 -0800 Add dummy |SSL_get_server_tmp_key|. Node.js calls it but handles it failing. Since we have abstracted this in the state machine, we mightn't even be using a cipher suite where the server's key can be expressed as an EVP_PKEY. Change-Id: Ic3f013dc9bcd7170a9eb2c7535378d478b985849 Reviewed-on: https://boringssl-review.googlesource.com/7272 Reviewed-by: David Benjamin <davidben@google.com> commit d323f4b1e185b43f8d5e5a3b191d4bf0d5b65609 Author: Adam Langley <agl@google.com> Date: Tue Mar 1 15:58:14 2016 -0800 Bring back |verify_store|. This was dropped in d27441a9cb55b02149d7f1236de94f3a40dd1692 due to lack of use, but node.js now needs it. Change-Id: I1e207d4b46fc746cfae309a0ea7bbbc04ea785e8 Reviewed-on: https://boringssl-review.googlesource.com/7270 Reviewed-by: David Benjamin <davidben@google.com> commit 2b07fa4b22198ac02e0cee8f37f3337c3dba91bc Author: David Benjamin <davidben@google.com> Date: Wed Mar 2 00:23:57 2016 -0500 Fix a memory leak in an error path. Found by libFuzzer combined with some experimental unsafe-fuzzer-mode patches (to be uploaded once I've cleaned them up a bit) to disable all those pesky cryptographic checks in the protocol. Change-Id: I9153164fa56a0c2262c4740a3236c2b49a596b1b Reviewed-on: https://boringssl-review.googlesource.com/7282 Reviewed-by: Adam Langley <agl@google.com> commit ff3a1498dae79e7fa1cf8d93f735f6fdae49e286 Author: David Benjamin <davidben@google.com> Date: Wed Mar 2 10:12:06 2016 -0500 Ensure runner notices post-main stderr output. If LeakSanitizer fires something on a test that's expected to fail, runner will swallow it. Have stderr output always end in a "--- DONE ---" marker and treat all output following that as a test failure. Change-Id: Ia8fd9dfcaf48dd23972ab8f906d240bcb6badfe2 Reviewed-on: https://boringssl-review.googlesource.com/7281 Reviewed-by: Adam Langley <agl@google.com> commit 3cd8196f14d8fd762f06ce2e20a23cd912eb06f2 Author: David Benjamin <davidben@google.com> Date: Wed Mar 2 09:40:08 2016 -0500 Mark all curve25519 tables const. See also upstream's dc22d6b37e8058a4334e6f98932c2623cd3d8d0d. (Though I'm not sure why they didn't need to fix cmov.) Change-Id: I2a194a8aea1734d4c1e7f6a0536a636379381627 Reviewed-on: https://boringssl-review.googlesource.com/7280 Reviewed-by: Adam Langley <agl@google.com> commit 7a17ba2e3ab1cc30812193660138cb9f09b27c7e Author: Adam Langley <alangley@gmail.com> Date: Tue Mar 1 16:00:36 2016 -0800 Add |FIPS_mode|, which returns zero. (node.js calls it.) Change-Id: I7401f4cb4dfc61d500331821784ae717ad9f7adf Reviewed-on: https://boringssl-review.googlesource.com/7271 Reviewed-by: David Benjamin <davidben@google.com> commit 708db16463a21b922aed6d393ef74c3c5a366668 Author: Adam Langley <agl@google.com> Date: Tue Mar 1 11:48:00 2016 -0800 Pass |alice_msg| by reference in the SPAKE2 speed test. This is an attempt to make MSVC happy. Currently it's saying: ..\tool\speed.cc(508) : error C2536: 'SpeedSPAKE2::<lambda_…>::SpeedSPAKE2::<lambda_…>::alice_msg' : cannot specify explicit initializer for arrays Change-Id: Ifba1df26b5d734f142668a41834645c1549f9f52 Reviewed-on: https://boringssl-review.googlesource.com/7248 Reviewed-by: David Benjamin <davidben@google.com> commit f27459e41259bd66179febbd3b89cc183791172c Author: Arnar Birgisson <arnarb@google.com> Date: Tue Feb 9 18:09:00 2016 -0800 Add SPAKE2 over Ed25519. SPAKE2 is a password-authenticated key exchange. This implementation is over the twisted Edwards curve Ed25519, and uses SHA-512 as the hash primitive. See https://tools.ietf.org/html/draft-irtf-cfrg-spake2-03 Change-Id: I2cd3c3ebdc3d55ac3aea3a9eb0d06275509597ac Reviewed-on: https://boringssl-review.googlesource.com/7114 Reviewed-by: Adam Langley <agl@google.com> commit e4f3f4df6e521e9f98f6b2e340b98b59cba2c237 Author: Adam Langley <agl@google.com> Date: Tue Mar 1 09:07:14 2016 -0800 Add test that A+A = 2×A on elliptic curves. Change-Id: I914efab9a15c903f79a1b83388b577b14c534269 Reviewed-on: https://boringssl-review.googlesource.com/7247 Reviewed-by: David Benjamin <davidben@google.com> commit 060bd590cec36c11008a513a0f1f239e0c84c774 Author: Adam Langley <agl@google.com> Date: Tue Mar 1 08:23:53 2016 -0800 ec/asm/p256-x86_64-asm.pl: get corner case logic right. (Imported from upstream's 64333004a41a9f4aa587b8e5401420fb70d00687.) RT#4284. This case should be impossible to hit because |EC_POINT_add| doesn't use this function and trying to add equal inputs should never occur during a multiplication. Support for this exists because the pattern has been copied from the first 64-bit P-224 and P-256 work that Emilia, Bodo and I did. There it seemed like a reasonable defense-in-depth in case the code changed in the future. Change-Id: I7ff138669c5468b7d7a5153429bec728cb67e338 Reviewed-on: https://boringssl-review.googlesource.com/7246 Reviewed-by: David Benjamin <davidben@google.com> commit 7aea80f5761e839543b4c9b3952eec123d611f3c Author: Steven Valdez <svaldez@google.com> Date: Tue Mar 1 10:09:04 2016 -0500 Adding missing BN_CTX_start/BN_CTX_end in ec_key Change-Id: Icfa6a0bc36b808e2e6ea8b36a0fc49b3c4943b07 Reviewed-on: https://boringssl-review.googlesource.com/7254 Reviewed-by: David Benjamin <davidben@google.com> commit df2a5562f3cbbf4438cf215cca1d4c3f77fad292 Author: Adam Langley <agl@google.com> Date: Tue Mar 1 08:17:29 2016 -0800 bn/asm/x86_64-mont5.pl: unify gather procedure in hardly used path and reorganize/harmonize post-conditions. (Imported from upstream's 515f3be47a0b58eec808cf365bc5e8ef6917266b) Additional hardening following on from CVE-2016-0702. Change-Id: I19a6739b401887a42eb335fe5838379dc8d04100 Reviewed-on: https://boringssl-review.googlesource.com/7245 Reviewed-by: Adam Langley <agl@google.com> commit b360eaf0018a0ed82b3713adc993ffff8270631e Author: Adam Langley <agl@google.com> Date: Tue Mar 1 08:16:30 2016 -0800 crypto/bn/x86_64-mont5.pl: constant-time gather procedure. (Imported from upstream's 25d14c6c29b53907bf614b9964d43cd98401a7fc.) At the same time remove miniscule bias in final subtraction. Performance penalty varies from platform to platform, and even with key length. For rsa2048 sign it was observed to be 4% for Sandy Bridge and 7% on Broadwell. (This is part of the fix for CVE-2016-0702.) Change-Id: I43a13d592c4a589d04c17c33c0ca40c2d7375522 Reviewed-on: https://boringssl-review.googlesource.com/7244 Reviewed-by: Adam Langley <agl@google.com> commit 1168fc72fc7f3d5b2954ff0cd41365f2a973ba1b Author: Adam Langley <agl@google.com> Date: Tue Mar 1 07:58:38 2016 -0800 bn/asm/rsaz-avx2.pl: constant-time gather procedure. (Imported from upstream's 08ea966c01a39e38ef89e8920d53085e4807a43a) Performance penalty is 2%. (This is part of the fix for CVE-2016-0702.) Change-Id: Id3b6262c5d3201dd64b93bdd34601a51794a9275 Reviewed-on: https://boringssl-review.googlesource.com/7243 Reviewed-by: Adam Langley <agl@google.com> commit 842a06c2b9f7797d19f7f3ba862abe0f208d2391 Author: Adam Langley <agl@google.com> Date: Tue Mar 1 07:57:08 2016 -0800 bn/asm/rsax-x86_64.pl: constant-time gather procedure. (Imported from upstream's ef98503eeef5c108018081ace902d28e609f7772.) Performance penalty is 2% on Linux and 5% on Windows. (This is part of the fix for CVE-2016-0702.) Change-Id: If82f95131c93168282a46ac5a35e2b007cc2bd67 Reviewed-on: https://boringssl-review.googlesource.com/7242 Reviewed-by: Adam Langley <agl@google.com> commit 82bdaa89f07c944265fa899aff9dbefdfd5d0f92 Author: Adam Langley <agl@google.com> Date: Tue Mar 1 07:54:10 2016 -0800 Make copy_from_prebuf constant time. (Imported from upstream's 708dc2f1291e104fe4eef810bb8ffc1fae5b19c1.) Performance penalty varies from platform to platform, and even key length. For rsa2048 sign it was observed to reach almost 10%. This is part of the fix for CVE-2016-0702. Change-Id: Ie0860bf3e531196f03102db1bc48eeaf30ab1d58 Reviewed-on: https://boringssl-review.googlesource.com/7241 Reviewed-by: Adam Langley <agl@google.com> commit aeb69a02b833994766f0af1f4d84929f7496d7f6 Author: Steven Valdez <svaldez@google.com> Date: Fri Feb 26 10:48:59 2016 -0500 Pass pure constants verbatim in perlasm/x86_64-xlate.pl (Imported from upstream's 10c639a8a56c90bec9e332c7ca76ef552b3952ac) Change-Id: Ia8203eeae9d274249595a6e352ec2f77a97ca5d5 Reviewed-on: https://boringssl-review.googlesource.com/7227 Reviewed-by: David Benjamin <davidben@google.com> commit 2c198fae28c13f7cdeadd33dc7f68036310edbe5 Author: David Benjamin <davidben@google.com> Date: Wed Feb 17 14:52:08 2016 -0500 Enforce that d2i_PrivateKey returns a key of the specified type. If d2i_PrivateKey hit the PKCS#8 codepath, it didn't enforce that the key was of the specified type. Note that this requires tweaking d2i_AutoPrivateKey slightly. A PKCS #8 PrivateKeyInfo may have 3 or 4 elements (optional attributes), so we were relying on this bug for d2i_AutoPrivateKey to work. Change-Id: If50b7a742f535d208e944ba37c3a585689d1da43 Reviewed-on: https://boringssl-review.googlesource.com/7253 Reviewed-by: Adam Langley <agl@google.com> commit 886119b9f73b4fe0159c2ab793cccb3fa96ace99 Author: David Benjamin <davidben@google.com> Date: Mon Feb 29 17:21:02 2016 -0500 Disable ChaCha20 assembly for OPENSSL_X86. They fail the newly-added in-place tests. Since we don't have bots for them yet, verified manually that the arm and aarch64 code is fine. Change-Id: Ic6f4060f63e713e09707af05e6b7736b7b65c5df Reviewed-on: https://boringssl-review.googlesource.com/7252 Reviewed-by: Adam Langley <agl@google.com> commit f132d4e8f84602182e521fbe688a264dbc3d19f8 Author: Adam Langley <agl@google.com> Date: Thu Feb 25 17:07:19 2016 -0800 Test AEAD interface with aliased buffers. Cases where the input and output buffers overlap are always a little odd. This change adds a test to ensures that the (generic) AEADs function in these situations. Change-Id: I6f1987a5e10ddef6b2b8f037a6d50737a120bc99 Reviewed-on: https://boringssl-review.googlesource.com/7195 Reviewed-by: David Benjamin <davidben@google.com> commit 42c8c63fcbb53642674da648924e61d4aa65b67c Author: David Benjamin <davidben@google.com> Date: Mon Feb 29 16:59:19 2016 -0500 Fix build. Forgot to delete a line. Change-Id: Ia1fb2904398816d495045dc237337f0be5b09272 Reviewed-on: https://boringssl-review.googlesource.com/7250 Reviewed-by: Steven Valdez <svaldez@google.com> Reviewed-by: David Benjamin <davidben@google.com> commit d7305d50e4dbc16edc2f22133b7daae2cd1724f2 Author: Steven Valdez <svaldez@google.com> Date: Mon Feb 29 10:38:26 2016 -0500 Add missing initialization in bn/exponentiation (Imported from upstream's 04f2a0b50d219aafcef2fa718d91462b587aa23d) Change-Id: Ie840edeb1fc9d5a4273f137467e3ef16528c9668 Reviewed-on: https://boringssl-review.googlesource.com/7234 Reviewed-by: David Benjamin <davidben@google.com> commit 318c076b69d1487cae300abbec7025583f198a2e Author: Steven Valdez <svaldez@google.com> Date: Mon Feb 29 10:14:11 2016 -0500 modes/ctr.c: Ensure ecount_buf alignment in CRYPTO_ctr128_encrypt. This isn't a problem when called from EVP, since the buffer is aligned in the EVP_CIPHER_CTX. The increment counter code is also fixed to deal with overflow. (Imported from upstream's 6533a0b8d1ed12aa5f7dfd7a429eec67c5486bb5) Change-Id: I8d7191c3d3873db254a551085d2358d90bc8397a Reviewed-on: https://boringssl-review.googlesource.com/7233 Reviewed-by: David Benjamin <davidben@google.com> commit df1dc9840946c91426a55c242fe3dc50ed781152 Author: David Benjamin <davidben@google.com> Date: Mon Feb 29 16:27:37 2016 -0500 Add a few more large tag tests to asn1_test. While we're here, may as well test others. Change-Id: I711528641a3f7dd035c696c3c1d6b035437c91cc Reviewed-on: https://boringssl-review.googlesource.com/7239 Reviewed-by: Adam Langley <agl@google.com> commit fb2c6f8c8565e1e2d85c24408050c96521acbcdc Author: David Benjamin <davidben@google.com> Date: Mon Feb 29 15:42:59 2016 -0500 ASN1_get_object should not accept large universal tags. The high bits of the type get used for the V_ASN1_NEG bit, so when used with ASN1_ANY/ASN1_TYPE, universal tags become ambiguous. This allows one to create a negative zero, which should be impossible. Impose an upper bound on universal tags accepted by crypto/asn1 and add a test. BUG=590615 Change-Id: I363e01ebfde621c8865101f5bcbd5f323fb59e79 Reviewed-on: https://boringssl-review.googlesource.com/7238 Reviewed-by: Adam Langley <agl@google.com> commit 7e8ed440135c166d0a29e28548b485b66d1645b8 Author: Adam Langley <agl@google.com> Date: Mon Feb 29 08:08:11 2016 -0800 Fix possible memory leak on BUF_MEM_grow_clean failure (Imported from upstream's e9cf5f03666bb82f0184e4f013702d0b164afdca and 29305f4edc886db349f2beedb345f9dd93311c09) Change-Id: I0fa019e9d337676a84a7a6c103d2c4e14e18aede Reviewed-on: https://boringssl-review.googlesource.com/7240 Reviewed-by: David Benjamin <davidben@google.com> commit a14934ff2de02c6a12cc34272a26816940e93a60 Author: Steven Valdez <svaldez@google.com> Date: Mon Feb 29 10:05:08 2016 -0500 Handle shutdown during init/handshake earlier Sending close_notify during init causes some problems for some applications so we instead revert to the previous behavior returning an error instead of silently passing. (Imported from upstream's 64193c8218540499984cd63cda41f3cd491f3f59) Change-Id: I5efed1ce152197d291e6c7ece6e5dbb8f3ad867d Reviewed-on: https://boringssl-review.googlesource.com/7232 Reviewed-by: David Benjamin <davidben@google.com> commit c4eec0c16b02c97a62a95b6a08656c3a9ddb6baa Author: Adam Langley <agl@google.com> Date: Mon Feb 29 08:01:05 2016 -0800 Fix encoding bug in i2c_ASN1_INTEGER (Imported from upstream's 3661bb4e7934668bd99ca777ea8b30eedfafa871.) Fix bug where i2c_ASN1_INTEGER mishandles zero if it is marked as negative. Thanks to Huzaifa Sidhpurwala <huzaifas@redhat.com> and Hanno Böck <hanno@hboeck.de> for reporting this issue. BUG=590615 Change-Id: I8959e8ae01510a5924862a3f353be23130eee554 Reviewed-on: https://boringssl-review.googlesource.com/7199 Reviewed-by: David Benjamin <davidben@google.com> commit b944882f26d64881161622b6c708568ff67483dd Author: Brian Smith <brian@briansmith.org> Date: Wed Jan 13 10:50:00 2016 -1000 Reduce maximum RSA public exponent size to 33 bits. Reduce the maximum RSA exponent size to 33 bits, regardless of modulus size, for public key operations. Change-Id: I88502b1033d8854696841531031298e8ad96a467 Reviewed-on: https://boringssl-review.googlesource.com/6901 Reviewed-by: Adam Langley <agl@google.com> commit f4e447c16d24aa2f6a9336aa6dbba015380beb29 Author: David Benjamin <davidben@chromium.org> Date: Sun Feb 7 12:31:53 2016 -0500 Move ASN1_bn_print to a static function in evp/print.c. It's not used anywhere else, in the library or consumers (Google ones or ones I could find on Debian codesearch). This is a sufficiently specialized function that the risk of a third-party library newly depending on it is low. This removes the last include of asn1.h or x509.h in crypto/evp. (This is almost entirely cosmetic because it wasn't keeping the static linker from doing the right thing anyway. But if we were want to separate the legacy ASN.1 stack into its own decrepit-like target, we'll need to be pickier about separation.) Change-Id: I9be97c9321572e3a2ed093e1d50036b7654cff41 Reviewed-on: https://boringssl-review.googlesource.com/7080 Reviewed-by: Adam Langley <agl@google.com> commit 63d9246812e4ee0055ca8be425d61b12b89a5876 Author: David Benjamin <davidben@chromium.org> Date: Mon Feb 1 15:48:51 2016 -0500 Reset crypto/evp error codes. A number of values have fallen off now that code's been shuffled around. Change-Id: I5eac1d3fa4a9335c6aa72b9876d37bb9a9a029ac Reviewed-on: https://boringssl-review.googlesource.com/7029 Reviewed-by: Adam Langley <agl@google.com> commit 921d906bb640e105b852c849edb8f0a115cc1a6c Author: David Benjamin <davidben@chromium.org> Date: Sat Jan 30 19:33:52 2016 -0500 Reimplement d2i_PrivateKey. Functions which lose object reuse and need auditing: - d2i_PrivateKey This removes evp_asn1.c's dependency on the old stack. (Aside from obj/.) It also takes old_priv_decode out of EVP_ASN1_METHOD in favor of calling out to the new-style function. EVP_ASN1_METHOD no longer has any old-style type-specific serialization hooks, only the PKCS#8 and SPKI ones. BUG=499653 Change-Id: Ic142dc05a5505b50e4717c260d3893b20e680194 Reviewed-on: https://boringssl-review.googlesource.com/7027 Reviewed-by: Adam Langley <agl@google.com> commit 6d3387d9c1cc184c7d9ca29d726ab478cdfc1023 Author: David Benjamin <davidben@chromium.org> Date: Thu Dec 31 15:11:31 2015 -0500 Reimplement d2i_AutoPrivateKey with the new ASN.1 stack. This is kind of a ridiculous function. It would be nice to lose it, but SSL_use_PrivateKey_file actually calls into it (by way of d2i_PrivateKey_bio). BUG=499653 Change-Id: I83634f6982b15f4b877e29f6793b7e00a1c10450 Reviewed-on: https://boringssl-review.googlesource.com/7026 Reviewed-by: Adam Langley <agl@google.com> commit 8ebc0f55a01539a9eef39e162c25d09303f4013b Author: David Benjamin <davidben@chromium.org> Date: Sun Jan 3 03:02:50 2016 -0800 Decouple the EVP and PEM code. EVP_PKEY_asn1_find can already be private. EVP_PKEY_asn1_find_str is used only so the PEM code can get at legacy encoders. Since this is all legacy non-PKCS8 stuff, we can just explicitly list out the three cases in the two places that need it. If this changes, we can later add a table in crypto/pem mapping string to EVP_PKEY type. With this, EVP_PKEY_ASN1_METHOD is no longer exposed in the public API and nothing outside of EVP_PKEY reaches into it. Unexport all of that. Change-Id: Iab661014247dbdbc31e5e9887364176ec5ad2a6d Reviewed-on: https://boringssl-review.googlesource.com/6871 Reviewed-by: Adam Langley <agl@google.com> commit 3f4f7ee08fe0e36c87519befcaff073dc5a90e95 Author: David Benjamin <davidben@chromium.org> Date: Sun Jan 3 02:52:40 2016 -0800 PEM_write_bio_PrivateKey is always PKCS#8. Every key type which has a legacy PEM encoding also has a PKCS#8 encoding. The fallback codepath is never reached. This removes the only consumer of pem_str, so that may be removed from EVP_PKEY_ASN1_METHOD. Change-Id: Ic680bfc162e1dc76db8b8016f6c10f669b24f5aa Reviewed-on: https://boringssl-review.googlesource.com/6870 Reviewed-by: Adam Langley <agl@google.com> commit 8c07ad3e3be810663d2fe5f94de8cfb256285851 Author: David Benjamin <davidben@chromium.org> Date: Fri Aug 7 12:34:57 2015 -0400 Pull EVP_PKEY print hooks out of the main method table. This allows the static linker to drop it in consumers which don't need this stuff (i.e. all sane ones), once crypto/x509 falls off. This cuts down on a number of dependencies from the core crypto bits on crypto/asn1 and crypto/x509. BUG=499653 Change-Id: I76a10a04dcc444c1ded31683df9f87725a95a4e6 Reviewed-on: https://boringssl-review.googlesource.com/5660 Reviewed-by: Adam Langley <agl@google.com> commit 17727c6843e3b3d4ec93132a454732dd5176ff85 Author: David Benjamin <davidben@chromium.org> Date: Sat Jan 30 14:58:52 2016 -0500 Move all signature algorithm code to crypto/x509. All the signature algorithm logic depends on X509_ALGOR. This also removes the X509_ALGOR-based EVP functions which are no longer used externally. I think those APIs were a mistake on my part. The use in Chromium was unnecessary (and has since been removed anyway). The new X.509 stack will want to process the signatureAlgorithm itself to be able to enforce policies on it. This also moves the RSA_PSS_PARAMS bits to crypto/x509 from crypto/rsa. That struct is also tied to crypto/x509. Any new RSA-PSS code would have to use something else anyway. BUG=499653 Change-Id: I6c4b4573b2800a2e0f863d35df94d048864b7c41 Reviewed-on: https://boringssl-review.googlesource.com/7025 Reviewed-by: Adam Langley <agl@google.com> commit 93a69b4f8f33d70a3350512ec744b5b948fe2f6b Author: David Benjamin <davidben@chromium.org> Date: Sat Jan 30 12:57:05 2016 -0500 Move X.509 signature algorithm tests to the crypto/x509 layer. This is in preparation for moving the logic itself to crypto/x509, so the lower-level functions will not be as readily available. Change-Id: I6507b895317df831ab11d0588c5b09bbb2aa2c24 Reviewed-on: https://boringssl-review.googlesource.com/7023 Reviewed-by: Adam Langley <agl@google.com> commit da295d35f2ccd179635229d719345dd056a56cfb Author: David Benjamin <davidben@chromium.org> Date: Sat Jan 30 14:09:08 2016 -0500 Drop the DSA signature printing hook. It's only used by crypto/x509, and we don't even support DSA in crypto/x509 anymore since the EVP_PKEY_CTX hooks aren't wired up. Change-Id: I1b8538353eb51df353cf9171b1cbb0bb47a879a3 Reviewed-on: https://boringssl-review.googlesource.com/7024 Reviewed-by: Adam Langley <agl@google.com> commit 136df6bd999aa72d4a3817f719bcb87f86014490 Author: Aaron Green <aarongreen@google.com> Date: Fri Feb 12 08:15:35 2016 -0800 Fix implementation-specific behavior in gcm_test.c gcm_test.c includes a test case that does a 'malloc(0)'. This test case currently fails if malloc(0) returns NULL. According to the standard, malloc's behavior with a size of 0is implementation specific and may either be NULL or another pointer suitable to be passed to free(). This change modifies gcm_test.c to handle a return value of NULL. It has been tested with a custom allocator on an experimental branch. Change-Id: I35514ec9735cedffc621f7dfae42b4c6664a1766 Reviewed-on: https://boringssl-review.googlesource.com/7122 Reviewed-by: Adam Langley <agl@google.com> commit 95a79eec40703fcd9f108ff7dac0ec4d34856ecb Author: Emily Stark <estark@google.com> Date: Thu Feb 25 21:12:28 2016 -0800 Add a stub for SSL_get_shared_ciphers(). This stub returns an empty string rather than NULL (since some callers might assume that NULL means there are no shared ciphers). Change-Id: I9537fa0a80c76559b293d8518599b68fd9977dd8 Reviewed-on: https://boringssl-review.googlesource.com/7196 Reviewed-by: David Benjamin <davidben@google.com> commit 6f0c4db90e47437ed87a2d385c7797e692a2cf65 Author: David Benjamin <davidben@google.com> Date: Tue Feb 23 17:43:36 2016 -0500 Enable upstream's Poly1305 code. The C implementation is still our existing C implementation, but slightly tweaked to fit with upstream's init/block/emits convention. I've tested this by looking at code coverage in kcachegrind and valgrind --tool=callgrind --dump-instr=yes --collect-jumps=yes (NB: valgrind 3.11.0 is needed for AVX2. And even that only does 64-bit AVX2, so we can't get coverage for the 32-bit code yet. But I had to disable that anyway.) This was paired with a hacked up version of poly1305_test that would repeat tests with different ia32cap and armcap values. This isn't checked in, but we badly need a story for testing all the different variants. I'm not happy with upstream's code in either the C/asm boundary or how it dispatches between different versions, but just debugging the code has been a significant time investment. I'd hoped to extract the SIMD parts and do the rest in C, but I think we need to focus on testing first (and use that to guide what modifications would help). For now, this version seems to work at least. The x86 (not x86_64) AVX2 code needs to be disabled because it's broken. It also seems pretty unnecessary. https://rt.openssl.org/Ticket/Display.html?id=4346 Otherwise it seems to work and buys us a decent performance improvement. Notably, my Nexus 6P is finally faster at ChaCha20-Poly1305 than my Nexus 4! bssl speed numbers follow: x86 --- Old: Did 1554000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000536us (1553167.5 ops/sec): 24.9 MB/s Did 136000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1003947us (135465.3 ops/sec): 182.9 MB/s Did 30000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1022990us (29325.8 ops/sec): 240.2 MB/s Did 1888000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000206us (1887611.2 ops/sec): 30.2 MB/s Did 173000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1003036us (172476.4 ops/sec): 232.8 MB/s Did 30000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1027759us (29189.7 ops/sec): 239.1 MB/s New: Did 2030000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000507us (2028971.3 ops/sec): 32.5 MB/s Did 404000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1000287us (403884.1 ops/sec): 545.2 MB/s Did 83000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1001258us (82895.7 ops/sec): 679.1 MB/s Did 2018000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000006us (2017987.9 ops/sec): 32.3 MB/s Did 360000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1001962us (359295.1 ops/sec): 485.0 MB/s Did 85000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1002479us (84789.8 ops/sec): 694.6 MB/s x86_64, no AVX2 --- Old: Did 2023000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000258us (2022478.2 ops/sec): 32.4 MB/s Did 466000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1002619us (464782.7 ops/sec): 627.5 MB/s Did 90000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1001133us (89898.1 ops/sec): 736.4 MB/s Did 2238000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000175us (2237608.4 ops/sec): 35.8 MB/s Did 483000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1001348us (482349.8 ops/sec): 651.2 MB/s Did 90000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1003141us (89718.2 ops/sec): 735.0 MB/s New: Did 2558000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000275us (2557296.7 ops/sec): 40.9 MB/s Did 510000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1001810us (509078.6 ops/sec): 687.3 MB/s Did 115000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1006457us (114262.2 ops/sec): 936.0 MB/s Did 2818000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000187us (2817473.1 ops/sec): 45.1 MB/s Did 418000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1001140us (417524.0 ops/sec): 563.7 MB/s Did 91000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1002539us (90769.5 ops/sec): 743.6 MB/s x86_64, AVX2 --- Old: Did 2516000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000115us (2515710.7 ops/sec): 40.3 MB/s Did 774000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1000300us (773767.9 ops/sec): 1044.6 MB/s Did 171000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1004373us (170255.5 ops/sec): 1394.7 MB/s Did 2580000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000144us (2579628.5 ops/sec): 41.3 MB/s Did 769000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1000472us (768637.2 ops/sec): 1037.7 MB/s Did 169000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1000320us (168945.9 ops/sec): 1384.0 MB/s New: Did 3240000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000114us (3239630.7 ops/sec): 51.8 MB/s Did 932000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1000059us (931945.0 ops/sec): 1258.1 MB/s Did 217000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1003282us (216290.1 ops/sec): 1771.8 MB/s Did 3187000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000100us (3186681.3 ops/sec): 51.0 MB/s Did 926000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1000071us (925934.3 ops/sec): 1250.0 MB/s Did 215000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1000479us (214897.1 ops/sec): 1760.4 MB/s arm, Nexus 4 --- Old: Did 430248 ChaCha20-Poly1305 (16 bytes) seal operations in 1000153us (430182.2 ops/sec): 6.9 MB/s Did 115250 ChaCha20-Poly1305 (1350 bytes) seal operations in 1000549us (115186.8 ops/sec): 155.5 MB/s Did 27000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1030124us (26210.4 ops/sec): 214.7 MB/s Did 451750 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000549us (451502.1 ops/sec): 7.2 MB/s Did 118000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1001557us (117816.6 ops/sec): 159.1 MB/s Did 27000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1024263us (26360.4 ops/sec): 215.9 MB/s New: Did 553644 ChaCha20-Poly1305 (16 bytes) seal operations in 1000183us (553542.7 ops/sec): 8.9 MB/s Did 126000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1000396us (125950.1 ops/sec): 170.0 MB/s Did 27000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1000336us (26990.9 ops/sec): 221.1 MB/s Did 559000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1001465us (558182.3 ops/sec): 8.9 MB/s Did 124000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1000824us (123897.9 ops/sec): 167.3 MB/s Did 28000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1034854us (27057.0 ops/sec): 221.7 MB/s aarch64, Nexus 6P --- Old: Did 358000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000358us (357871.9 ops/sec): 5.7 MB/s Did 45000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1022386us (44014.7 ops/sec): 59.4 MB/s Did 8657 ChaCha20-Poly1305 (8192 bytes) seal operations in 1063722us (8138.4 ops/sec): 66.7 MB/s Did 350000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000074us (349974.1 ops/sec): 5.6 MB/s Did 44000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1007907us (43654.8 ops/sec): 58.9 MB/s Did 8525 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1042644us (8176.3 ops/sec): 67.0 MB/s New: Did 713000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000190us (712864.6 ops/sec): 11.4 MB/s Did 180000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1004249us (179238.4 ops/sec): 242.0 MB/s Did 41000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1005811us (40763.1 ops/sec): 333.9 MB/s Did 775000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000719us (774443.2 ops/sec): 12.4 MB/s Did 182000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1003529us (181360.0 ops/sec): 244.8 MB/s Did 41000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1010576us (40570.9 ops/sec): 332.4 MB/s Change-Id: Iaa4ab86ac1174b79833077963cc3616cfb08e686 Reviewed-on: https://boringssl-review.googlesource.com/7226 Reviewed-by: Adam Langley <agl@google.com> commit a211aee545cb665b5099803e106656e4c3b788bf Author: David Benjamin <davidben@google.com> Date: Wed Feb 24 17:18:44 2016 -0500 Add SSL_CIPHER_has_SHA256_HMAC. Change-Id: I05a8f5d1778aba1813fe4d34b4baa21849158218 Reviewed-on: https://boringssl-review.googlesource.com/7215 Reviewed-by: Adam Langley <agl@google.com> commit e593fed3786e9e5dcfe5a1e43181dc91c8e3ff27 Author: David Benjamin <davidben@google.com> Date: Thu Feb 25 11:39:59 2016 -0500 Rename opensslfeatures.h to opensslconf.h. Some software #includes opensslconf.h which typically contains settings that we put in opensslfeatures.h (a header name not in OpenSSL). Rename it to opensslconf.h. Change-Id: Icd21dde172e5e489ce90dd5c16ae4d2696909fb6 Reviewed-on: https://boringssl-review.googlesource.com/7216 Reviewed-by: Adam Langley <agl@google.com> commit a473e554b412abf8415cc83487d146909ecb1e45 Author: David Benjamin <davidben@google.com> Date: Thu Feb 25 12:04:37 2016 -0500 Add BIO_do_connect. Some consumers of connect BIOs connect them explicitly, and we already have the BIO_ctrl hooked up. Change-Id: Ie6b14f8ceb272b560e2b534e0b6c32fae050475b Reviewed-on: https://boringssl-review.googlesource.com/7217 Reviewed-by: Adam Langley <agl@google.com> commit b4e3e694e80bf59bbdc202c9a626e6ecb272c9b1 Author: Brian Smith <brian@briansmith.org> Date: Wed Feb 24 09:58:18 2016 -1000 Use correct counter after invoking stitched AES-NI GCM code. Commit a3d9528e9e212e0dcda30dcb561092c3b3a69010 has a bug that could cause counters to be reused if |$avx=2| were set in the AES-NI AES-GCM assembly code, if the EVP interface were used with certain coding patterns, as demonstrated by the test cases added in a5ee83f67e83d4065d1aa40137e8dd8b1c83b3e5. This changes the encryption code in the same way the decryption code was changed in a3d9528e9e212e0dcda30dcb561092c3b3a69010. This doesn't have any effect currently since the AES-NI AES-GCM code has |$avx=0| now, so |aesni_gcm_encrypt| doesn't change the counter. Change-Id: Iba69cb4d2043d1ea57c6538b398246af28cba006 Reviewed-on: https://boringssl-review.googlesource.com/7193 Reviewed-by: Adam Langley <agl@google.com> commit 6234a7f3a706d2f863e949b4d360ff07faba9dbd Author: David Benjamin <davidben@google.com> Date: Tue Feb 23 18:39:10 2016 -0500 Switch poly1305-armv4.pl to named constants. See https://rt.openssl.org/Ticket/Display.html?id=4341. Change-Id: Ied39744dcf557e4267c7a84d6f95d78a691084e1 Reviewed-on: https://boringssl-review.googlesource.com/7225 Reviewed-by: Adam Langley <agl@google.com> commit f28caea521aab668abf83629dc8116a518f53459 Author: David Benjamin <davidben@google.com> Date: Tue Feb 23 16:25:40 2016 -0500 Check in pristine copies of upstream's poly1305 assembly. Taken from 6b2ebe4332e22b4eb7dd6fadf418e3da7b926ca4. These don't do anything right now but are checked in unmodified to make diffs easier to see. Change-Id: I4f5bdb7b16f4ac27e7ef175f475540c481b8d593 Reviewed-on: https://boringssl-review.googlesource.com/7224 Reviewed-by: Adam Langley <agl@google.com> commit 8ccc3c383a3dc9f3fee1974c08f4f93b3e38404e Author: David Benjamin <davidben@google.com> Date: Thu Feb 25 11:37:12 2016 -0500 Test poly1305 more aggressively. OpenSSL upstream's SIMD assembly is rather complex. This pattern of update calls should be sufficient to stress all the codepaths. Change-Id: I50dea8351e4203b6b2cd9b23456eb4a592d31b5e Reviewed-on: https://boringssl-review.googlesource.com/7223 Reviewed-by: Adam Langley <agl@google.com> commit 3f81b607fee408fe8142442c6e654b0762d8f844 Author: Steven Valdez <svaldez@google.com> Date: Thu Feb 25 13:43:49 2016 -0500 Fix missing ok=0 with cert verification. Also avoid using "i" in X509_cert_verify as a loop counter, trust outcome and as an error ordinal. (Imported from upstream's a3baa171053547488475709c7197592c66e427cf) Change-Id: I4b0b542ffacf7fa861c93c8124b334c0aacc3c17 Reviewed-on: https://boringssl-review.googlesource.com/7222 Reviewed-by: David Benjamin <davidben@google.com> commit 06c5fb4512ecd9aeb74e7d438c257b9f606f67af Author: David Benjamin <davidben@google.com> Date: Thu Feb 25 20:23:24 2016 +0000 Revert "Fix missing ok=0 with cert verification." This reverts commit b0576889fa4c86a8e9cb7e978e7160904fa2c5b4. This broke x509_test. Change-Id: Idbb60df9ca0a8ce727931f8e35e99bbd0f08c3c1 Reviewed-on: https://boringssl-review.googlesource.com/7221 Reviewed-by: David Benjamin <davidben@google.com> commit fd26b7a015b4a5f372eff88c4cd981d34217cc45 Author: Steven Valdez <svaldez@google.com> Date: Thu Feb 25 13:49:45 2016 -0500 If no comparison function is set, sk_sort is a NOP (Imported from upstream's 402fb1896b2aab5cf887127bbce964554b9c8113) Change-Id: I80c1f952085c8fc9062d3395f211a525151c404d Reviewed-on: https://boringssl-review.googlesource.com/7219 Reviewed-by: David Benjamin <davidben@google.com> commit b0576889fa4c86a8e9cb7e978e7160904fa2c5b4 Author: Steven Valdez <svaldez@google.com> Date: Thu Feb 25 13:43:49 2016 -0500 Fix missing ok=0 with cert verification. Also avoid using "i" in X509_cert_verify as a loop counter, trust outcome and as an error ordinal. (Imported from upstream's a3baa171053547488475709c7197592c66e427cf) Change-Id: I492afdbaa5017bcf00a0412033cf99fca3fe9401 Reviewed-on: https://boringssl-review.googlesource.com/7218 Reviewed-by: David Benjamin <davidben@google.com> commit e42da0e4b4a587f30ee5fbb65ce7bb5791a7a5be Author: David Benjamin <davidben@google.com> Date: Thu Feb 25 13:53:25 2016 -0500 Fix bssl rand -hex. It emits NULs instead of c. Change-Id: Id7f103eac049129dbf9a3e852454b22134ce3270 Reviewed-on: https://boringssl-review.googlesource.com/7220 Reviewed-by: Adam Langley <agl@google.com> commit cd8d1761df85b460562237e50af3ee60a1b9856f Author: Brian Smith <brian@briansmith.org> Date: Sun Feb 14 10:12:05 2016 -1000 Move |bn_div_words| to crypto/bn/div.c and make it static. It is only used by |bn_div_rem_words|. Change-Id: I57627091d8db5890d7fea34d8560897717008646 Reviewed-on: https://boringssl-review.googlesource.com/7128 Reviewed-by: David Benjamin <davidben@google.com> commit d1425f69df16310bdca46a3d66144dcb4e3ad4fc Author: Brian Smith <brian@briansmith.org> Date: Thu Feb 11 12:10:16 2016 -1000 Simplify division-with-remainder calculations in crypto/bn/div.c. Create a |bn_div_rem_words| that is used for double-word/single-word divisions and division-with-remainder. Remove all implementations of |bn_div_words| except for the implementation needed for 64-bit MSVC. This allows more code to be shared across platforms and also removes an instance of the dangerous pattern wherein the |div_asm| macro modified a variable that wasn't passed as a parameter. Also, document the limitations of the compiler-generated code for the non-asm code paths more fully. Compilers indeed have not improved in this respect. Change-Id: I5a36a2edd7465de406d47d72dcd6bf3e63e5c232 Reviewed-on: https://boringssl-review.googlesource.com/7127 Reviewed-by: David Benjamin <davidben@google.com> commit 76c6381c21ef07b13371120dc0b938da64f51ca7 Author: Brian Smith <brian@briansmith.org> Date: Sat Feb 13 16:46:11 2016 -1000 Return 0 on error in |EC_POINT_is_on_curve| instead of -1. Callers of this function are not checking for the -1 result. Change the semantics to match their expectations and to match the common semantics of most other parts of BoringSSL. Change-Id: I4ec537d7619e20e8ddfee80c72125e4c02cfaac1 Reviewed-on: https://boringssl-review.googlesource.com/7125 Reviewed-by: David Benjamin <davidben@google.com> commit 0bc2349375212f79cc4a5996f86389d6250fde4f Author: Brian Smith <brian@briansmith.org> Date: Fri Feb 12 10:06:36 2016 -1000 Remove unused |ccm128_context| in crypto/modes/internal.h. Note that this structure has a weak pointer to the key, which was a problem corrected in the AES-GCM code in 0f8bfdeb3383749eecfefb17a36416e6b35fa10c. Also, it uses |void *| instead of |const AES_KEY *| to refer to that key. Change-Id: I70e632e3370ab27eb800bc1c0c64d2bd36b7cafb Reviewed-on: https://boringssl-review.googlesource.com/7123 Reviewed-by: David Benjamin <davidben@google.com> commit d8eea14443ab890b0a6d00a40d2dbf6d3bf79484 Author: Steven Valdez <svaldez@google.com> Date: Wed Feb 24 14:00:22 2016 -0500 BIO_new_mem_buf should take const void * BIO_FLAGS_MEM_RDONLY keeps the invariant. (Imported from upstream's a38a159bfcbc94214dda00e0e6b1fc6454a23b78) Change-Id: I4cb35615d76b77929915e370dbb7fec1455da069 Reviewed-on: https://boringssl-review.googlesource.com/7214 Reviewed-by: David Benjamin <davidben@google.com> commit a5ee83f67e83d4065d1aa40137e8dd8b1c83b3e5 Author: Adam Langley <agl@google.com> Date: Wed Feb 24 10:04:31 2016 -0800 Test different chunk sizes in cipher_test. This change causes cipher_test to test the EVP cipher interfaces with various chunk sizes and adds a couple of large tests of GCM. This is sufficient to uncover the issue that would have been caused by a3d9528e, had the AVX code been enabled. Change-Id: I58d4924c0bcd11a0999c24a0fb77fc5eee71130f Reviewed-on: https://boringssl-review.googlesource.com/7192 Reviewed-by: David Benjamin <davidben@google.com> commit 5ec72de203ff52ff73648b0a3018e79dca830208 Author: Steven Valdez <svaldez@google.com> Date: Wed Feb 24 12:16:32 2016 -0500 Add missing EC NULL Check (imported from upstream's 2b80d00e3ac652377ace84c51b53f51a1b7e1ba2) Change-Id: Iee5a8d85d276033b6ac8bc9ac87e157916a1a29a Reviewed-on: https://boringssl-review.googlesource.com/7212 Reviewed-by: David Benjamin <davidben@google.com> commit b9824e241746d70d985d1004078b5bad0ad9a75b Author: Steven Valdez <svaldez@chromium.org> Date: Wed Feb 24 10:47:52 2016 -0500 Handle SSL_shutdown while in init more appropriately Calling SSL_shutdown while in init previously gave a "1" response, meaning everything was successfully closed down (even though it wasn't). Better is to send our close_notify, but fail when trying to receive one. The problem with doing a shutdown while in the middle of a handshake is that once our close_notify is sent we shouldn't really do anything else (including process handshake/CCS messages) until we've received a close_notify back from the peer. However the peer might send a CCS before acting on our close_notify - so we won't be able to read it because we're not acting on CCS messages! (Imported from upstream's f73c737c7ac908c5d6407c419769123392a3b0a9) Change-Id: Iaad5c5e38983456d3697c955522a89919628024b Reviewed-on: https://boringssl-review.googlesource.com/7207 Reviewed-by: David Benjamin <davidben@google.com> commit e52d22d5f9dc439658746d25cb69702749ec3f67 Author: Steven Valdez <svaldez@chromium.org> Date: Wed Feb 24 10:44:54 2016 -0500 Empty SNI names are not valid (Imported from upstream's 4d6fe78f65be650c84e14777c90e7a088f7a44ce) Change-Id: Id28e0d49da2490e454dcb8603ccb93a506dfafaf Reviewed-on: https://boringssl-review.googlesource.com/7206 Reviewed-by: David Benjamin <davidben@google.com> commit e412bbd9a15d812666291e38e194b71da6a2a062 Author: Steven Valdez <svaldez@chromium.org> Date: Tue Feb 23 15:37:41 2016 -0500 Fix wildcard match on punycode/IDNA DNS names - bugfix: should not treat '--' as invalid domain substring. - '-' should not be the first letter of a domain (Imported from upstream's 15debc128ac13420a4eec9b4a66d72f1dfd69126) Change-Id: Ifd8ff7cef1aab69da5cade8ff8c76c3a723f3838 Reviewed-on: https://boringssl-review.googlesource.com/7205 Reviewed-by: David Benjamin <davidben@google.com> commit 85003903fc58d8825e02162fd33a9b9c28fdec35 Author: David Benjamin <davidben@google.com> Date: Tue Feb 23 18:04:15 2016 -0500 Remove CRYPTO_set_NEON_functional. This depends on https://codereview.chromium.org/1730823002/. The bit was only ever targetted to one (rather old) CPU. Disable NEON on it uniformly, so we don't have to worry about whether any new NEON code breaks it. BUG=589200 Change-Id: Icc7d17d634735aca5425fe0a765ec2fba3329326 Reviewed-on: https://boringssl-review.googlesource.com/7211 Reviewed-by: Adam Langley <agl@google.com> commit 030d08513e7127a0fe8608fed9d75308e1df98b6 Author: David Benjamin <davidben@google.com> Date: Tue Feb 23 16:43:54 2016 -0500 ymm registers are not suffixed with w. This imports a fix to x86gas.pl from upstream's a98c648e40ea5158c8ba29b5a70ccc239d426a20. It's needed to get poly1305-x86.pl working. Confirmed that this is a no-op for our current assembly files. Change-Id: I28de1dbf421b29a06147d1aea3ff3659372a78b3 Reviewed-on: https://boringssl-review.googlesource.com/7210 Reviewed-by: Adam Langley <agl@google.com> commit a3d9528e9e212e0dcda30dcb561092c3b3a69010 Author: Brian Smith <brian@briansmith.org> Date: Wed Feb 17 18:59:19 2016 -1000 Unify AEAD and EVP code paths for AES-GCM. This change makes the AEAD and EVP code paths use the same code for AES-GCM. When AVX instructions are enabled in the assembly this will allow them to use the stitched AES-GCM implementation. Note that the stitched implementations are no-ops for small inputs (smaller than 288 bytes for encryption; smaller than 96 bytes for decryption). This means that only a handful of test cases with longish inputs actually test the stitched code. Change-Id: Iece8003d90448dcac9e0bde1f42ff102ebe1a1c9 Reviewed-on: https://boringssl-review.googlesource.com/7173 Reviewed-by: Adam Langley <agl@google.com> commit 3dbecdf6f422fe6112533bef95be41caedb80583 Author: David Benjamin <davidben@google.com> Date: Tue Feb 23 17:44:12 2016 -0500 Append to CMAKE_ASM_FLAGS rather than replace it. Otherwise we clobber things like -m32. Change-Id: I9457e4b50dc3063643c31d19c7935276b8a312a1 Reviewed-on: https://boringssl-review.googlesource.com/7209 Reviewed-by: Adam Langley <agl@google.com> commit 65f83b64d92a17b999d7db711628ee0a9a74e9d6 Author: David Benjamin <davidben@google.com> Date: Thu Feb 18 13:44:25 2016 -0500 Set --noexecstack for assembly files in the standalone build. See also upstream's 2966c2ec31e81187da3fbbe1499a6aa3acfd355f. Change-Id: Iad0a0f11accb4fa2bd93667239dd7462f9fdbd7f Reviewed-on: https://boringssl-review.googlesource.com/7180 Reviewed-by: Adam Langley <agl@google.com> commit 35be6880788d90bc2a93de5295391b001a8a6a46 Author: David Benjamin <davidben@google.com> Date: Fri Feb 19 18:47:22 2016 -0500 Enable upstream's ChaCha20 assembly for x86 and ARM (32- and 64-bit). This removes chacha_vec_arm.S and chacha_vec.c in favor of unifying on upstream's code. Upstream's is faster and this cuts down on the number of distinct codepaths. Our old scheme also didn't give vectorized code on Windows or aarch64. BoringSSL-specific modifications made to the assembly: - As usual, the shelling out to $CC is replaced with hardcoding $avx. I've tested up to the AVX2 codepath, so enable it all. - I've removed the AMD XOP code as I have not tested it. - As usual, the ARM file need the arm_arch.h include tweaked. Speed numbers follow. We can hope for further wins on these benchmarks after importing the Poly1305 assembly. x86 --- Old: Did 1422000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000433us (1421384.5 ops/sec): 22.7 MB/s Did 123000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1003803us (122534.0 ops/sec): 165.4 MB/s Did 22000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1000282us (21993.8 ops/sec): 180.2 MB/s Did 1428000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000214us (1427694.5 ops/sec): 22.8 MB/s Did 124000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1006332us (123219.8 ops/sec): 166.3 MB/s Did 22000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1020771us (21552.3 ops/sec): 176.6 MB/s New: Did 1520000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000567us (1519138.6 ops/sec): 24.3 MB/s Did 152000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1004216us (151361.9 ops/sec): 204.3 MB/s Did 31000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1009085us (30720.9 ops/sec): 251.7 MB/s Did 1797000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000141us (1796746.7 ops/sec): 28.7 MB/s Did 171000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1003204us (170453.9 ops/sec): 230.1 MB/s Did 31000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1005349us (30835.1 ops/sec): 252.6 MB/s x86_64, no AVX2 --- Old: Did 1782000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000204us (1781636.5 ops/sec): 28.5 MB/s Did 317000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1001579us (316500.2 ops/sec): 427.3 MB/s Did 62000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1012146us (61256.0 ops/sec): 501.8 MB/s Did 1778000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000220us (1777608.9 ops/sec): 28.4 MB/s Did 315000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1002886us (314093.5 ops/sec): 424.0 MB/s Did 71000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1014606us (69977.9 ops/sec): 573.3 MB/s New: Did 1866000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000019us (1865964.5 ops/sec): 29.9 MB/s Did 399000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1001017us (398594.6 ops/sec): 538.1 MB/s Did 84000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1005645us (83528.5 ops/sec): 684.3 MB/s Did 1881000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000325us (1880388.9 ops/sec): 30.1 MB/s Did 404000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1000004us (403998.4 ops/sec): 545.4 MB/s Did 85000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1010048us (84154.4 ops/sec): 689.4 MB/s x86_64, AVX2 --- Old: Did 2375000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000282us (2374330.4 ops/sec): 38.0 MB/s Did 448000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1001865us (447166.0 ops/sec): 603.7 MB/s Did 88000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1005217us (87543.3 ops/sec): 717.2 MB/s Did 2409000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000188us (2408547.2 ops/sec): 38.5 MB/s Did 446000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1001003us (445553.1 ops/sec): 601.5 MB/s Did 90000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1006722us (89399.1 ops/sec): 732.4 MB/s New: Did 2622000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000266us (2621302.7 ops/sec): 41.9 MB/s Did 794000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1000783us (793378.8 ops/sec): 1071.1 MB/s Did 173000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1000176us (172969.6 ops/sec): 1417.0 MB/s Did 2623000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000330us (2622134.7 ops/sec): 42.0 MB/s Did 783000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1000531us (782584.4 ops/sec): 1056.5 MB/s Did 174000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1000840us (173854.0 ops/sec): 1424.2 MB/s arm, Nexus 4 --- Old: Did 388550 ChaCha20-Poly1305 (16 bytes) seal operations in 1000580us (388324.8 ops/sec): 6.2 MB/s Did 90000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1003816us (89657.9 ops/sec): 121.0 MB/s Did 19000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1045750us (18168.8 ops/sec): 148.8 MB/s Did 398500 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000305us (398378.5 ops/sec): 6.4 MB/s Did 90500 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1000305us (90472.4 ops/sec): 122.1 MB/s Did 19000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1043278us (18211.8 ops/sec): 149.2 MB/s New: Did 424788 ChaCha20-Poly1305 (16 bytes) seal operations in 1000641us (424515.9 ops/sec): 6.8 MB/s Did 115000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1001526us (114824.8 ops/sec): 155.0 MB/s Did 27000 ChaCha20-Poly1305 (8192 bytes) seal operations in 1033023us (26136.9 ops/sec): 214.1 MB/s Did 447750 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000549us (447504.3 ops/sec): 7.2 MB/s Did 117500 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1001923us (117274.5 ops/sec): 158.3 MB/s Did 27000 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1025118us (26338.4 ops/sec): 215.8 MB/s aarch64, Nexus 6p (Note we didn't have aarch64 assembly before at all, and still don't have it for Poly1305. Hopefully once that's added this will be faster than the arm numbers...) --- Old: Did 145040 ChaCha20-Poly1305 (16 bytes) seal operations in 1003065us (144596.8 ops/sec): 2.3 MB/s Did 14000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1042605us (13427.9 ops/sec): 18.1 MB/s Did 2618 ChaCha20-Poly1305 (8192 bytes) seal operations in 1093241us (2394.7 ops/sec): 19.6 MB/s Did 148000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000709us (147895.1 ops/sec): 2.4 MB/s Did 14000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1047294us (13367.8 ops/sec): 18.0 MB/s Did 2607 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1090745us (2390.1 ops/sec): 19.6 MB/s New: Did 358000 ChaCha20-Poly1305 (16 bytes) seal operations in 1000769us (357724.9 ops/sec): 5.7 MB/s Did 45000 ChaCha20-Poly1305 (1350 bytes) seal operations in 1021267us (44062.9 ops/sec): 59.5 MB/s Did 8591 ChaCha20-Poly1305 (8192 bytes) seal operations in 1047136us (8204.3 ops/sec): 67.2 MB/s Did 343000 ChaCha20-Poly1305-Old (16 bytes) seal operations in 1000489us (342832.4 ops/sec): 5.5 MB/s Did 44000 ChaCha20-Poly1305-Old (1350 bytes) seal operations in 1008326us (43636.7 ops/sec): 58.9 MB/s Did 8866 ChaCha20-Poly1305-Old (8192 bytes) seal operations in 1083341us (8183.9 ops/sec): 67.0 MB/s Change-Id: I629fe195d072f2c99e8f947578fad6d70823c4c8 Reviewed-on: https://boringssl-review.googlesource.com/7202 Reviewed-by: Adam Langley <agl@google.com> commit 0182ecd346add6019e6559ea6f6e515b54c1d78f Author: David Benjamin <davidben@google.com> Date: Tue Feb 23 11:20:09 2016 -0500 Consistently use named constants in ARM assembly files. Most of the OPENSSL_armcap_P accesses in assembly use named constants from arm_arch.h, but some don't. Consistently use the constants. The dispatch really should be in C, but in the meantime, make it easier to tell what's going on. I'll send this patch upstream so we won't be carrying a diff here. Change-Id: I63c68d2351ea5ce11005813314988e32b6459526 Reviewed-on: https://boringssl-review.googlesource.com/7203 Reviewed-by: Adam Langley <agl@google.com> commit 295960044bc34fa8aeb01cbed64269330fd0cef6 Author: David Benjamin <davidben@google.com> Date: Mon Feb 22 17:32:18 2016 -0500 Fix chacha-armv4.pl. Patch taken from https://rt.openssl.org/Ticket/Display.html?id=4323. Change-Id: Icbaf8f9a0f92da48f213b251b0afa4b0d5aa627d Reviewed-on: https://boringssl-review.googlesource.com/7201 Reviewed-by: Adam Langley <agl@google.com> commit ea4d6863c7d54c96bdd3a7c1a84062c501ea1494 Author: David Benjamin <davidben@google.com> Date: Fri Feb 19 18:32:47 2016 -0500 Check in pristine copies of OpenSSL's chacha-{arm*,x86}.pl. They won't be used as-is. This is just to make the diffs easier to see. Taken from upstream's 4f16039efe3589aa4d63a6f1fab799d0cd9338ca. Change-Id: I34d8be409f9c8f15b8a6da4b2d98ba3e60aa2210 Reviewed-on: https://boringssl-review.googlesource.com/7200 Reviewed-by: Adam Langley <agl@google.com> commit b104517f1dd54e7b269ff12fac8842340bf6614b Author: Adam Langley <agl@google.com> Date: Mon Feb 22 11:48:18 2016 -0800 Add some bug references to the LICENSE file. Add references for some cases where we have explicit permission from authors to use their work. This is just to make things easy for us to find. Change-Id: I47dacc6a80f9d0c960c5b6713a8dc25e1a4e6f0b Reviewed-on: https://boringssl-review.googlesource.com/7191 Reviewed-by: David Benjamin <davidben@google.com> commit 65dcfc7f9b2ae147cf817ecad22dfcab89230d5e Author: Adam Langley <agl@google.com> Date: Mon Feb 22 09:16:57 2016 -0800 Remove CP_UTF8 code for Windows filenames. Thanks to Gisle Vanem for pointing out that this code was broken and could never have compiled. Since it has never worked, and thus has never been used, remove it. Change-Id: Ic274eaf187928765a809690eda8d790b79f939a5 Reviewed-on: https://boringssl-review.googlesource.com/7190 Reviewed-by: David Benjamin <davidben@google.com>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/CMakeLists.txt55
-rw-r--r--crypto/aes/mode_wrappers.c8
-rw-r--r--crypto/asn1/CMakeLists.txt4
-rw-r--r--crypto/asn1/a_bytes.c4
-rw-r--r--crypto/asn1/a_d2i_fp.c41
-rw-r--r--crypto/asn1/a_gentm.c2
-rw-r--r--crypto/asn1/a_strnid.c1
-rw-r--r--crypto/asn1/a_type.c2
-rw-r--r--crypto/asn1/a_utctm.c2
-rw-r--r--crypto/asn1/asn1_lib.c26
-rw-r--r--crypto/asn1/asn1_locl.h10
-rw-r--r--crypto/asn1/asn1_par.c322
-rw-r--r--crypto/asn1/asn1_test.cc32
-rw-r--r--crypto/asn1/bio_asn1.c477
-rw-r--r--crypto/asn1/bio_ndef.c251
-rw-r--r--crypto/asn1/t_pkey.c110
-rw-r--r--crypto/asn1/tasn_dec.c16
-rw-r--r--crypto/asn1/tasn_enc.c2
-rw-r--r--crypto/asn1/tasn_prn.c596
-rw-r--r--crypto/base64/base64.c526
-rw-r--r--crypto/base64/base64_test.cc354
-rw-r--r--crypto/bio/bio_mem.c5
-rw-r--r--crypto/bio/bio_test.cc6
-rw-r--r--crypto/bio/connect.c15
-rw-r--r--crypto/bio/fd.c37
-rw-r--r--crypto/bio/file.c40
-rw-r--r--crypto/bio/internal.h3
-rw-r--r--crypto/bio/pair.c2
-rw-r--r--crypto/bio/socket.c12
-rw-r--r--crypto/bio/socket_helper.c4
-rw-r--r--crypto/bn/asm/armv4-mont.pl2
-rwxr-xr-x[-rw-r--r--]crypto/bn/asm/rsaz-avx2.pl219
-rwxr-xr-x[-rw-r--r--]crypto/bn/asm/rsaz-x86_64.pl375
-rw-r--r--crypto/bn/asm/x86_64-gcc.c8
-rwxr-xr-x[-rw-r--r--]crypto/bn/asm/x86_64-mont.pl227
-rwxr-xr-x[-rw-r--r--]crypto/bn/asm/x86_64-mont5.pl1276
-rw-r--r--crypto/bn/bn.c12
-rw-r--r--crypto/bn/bn_test.cc6
-rw-r--r--crypto/bn/cmp.c14
-rw-r--r--crypto/bn/convert.c13
-rw-r--r--crypto/bn/div.c206
-rw-r--r--crypto/bn/exponentiation.c465
-rw-r--r--crypto/bn/gcd.c27
-rw-r--r--crypto/bn/generic.c80
-rw-r--r--crypto/bn/internal.h10
-rw-r--r--crypto/bn/montgomery.c118
-rw-r--r--crypto/bn/mul.c3
-rw-r--r--crypto/buf/buf.c46
-rw-r--r--crypto/bytestring/ber.c1
-rw-r--r--crypto/bytestring/bytestring_test.cc7
-rw-r--r--crypto/bytestring/cbs.c29
-rw-r--r--crypto/chacha/CMakeLists.txt46
-rwxr-xr-xcrypto/chacha/asm/chacha-armv4.pl1151
-rwxr-xr-xcrypto/chacha/asm/chacha-armv8.pl1127
-rwxr-xr-xcrypto/chacha/asm/chacha-x86.pl753
-rwxr-xr-xcrypto/chacha/asm/chacha-x86_64.pl1767
-rw-r--r--crypto/chacha/chacha.c (renamed from crypto/chacha/chacha_generic.c)70
-rw-r--r--crypto/chacha/chacha_test.cc248
-rw-r--r--crypto/chacha/chacha_vec.c328
-rw-r--r--crypto/chacha/chacha_vec_arm.S1447
-rw-r--r--crypto/chacha/chacha_vec_arm_generate.go153
-rw-r--r--crypto/cipher/aead.c25
-rw-r--r--crypto/cipher/aead_test.cc172
-rw-r--r--crypto/cipher/cipher.c4
-rw-r--r--crypto/cipher/cipher_test.cc41
-rw-r--r--crypto/cipher/e_aes.c80
-rw-r--r--crypto/cipher/e_chacha20poly1305.c8
-rw-r--r--crypto/cipher/e_des.c2
-rw-r--r--crypto/cipher/e_null.c2
-rw-r--r--crypto/cipher/e_rc2.c2
-rw-r--r--crypto/cipher/e_rc4.c2
-rw-r--r--crypto/cipher/test/aes_128_gcm_tests.txt2
-rw-r--r--crypto/cipher/test/aes_256_gcm_tests.txt2
-rw-r--r--crypto/cipher/test/cipher_test.txt597
-rw-r--r--crypto/cipher/test/cipher_tests.txt613
-rw-r--r--crypto/cipher/tls_cbc.c42
-rw-r--r--crypto/cmac/cmac_test.cc2
-rw-r--r--crypto/conf/conf.c3
-rw-r--r--crypto/cpu-aarch64-linux.c61
-rw-r--r--crypto/cpu-arm-asm.S32
-rw-r--r--crypto/cpu-arm-linux.c360
-rw-r--r--crypto/cpu-arm.c161
-rw-r--r--crypto/cpu-intel.c8
-rw-r--r--crypto/crypto.c24
-rw-r--r--crypto/curve25519/CMakeLists.txt10
-rw-r--r--crypto/curve25519/curve25519.c508
-rw-r--r--crypto/curve25519/internal.h64
-rw-r--r--crypto/curve25519/spake25519.c464
-rw-r--r--crypto/curve25519/spake25519_test.cc169
-rw-r--r--crypto/curve25519/x25519-x86_64.c21
-rw-r--r--crypto/dh/dh.c19
-rw-r--r--crypto/dh/dh_asn1.c116
-rw-r--r--crypto/dh/dh_test.cc93
-rw-r--r--crypto/digest/digest.c6
-rw-r--r--crypto/directory.h66
-rw-r--r--crypto/directory_posix.c108
-rw-r--r--crypto/directory_win.c144
-rw-r--r--crypto/dsa/dsa.c17
-rw-r--r--crypto/dsa/dsa_asn1.c4
-rwxr-xr-x[-rw-r--r--]crypto/ec/asm/p256-x86_64-asm.pl11
-rw-r--r--crypto/ec/ec.c76
-rw-r--r--crypto/ec/ec_asn1.c134
-rw-r--r--crypto/ec/ec_key.c14
-rw-r--r--crypto/ec/ec_montgomery.c128
-rw-r--r--crypto/ec/ec_test.cc127
-rw-r--r--crypto/ec/example_mul.c4
-rw-r--r--crypto/ec/internal.h20
-rw-r--r--crypto/ec/oct.c22
-rw-r--r--crypto/ec/p224-64.c130
-rw-r--r--crypto/ec/p256-64.c205
-rw-r--r--crypto/ec/p256-x86_64.c45
-rw-r--r--crypto/ec/simple.c257
-rw-r--r--crypto/ec/util-64.c74
-rw-r--r--crypto/ecdsa/ecdsa.c9
-rw-r--r--crypto/ecdsa/ecdsa_asn1.c1
-rw-r--r--crypto/ecdsa/ecdsa_test.cc2
-rw-r--r--crypto/err/asn1.errordata163
-rw-r--r--crypto/err/dh.errordata2
-rw-r--r--crypto/err/err.c6
-rw-r--r--crypto/err/err_data_generate.go9
-rw-r--r--crypto/err/evp.errordata73
-rw-r--r--crypto/err/rsa.errordata92
-rw-r--r--crypto/err/ssl.errordata1
-rw-r--r--crypto/err/x509.errordata41
-rw-r--r--crypto/evp/CMakeLists.txt2
-rw-r--r--crypto/evp/evp.c67
-rw-r--r--crypto/evp/evp_asn1.c230
-rw-r--r--crypto/evp/evp_ctx.c5
-rw-r--r--crypto/evp/evp_extra_test.cc365
-rw-r--r--crypto/evp/evp_test.cc13
-rw-r--r--crypto/evp/evp_tests.txt5
-rw-r--r--crypto/evp/internal.h50
-rw-r--r--crypto/evp/p_dsa_asn1.c165
-rw-r--r--crypto/evp/p_ec.c2
-rw-r--r--crypto/evp/p_ec_asn1.c192
-rw-r--r--crypto/evp/p_rsa.c2
-rw-r--r--crypto/evp/p_rsa_asn1.c558
-rw-r--r--crypto/evp/pbkdf_test.cc1
-rw-r--r--crypto/evp/print.c527
-rw-r--r--crypto/ex_data.c4
-rw-r--r--crypto/hkdf/hkdf.c55
-rw-r--r--crypto/hkdf/hkdf_test.c66
-rw-r--r--crypto/hmac/hmac.c11
-rw-r--r--crypto/internal.h110
-rw-r--r--crypto/lhash/lhash_test.c4
-rw-r--r--crypto/md4/md4.c9
-rw-r--r--crypto/mem.c21
-rw-r--r--crypto/modes/asm/aesni-gcm-x86_64.pl46
-rw-r--r--crypto/modes/asm/ghash-x86_64.pl5
-rw-r--r--crypto/modes/cfb.c11
-rw-r--r--crypto/modes/ctr.c28
-rw-r--r--crypto/modes/gcm.c88
-rw-r--r--crypto/modes/gcm_test.c6
-rw-r--r--crypto/modes/internal.h42
-rw-r--r--crypto/modes/ofb.c6
-rw-r--r--crypto/newhope/CMakeLists.txt42
-rw-r--r--crypto/newhope/error_correction.c131
-rw-r--r--crypto/newhope/internal.h71
-rw-r--r--crypto/newhope/newhope.c174
-rw-r--r--crypto/newhope/newhope_statistical_test.cc156
-rw-r--r--crypto/newhope/newhope_test.cc142
-rw-r--r--crypto/newhope/newhope_tests.txt206
-rw-r--r--crypto/newhope/newhope_vectors_test.cc122
-rw-r--r--crypto/newhope/ntt.c148
-rw-r--r--crypto/newhope/poly.c189
-rw-r--r--crypto/newhope/precomp.c306
-rw-r--r--crypto/newhope/reduce.c42
-rw-r--r--crypto/obj/CMakeLists.txt13
-rw-r--r--crypto/obj/README12
-rw-r--r--crypto/obj/obj.c20
-rw-r--r--crypto/obj/obj_dat.h14
-rw-r--r--crypto/obj/obj_dat.pl6
-rw-r--r--crypto/obj/obj_mac.num3
-rw-r--r--crypto/obj/obj_test.cc106
-rw-r--r--crypto/obj/objects.pl40
-rw-r--r--crypto/obj/objects.txt5
-rw-r--r--crypto/pem/pem_lib.c49
-rw-r--r--crypto/pem/pem_pkey.c29
-rwxr-xr-xcrypto/perlasm/x86_64-xlate.pl9
-rw-r--r--crypto/perlasm/x86gas.pl2
-rw-r--r--crypto/pkcs8/CMakeLists.txt2
-rw-r--r--crypto/pkcs8/p5_pbe.c1
-rw-r--r--crypto/pkcs8/p5_pbev2.c1
-rw-r--r--crypto/pkcs8/pkcs12_test.cc2
-rw-r--r--crypto/pkcs8/pkcs8.c182
-rwxr-xr-xcrypto/poly1305/asm/poly1305-armv4.pl1216
-rwxr-xr-xcrypto/poly1305/asm/poly1305-armv8.pl925
-rwxr-xr-xcrypto/poly1305/asm/poly1305-x86.pl1788
-rwxr-xr-xcrypto/poly1305/asm/poly1305-x86_64.pl2235
-rw-r--r--crypto/poly1305/internal.h40
-rw-r--r--crypto/poly1305/poly1305.c17
-rw-r--r--crypto/poly1305/poly1305_arm.c1
-rw-r--r--crypto/poly1305/poly1305_test.cc59
-rw-r--r--crypto/poly1305/poly1305_test.txt52
-rw-r--r--crypto/poly1305/poly1305_tests.txt159
-rw-r--r--crypto/poly1305/poly1305_vec.c6
-rw-r--r--crypto/rand/CMakeLists.txt1
-rw-r--r--crypto/rand/deterministic.c49
-rw-r--r--crypto/rand/rand.c3
-rw-r--r--crypto/rand/urandom.c10
-rw-r--r--crypto/rand/windows.c8
-rw-r--r--crypto/rc4/asm/rc4-586.pl26
-rw-r--r--crypto/refcount_lock.c4
-rw-r--r--crypto/rsa/blinding.c299
-rw-r--r--crypto/rsa/internal.h18
-rw-r--r--crypto/rsa/padding.c15
-rw-r--r--crypto/rsa/rsa.c28
-rw-r--r--crypto/rsa/rsa_asn1.c13
-rw-r--r--crypto/rsa/rsa_impl.c253
-rw-r--r--crypto/rsa/rsa_test.cc62
-rw-r--r--crypto/sha/asm/sha512-armv4.pl2
-rw-r--r--crypto/sha/sha256.c4
-rw-r--r--crypto/sha/sha512.c4
-rw-r--r--crypto/stack/make_macros.sh9
-rw-r--r--crypto/stack/stack.c2
-rw-r--r--crypto/test/file_test.cc16
-rw-r--r--crypto/test/file_test.h10
-rw-r--r--crypto/test/scoped_types.h7
-rw-r--r--crypto/thread.c25
-rw-r--r--crypto/thread_none.c8
-rw-r--r--crypto/thread_pthread.c19
-rw-r--r--crypto/thread_test.c25
-rw-r--r--crypto/thread_win.c119
-rw-r--r--crypto/x509/CMakeLists.txt2
-rw-r--r--crypto/x509/a_sign.c6
-rw-r--r--crypto/x509/a_verify.c4
-rw-r--r--crypto/x509/algorithm.c (renamed from crypto/evp/algorithm.c)90
-rw-r--r--crypto/x509/asn1_gen.c3
-rw-r--r--crypto/x509/by_dir.c10
-rw-r--r--crypto/x509/internal.h66
-rw-r--r--crypto/x509/pkcs7_test.c20
-rw-r--r--crypto/x509/rsa_pss.c385
-rw-r--r--crypto/x509/t_x509.c22
-rw-r--r--crypto/x509/x509.c5
-rw-r--r--crypto/x509/x509_lu.c70
-rw-r--r--crypto/x509/x509_obj.c21
-rw-r--r--crypto/x509/x509_test.cc194
-rw-r--r--crypto/x509/x509_txt.c5
-rw-r--r--crypto/x509/x509_vfy.c59
-rw-r--r--crypto/x509/x_crl.c4
-rw-r--r--crypto/x509/x_name.c31
-rw-r--r--crypto/x509/x_pubkey.c11
-rw-r--r--crypto/x509/x_x509.c68
-rw-r--r--crypto/x509v3/pcy_cache.c4
-rw-r--r--crypto/x509v3/tab_test.c1
-rw-r--r--crypto/x509v3/v3_conf.c3
-rw-r--r--crypto/x509v3/v3_cpols.c5
-rw-r--r--crypto/x509v3/v3_prn.c3
-rw-r--r--crypto/x509v3/v3_purp.c4
-rw-r--r--crypto/x509v3/v3_utl.c3
-rw-r--r--crypto/x509v3/v3name_test.c10
251 files changed, 21704 insertions, 10762 deletions
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt
index 23a1a505..94e47ea1 100644
--- a/crypto/CMakeLists.txt
+++ b/crypto/CMakeLists.txt
@@ -22,6 +22,7 @@ elseif(UNIX)
endif()
set(ASM_EXT S)
enable_language(ASM)
+ set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,--noexecstack")
else()
if (CMAKE_CL_64)
message("Using nasm")
@@ -53,39 +54,6 @@ function(perlasm dest src)
)
endfunction()
-if (${ARCH} STREQUAL "x86_64")
- set(
- CRYPTO_ARCH_SOURCES
-
- cpu-intel.c
- )
-endif()
-
-if (${ARCH} STREQUAL "x86")
- set(
- CRYPTO_ARCH_SOURCES
-
- cpu-intel.c
- )
-endif()
-
-if (${ARCH} STREQUAL "arm")
- set(
- CRYPTO_ARCH_SOURCES
-
- cpu-arm.c
- cpu-arm-asm.S
- )
-endif()
-
-if (${ARCH} STREQUAL "aarch64")
- set(
- CRYPTO_ARCH_SOURCES
-
- cpu-arm.c
- )
-endif()
-
# Level 0.1 - depends on nothing outside this set.
add_subdirectory(stack)
add_subdirectory(lhash)
@@ -106,6 +74,7 @@ add_subdirectory(conf)
add_subdirectory(chacha)
add_subdirectory(poly1305)
add_subdirectory(curve25519)
+add_subdirectory(newhope)
# Level 1, depends only on 0.*
add_subdirectory(digest)
@@ -182,16 +151,19 @@ set(
$<TARGET_OBJECTS:pem>
$<TARGET_OBJECTS:x509>
$<TARGET_OBJECTS:x509v3>
- $<TARGET_OBJECTS:pkcs8>
+ $<TARGET_OBJECTS:pkcs8_lib>
+ $<TARGET_OBJECTS:newhope>
PARENT_SCOPE
)
add_library(
crypto-objects OBJECT
+ cpu-aarch64-linux.c
+ cpu-arm.c
+ cpu-arm-linux.c
+ cpu-intel.c
crypto.c
- directory_posix.c
- directory_win.c
ex_data.c
mem.c
refcount_c11.c
@@ -210,9 +182,11 @@ add_library(
add_library(
crypto
+ cpu-aarch64-linux.c
+ cpu-arm.c
+ cpu-arm-linux.c
+ cpu-intel.c
crypto.c
- directory_posix.c
- directory_win.c
ex_data.c
mem.c
refcount_c11.c
@@ -223,8 +197,6 @@ add_library(
thread_win.c
time_support.c
- ${CRYPTO_ARCH_SOURCES}
-
$<TARGET_OBJECTS:stack>
$<TARGET_OBJECTS:lhash>
$<TARGET_OBJECTS:err>
@@ -263,7 +235,8 @@ add_library(
$<TARGET_OBJECTS:pem>
$<TARGET_OBJECTS:x509>
$<TARGET_OBJECTS:x509v3>
- $<TARGET_OBJECTS:pkcs8>
+ $<TARGET_OBJECTS:pkcs8_lib>
+ $<TARGET_OBJECTS:newhope>
)
if(NOT MSVC AND NOT ANDROID)
diff --git a/crypto/aes/mode_wrappers.c b/crypto/aes/mode_wrappers.c
index dc657dcd..4929920f 100644
--- a/crypto/aes/mode_wrappers.c
+++ b/crypto/aes/mode_wrappers.c
@@ -96,13 +96,17 @@ void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len,
void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t length,
const AES_KEY *key, uint8_t *ivec, int *num) {
- CRYPTO_ofb128_encrypt(in, out, length, key, ivec, num,
+ unsigned num_u = (unsigned)(*num);
+ CRYPTO_ofb128_encrypt(in, out, length, key, ivec, &num_u,
(block128_f)AES_encrypt);
+ *num = (int)num_u;
}
void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t length,
const AES_KEY *key, uint8_t *ivec, int *num,
int enc) {
- CRYPTO_cfb128_encrypt(in, out, length, key, ivec, num, enc,
+ unsigned num_u = (unsigned)(*num);
+ CRYPTO_cfb128_encrypt(in, out, length, key, ivec, &num_u, enc,
(block128_f)AES_encrypt);
+ *num = (int)num_u;
}
diff --git a/crypto/asn1/CMakeLists.txt b/crypto/asn1/CMakeLists.txt
index bd16f872..90fe01f5 100644
--- a/crypto/asn1/CMakeLists.txt
+++ b/crypto/asn1/CMakeLists.txt
@@ -26,18 +26,14 @@ add_library(
asn1_lib.c
asn1_par.c
asn_pack.c
- bio_asn1.c
- bio_ndef.c
f_enum.c
f_int.c
f_string.c
t_bitst.c
- t_pkey.c
tasn_dec.c
tasn_enc.c
tasn_fre.c
tasn_new.c
- tasn_prn.c
tasn_typ.c
tasn_utl.c
x_bignum.c
diff --git a/crypto/asn1/a_bytes.c b/crypto/asn1/a_bytes.c
index 7e2f85dc..e6b2f2e9 100644
--- a/crypto/asn1/a_bytes.c
+++ b/crypto/asn1/a_bytes.c
@@ -202,13 +202,13 @@ ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp,
} else {
if (len != 0) {
if ((ret->length < len) || (ret->data == NULL)) {
- if (ret->data != NULL)
- OPENSSL_free(ret->data);
s = (unsigned char *)OPENSSL_malloc((int)len + 1);
if (s == NULL) {
i = ERR_R_MALLOC_FAILURE;
goto err;
}
+ if (ret->data != NULL)
+ OPENSSL_free(ret->data);
} else
s = ret->data;
memcpy(s, p, (int)len);
diff --git a/crypto/asn1/a_d2i_fp.c b/crypto/asn1/a_d2i_fp.c
index f8845d8a..b5449719 100644
--- a/crypto/asn1/a_d2i_fp.c
+++ b/crypto/asn1/a_d2i_fp.c
@@ -141,6 +141,7 @@ void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
#endif
#define HEADER_SIZE 8
+#define ASN1_CHUNK_INITIAL_SIZE (16 * 1024)
static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
{
BUF_MEM *b;
@@ -217,28 +218,42 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
/* suck in c.slen bytes of data */
want = c.slen;
if (want > (len - off)) {
+ size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE;
want -= (len - off);
if (want > INT_MAX /* BIO_read takes an int length */ ||
len + want < len) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
goto err;
}
- if (!BUF_MEM_grow_clean(b, len + want)) {
- OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
- goto err;
- }
while (want > 0) {
- i = BIO_read(in, &(b->data[len]), want);
- if (i <= 0) {
- OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
- goto err;
- }
/*
- * This can't overflow because |len+want| didn't
- * overflow.
+ * Read content in chunks of increasing size
+ * so we can return an error for EOF without
+ * having to allocate the entire content length
+ * in one go.
*/
- len += i;
- want -= i;
+ size_t chunk = want > chunk_max ? chunk_max : want;
+
+ if (!BUF_MEM_grow_clean(b, len + chunk)) {
+ OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ want -= chunk;
+ while (chunk > 0) {
+ i = BIO_read(in, &(b->data[len]), chunk);
+ if (i <= 0) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
+ goto err;
+ }
+ /*
+ * This can't overflow because |len+want| didn't
+ * overflow.
+ */
+ len += i;
+ chunk -= i;
+ }
+ if (chunk_max < INT_MAX/2)
+ chunk_max *= 2;
}
}
if (off + c.slen < off) {
diff --git a/crypto/asn1/a_gentm.c b/crypto/asn1/a_gentm.c
index 09e4f171..ee6b3db5 100644
--- a/crypto/asn1/a_gentm.c
+++ b/crypto/asn1/a_gentm.c
@@ -63,6 +63,8 @@
#include <openssl/mem.h>
#include <openssl/time_support.h>
+#include "asn1_locl.h"
+
int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d)
{
static const int min[9] = { 0, 0, 1, 1, 0, 0, 0, 0, 0 };
diff --git a/crypto/asn1/a_strnid.c b/crypto/asn1/a_strnid.c
index ba1224ef..c558bce6 100644
--- a/crypto/asn1/a_strnid.c
+++ b/crypto/asn1/a_strnid.c
@@ -247,6 +247,7 @@ int ASN1_STRING_TABLE_add(int nid,
}
tmp->flags = flags | STABLE_FLAGS_MALLOC;
tmp->nid = nid;
+ tmp->minsize = tmp->maxsize = -1;
new_nid = 1;
} else
tmp->flags = (tmp->flags & STABLE_FLAGS_MALLOC) | flags;
diff --git a/crypto/asn1/a_type.c b/crypto/asn1/a_type.c
index ecd47342..734ff8b4 100644
--- a/crypto/asn1/a_type.c
+++ b/crypto/asn1/a_type.c
@@ -122,9 +122,7 @@ int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b)
result = a->value.boolean - b->value.boolean;
break;
case V_ASN1_INTEGER:
- case V_ASN1_NEG_INTEGER:
case V_ASN1_ENUMERATED:
- case V_ASN1_NEG_ENUMERATED:
case V_ASN1_BIT_STRING:
case V_ASN1_OCTET_STRING:
case V_ASN1_SEQUENCE:
diff --git a/crypto/asn1/a_utctm.c b/crypto/asn1/a_utctm.c
index 35eb1c9b..5a55bd24 100644
--- a/crypto/asn1/a_utctm.c
+++ b/crypto/asn1/a_utctm.c
@@ -63,6 +63,8 @@
#include <openssl/mem.h>
#include <openssl/time_support.h>
+#include "asn1_locl.h"
+
#if 0
int i2d_ASN1_UTCTIME(ASN1_UTCTIME *a, unsigned char **pp)
{
diff --git a/crypto/asn1/asn1_lib.c b/crypto/asn1/asn1_lib.c
index 0025a676..b637e795 100644
--- a/crypto/asn1/asn1_lib.c
+++ b/crypto/asn1/asn1_lib.c
@@ -63,9 +63,15 @@
#include <openssl/err.h>
#include <openssl/mem.h>
-/* Cross-module errors from crypto/x509/i2d_pr.c */
+/* Cross-module errors from crypto/x509/i2d_pr.c. */
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_PUBLIC_KEY_TYPE);
+/* Cross-module errors from crypto/x509/algorithm.c. */
+OPENSSL_DECLARE_ERROR_REASON(ASN1, CONTEXT_NOT_INITIALISED);
+OPENSSL_DECLARE_ERROR_REASON(ASN1, DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
+OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
+OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_SIGNATURE_ALGORITHM);
+OPENSSL_DECLARE_ERROR_REASON(ASN1, WRONG_PUBLIC_KEY_TYPE);
/*
* Cross-module errors from crypto/x509/asn1_gen.c. TODO(davidben): Remove
* these once asn1_gen.c is gone.
@@ -95,7 +101,7 @@ OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_TAG);
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_TYPE);
static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
- int max);
+ long max);
static void asn1_put_length(unsigned char **pp, int length);
static int _asn1_check_infinite_end(const unsigned char **p, long len)
@@ -167,7 +173,7 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
*ptag = tag;
*pclass = xclass;
- if (!asn1_get_length(&p, &inf, plength, (int)max))
+ if (!asn1_get_length(&p, &inf, plength, max))
goto err;
if (inf && !(ret & V_ASN1_CONSTRUCTED))
@@ -195,14 +201,14 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
}
static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
- int max)
+ long max)
{
const unsigned char *p = *pp;
unsigned long ret = 0;
- unsigned int i;
+ unsigned long i;
if (max-- < 1)
- return (0);
+ return 0;
if (*p == 0x80) {
*inf = 1;
ret = 0;
@@ -211,15 +217,11 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
*inf = 0;
i = *p & 0x7f;
if (*(p++) & 0x80) {
- if (i > sizeof(long))
+ if (i > sizeof(ret) || max < (long)i)
return 0;
- if (max-- == 0)
- return (0);
while (i-- > 0) {
ret <<= 8L;
ret |= *(p++);
- if (max-- == 0)
- return (0);
}
} else
ret = i;
@@ -228,7 +230,7 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
return 0;
*pp = p;
*rl = (long)ret;
- return (1);
+ return 1;
}
/*
diff --git a/crypto/asn1/asn1_locl.h b/crypto/asn1/asn1_locl.h
index 49eceb6b..982bfd60 100644
--- a/crypto/asn1/asn1_locl.h
+++ b/crypto/asn1/asn1_locl.h
@@ -61,13 +61,3 @@
int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d);
-
-/* ASN1 print context structure */
-
-struct asn1_pctx_st {
- unsigned long flags;
- unsigned long nm_flags;
- unsigned long cert_flags;
- unsigned long oid_flags;
- unsigned long str_flags;
-} /* ASN1_PCTX */ ;
diff --git a/crypto/asn1/asn1_par.c b/crypto/asn1/asn1_par.c
index fbdaae84..b1a01eda 100644
--- a/crypto/asn1/asn1_par.c
+++ b/crypto/asn1/asn1_par.c
@@ -56,328 +56,6 @@
#include <openssl/asn1.h>
-#include <openssl/bio.h>
-#include <openssl/err.h>
-#include <openssl/mem.h>
-
-#define ASN1_PARSE_MAXDEPTH 128
-
-static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed,
- int indent);
-static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
- int offset, int depth, int indent, int dump);
-static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed,
- int indent)
-{
- static const char fmt[] = "%-18s";
- char str[128];
- const char *p;
-
- if (constructed & V_ASN1_CONSTRUCTED)
- p = "cons: ";
- else
- p = "prim: ";
- if (BIO_write(bp, p, 6) < 6)
- goto err;
- BIO_indent(bp, indent, 128);
-
- p = str;
- if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
- BIO_snprintf(str, sizeof str, "priv [ %d ] ", tag);
- else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
- BIO_snprintf(str, sizeof str, "cont [ %d ]", tag);
- else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
- BIO_snprintf(str, sizeof str, "appl [ %d ]", tag);
- else if (tag > 30)
- BIO_snprintf(str, sizeof str, "<ASN1 %d>", tag);
- else
- p = ASN1_tag2str(tag);
-
- if (BIO_printf(bp, fmt, p) <= 0)
- goto err;
- return (1);
- err:
- return (0);
-}
-
-int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent)
-{
- return (asn1_parse2(bp, &pp, len, 0, 0, indent, 0));
-}
-
-int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent,
- int dump)
-{
- return (asn1_parse2(bp, &pp, len, 0, 0, indent, dump));
-}
-
-static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
- int offset, int depth, int indent, int dump)
-{
- const unsigned char *p, *ep, *tot, *op, *opp;
- long len;
- int tag, xclass, ret = 0;
- int nl, hl, j, r;
- ASN1_OBJECT *o = NULL;
- ASN1_OCTET_STRING *os = NULL;
- /* ASN1_BMPSTRING *bmp=NULL; */
- int dump_indent;
-
-#if 0
- dump_indent = indent;
-#else
- dump_indent = 6; /* Because we know BIO_dump_indent() */
-#endif
-
- if (depth > ASN1_PARSE_MAXDEPTH) {
- BIO_puts(bp, "BAD RECURSION DEPTH\n");
- return 0;
- }
-
- p = *pp;
- tot = p + length;
- op = p - 1;
- while ((p < tot) && (op < p)) {
- op = p;
- j = ASN1_get_object(&p, &len, &tag, &xclass, length);
-#ifdef LINT
- j = j;
-#endif
- if (j & 0x80) {
- if (BIO_puts(bp, "Error in encoding\n") <= 0)
- goto end;
- ret = 0;
- goto end;
- }
- hl = (p - op);
- length -= hl;
- /*
- * if j == 0x21 it is a constructed indefinite length object
- */
- if (BIO_printf(bp, "%5ld:", (long)offset + (long)(op - *pp))
- <= 0)
- goto end;
-
- if (j != (V_ASN1_CONSTRUCTED | 1)) {
- if (BIO_printf(bp, "d=%-2d hl=%ld l=%4ld ",
- depth, (long)hl, len) <= 0)
- goto end;
- } else {
- if (BIO_printf(bp, "d=%-2d hl=%ld l=inf ", depth, (long)hl) <= 0)
- goto end;
- }
- if (!asn1_print_info(bp, tag, xclass, j, (indent) ? depth : 0))
- goto end;
- if (j & V_ASN1_CONSTRUCTED) {
- ep = p + len;
- if (BIO_puts(bp, "\n") <= 0)
- goto end;
- if (len > length) {
- BIO_printf(bp, "length is greater than %ld\n", length);
- ret = 0;
- goto end;
- }
- if ((j == 0x21) && (len == 0)) {
- for (;;) {
- r = asn1_parse2(bp, &p, (long)(tot - p),
- offset + (p - *pp), depth + 1,
- indent, dump);
- if (r == 0) {
- ret = 0;
- goto end;
- }
- if ((r == 2) || (p >= tot))
- break;
- }
- } else
- while (p < ep) {
- r = asn1_parse2(bp, &p, (long)len,
- offset + (p - *pp), depth + 1,
- indent, dump);
- if (r == 0) {
- ret = 0;
- goto end;
- }
- }
- } else if (xclass != 0) {
- p += len;
- if (BIO_puts(bp, "\n") <= 0)
- goto end;
- } else {
- nl = 0;
- if ((tag == V_ASN1_PRINTABLESTRING) ||
- (tag == V_ASN1_T61STRING) ||
- (tag == V_ASN1_IA5STRING) ||
- (tag == V_ASN1_VISIBLESTRING) ||
- (tag == V_ASN1_NUMERICSTRING) ||
- (tag == V_ASN1_UTF8STRING) ||
- (tag == V_ASN1_UTCTIME) || (tag == V_ASN1_GENERALIZEDTIME)) {
- if (BIO_puts(bp, ":") <= 0)
- goto end;
- if ((len > 0) && BIO_write(bp, (const char *)p, (int)len)
- != (int)len)
- goto end;
- } else if (tag == V_ASN1_OBJECT) {
- opp = op;
- if (d2i_ASN1_OBJECT(&o, &opp, len + hl) != NULL) {
- if (BIO_puts(bp, ":") <= 0)
- goto end;
- i2a_ASN1_OBJECT(bp, o);
- } else {
- if (BIO_puts(bp, ":BAD OBJECT") <= 0)
- goto end;
- }
- } else if (tag == V_ASN1_BOOLEAN) {
- int ii;
-
- opp = op;
- ii = d2i_ASN1_BOOLEAN(NULL, &opp, len + hl);
- if (ii < 0) {
- if (BIO_puts(bp, "Bad boolean\n") <= 0)
- goto end;
- }
- BIO_printf(bp, ":%d", ii);
- } else if (tag == V_ASN1_BMPSTRING) {
- /* do the BMP thang */
- } else if (tag == V_ASN1_OCTET_STRING) {
- int i, printable = 1;
-
- opp = op;
- os = d2i_ASN1_OCTET_STRING(NULL, &opp, len + hl);
- if (os != NULL && os->length > 0) {
- opp = os->data;
- /*
- * testing whether the octet string is printable
- */
- for (i = 0; i < os->length; i++) {
- if (((opp[i] < ' ') &&
- (opp[i] != '\n') &&
- (opp[i] != '\r') &&
- (opp[i] != '\t')) || (opp[i] > '~')) {
- printable = 0;
- break;
- }
- }
- if (printable)
- /* printable string */
- {
- if (BIO_puts(bp, ":") <= 0)
- goto end;
- if (BIO_write(bp, (const char *)opp, os->length) <= 0)
- goto end;
- } else if (!dump)
- /*
- * not printable => print octet string as hex dump
- */
- {
- if (BIO_puts(bp, "[HEX DUMP]:") <= 0)
- goto end;
- for (i = 0; i < os->length; i++) {
- if (BIO_printf(bp, "%02X", opp[i]) <= 0)
- goto end;
- }
- } else
- /* print the normal dump */
- {
- if (!nl) {
- if (BIO_puts(bp, "\n") <= 0)
- goto end;
- }
- if (!BIO_hexdump(bp, opp,
- ((dump == -1 || dump >
- os->length) ? os->length : dump),
- dump_indent))
- goto end;
- nl = 1;
- }
- }
- if (os != NULL) {
- M_ASN1_OCTET_STRING_free(os);
- os = NULL;
- }
- } else if (tag == V_ASN1_INTEGER) {
- ASN1_INTEGER *bs;
- int i;
-
- opp = op;
- bs = d2i_ASN1_INTEGER(NULL, &opp, len + hl);
- if (bs != NULL) {
- if (BIO_puts(bp, ":") <= 0)
- goto end;
- if (bs->type == V_ASN1_NEG_INTEGER)
- if (BIO_puts(bp, "-") <= 0)
- goto end;
- for (i = 0; i < bs->length; i++) {
- if (BIO_printf(bp, "%02X", bs->data[i]) <= 0)
- goto end;
- }
- if (bs->length == 0) {
- if (BIO_puts(bp, "00") <= 0)
- goto end;
- }
- } else {
- if (BIO_puts(bp, "BAD INTEGER") <= 0)
- goto end;
- }
- M_ASN1_INTEGER_free(bs);
- } else if (tag == V_ASN1_ENUMERATED) {
- ASN1_ENUMERATED *bs;
- int i;
-
- opp = op;
- bs = d2i_ASN1_ENUMERATED(NULL, &opp, len + hl);
- if (bs != NULL) {
- if (BIO_puts(bp, ":") <= 0)
- goto end;
- if (bs->type == V_ASN1_NEG_ENUMERATED)
- if (BIO_puts(bp, "-") <= 0)
- goto end;
- for (i = 0; i < bs->length; i++) {
- if (BIO_printf(bp, "%02X", bs->data[i]) <= 0)
- goto end;
- }
- if (bs->length == 0) {
- if (BIO_puts(bp, "00") <= 0)
- goto end;
- }
- } else {
- if (BIO_puts(bp, "BAD ENUMERATED") <= 0)
- goto end;
- }
- M_ASN1_ENUMERATED_free(bs);
- } else if (len > 0 && dump) {
- if (!nl) {
- if (BIO_puts(bp, "\n") <= 0)
- goto end;
- }
- if (!BIO_hexdump(bp, p,
- ((dump == -1 || dump > len) ? len : dump),
- dump_indent))
- goto end;
- nl = 1;
- }
-
- if (!nl) {
- if (BIO_puts(bp, "\n") <= 0)
- goto end;
- }
- p += len;
- if ((tag == V_ASN1_EOC) && (xclass == 0)) {
- ret = 2; /* End of sequence */
- goto end;
- }
- }
- length -= len;
- }
- ret = 1;
- end:
- if (o != NULL)
- ASN1_OBJECT_free(o);
- if (os != NULL)
- M_ASN1_OCTET_STRING_free(os);
- *pp = p;
- return (ret);
-}
const char *ASN1_tag2str(int tag)
{
diff --git a/crypto/asn1/asn1_test.cc b/crypto/asn1/asn1_test.cc
index 1044f7b2..8b024427 100644
--- a/crypto/asn1/asn1_test.cc
+++ b/crypto/asn1/asn1_test.cc
@@ -21,6 +21,11 @@
#include "../test/scoped_types.h"
+// kTag128 is an ASN.1 structure with a universal tag with number 128.
+static const uint8_t kTag128[] = {
+ 0x1f, 0x81, 0x00, 0x01, 0x00,
+};
+
// kTag258 is an ASN.1 structure with a universal tag with number 258.
static const uint8_t kTag258[] = {
0x1f, 0x82, 0x02, 0x01, 0x00,
@@ -29,13 +34,38 @@ static const uint8_t kTag258[] = {
static_assert(V_ASN1_NEG_INTEGER == 258,
"V_ASN1_NEG_INTEGER changed. Update kTag258 to collide with it.");
-bool TestLargeTags() {
+// kTagOverflow is an ASN.1 structure with a universal tag with number 2^35-1,
+// which will not fit in an int.
+static const uint8_t kTagOverflow[] = {
+ 0x1f, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00,
+};
+
+static bool TestLargeTags() {
const uint8_t *p = kTag258;
ScopedASN1_TYPE obj(d2i_ASN1_TYPE(NULL, &p, sizeof(kTag258)));
if (obj) {
fprintf(stderr, "Parsed value with illegal tag (type = %d).\n", obj->type);
return false;
}
+ ERR_clear_error();
+
+ p = kTagOverflow;
+ obj.reset(d2i_ASN1_TYPE(NULL, &p, sizeof(kTagOverflow)));
+ if (obj) {
+ fprintf(stderr, "Parsed value with tag overflow (type = %d).\n", obj->type);
+ return false;
+ }
+ ERR_clear_error();
+
+ p = kTag128;
+ obj.reset(d2i_ASN1_TYPE(NULL, &p, sizeof(kTag128)));
+ if (!obj || obj->type != 128 || obj->value.asn1_string->length != 1 ||
+ obj->value.asn1_string->data[0] != 0) {
+ fprintf(stderr, "Failed to parse value with tag 128.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
return true;
}
diff --git a/crypto/asn1/bio_asn1.c b/crypto/asn1/bio_asn1.c
deleted file mode 100644
index 03cc9a6e..00000000
--- a/crypto/asn1/bio_asn1.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.] */
-
-#include <openssl/asn1.h>
-
-#include <assert.h>
-#include <string.h>
-
-#include <openssl/bio.h>
-#include <openssl/mem.h>
-
-/* Must be large enough for biggest tag+length */
-#define DEFAULT_ASN1_BUF_SIZE 20
-
-typedef enum {
- ASN1_STATE_START,
- ASN1_STATE_PRE_COPY,
- ASN1_STATE_HEADER,
- ASN1_STATE_HEADER_COPY,
- ASN1_STATE_DATA_COPY,
- ASN1_STATE_POST_COPY,
- ASN1_STATE_DONE
-} asn1_bio_state_t;
-
-typedef struct BIO_ASN1_EX_FUNCS_st {
- asn1_ps_func *ex_func;
- asn1_ps_func *ex_free_func;
-} BIO_ASN1_EX_FUNCS;
-
-typedef struct BIO_ASN1_BUF_CTX_t {
- /* Internal state */
- asn1_bio_state_t state;
- /* Internal buffer */
- unsigned char *buf;
- /* Size of buffer */
- int bufsize;
- /* Current position in buffer */
- int bufpos;
- /* Current buffer length */
- int buflen;
- /* Amount of data to copy */
- int copylen;
- /* Class and tag to use */
- int asn1_class, asn1_tag;
- asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free;
- /* Extra buffer for prefix and suffix data */
- unsigned char *ex_buf;
- int ex_len;
- int ex_pos;
- void *ex_arg;
-} BIO_ASN1_BUF_CTX;
-
-static int asn1_bio_write(BIO *h, const char *buf, int num);
-static int asn1_bio_read(BIO *h, char *buf, int size);
-static int asn1_bio_puts(BIO *h, const char *str);
-static int asn1_bio_gets(BIO *h, char *str, int size);
-static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
-static int asn1_bio_new(BIO *h);
-static int asn1_bio_free(BIO *data);
-static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb fp);
-
-static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size);
-static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
- asn1_ps_func *cleanup, asn1_bio_state_t next);
-static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
- asn1_ps_func *setup,
- asn1_bio_state_t ex_state,
- asn1_bio_state_t other_state);
-
-static const BIO_METHOD methods_asn1 = {
- BIO_TYPE_ASN1,
- "asn1",
- asn1_bio_write,
- asn1_bio_read,
- asn1_bio_puts,
- asn1_bio_gets,
- asn1_bio_ctrl,
- asn1_bio_new,
- asn1_bio_free,
- asn1_bio_callback_ctrl,
-};
-
-const BIO_METHOD *BIO_f_asn1(void)
-{
- return (&methods_asn1);
-}
-
-static int asn1_bio_new(BIO *b)
-{
- BIO_ASN1_BUF_CTX *ctx;
- ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX));
- if (!ctx)
- return 0;
- if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) {
- OPENSSL_free(ctx);
- return 0;
- }
- b->init = 1;
- b->ptr = (char *)ctx;
- b->flags = 0;
- return 1;
-}
-
-static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size)
-{
- ctx->buf = OPENSSL_malloc(size);
- if (!ctx->buf)
- return 0;
- ctx->bufsize = size;
- ctx->bufpos = 0;
- ctx->buflen = 0;
- ctx->copylen = 0;
- ctx->asn1_class = V_ASN1_UNIVERSAL;
- ctx->asn1_tag = V_ASN1_OCTET_STRING;
- ctx->ex_buf = 0;
- ctx->ex_pos = 0;
- ctx->ex_len = 0;
- ctx->state = ASN1_STATE_START;
- return 1;
-}
-
-static int asn1_bio_free(BIO *b)
-{
- BIO_ASN1_BUF_CTX *ctx;
- ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
- if (ctx == NULL)
- return 0;
- if (ctx->buf)
- OPENSSL_free(ctx->buf);
- OPENSSL_free(ctx);
- b->init = 0;
- b->ptr = NULL;
- b->flags = 0;
- return 1;
-}
-
-static int asn1_bio_write(BIO *b, const char *in, int inl)
-{
- BIO_ASN1_BUF_CTX *ctx;
- int wrmax, wrlen, ret;
- unsigned char *p;
- if (!in || (inl < 0) || (b->next_bio == NULL))
- return 0;
- ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
- if (ctx == NULL)
- return 0;
-
- wrlen = 0;
- ret = -1;
-
- for (;;) {
- switch (ctx->state) {
-
- /* Setup prefix data, call it */
- case ASN1_STATE_START:
- if (!asn1_bio_setup_ex(b, ctx, ctx->prefix,
- ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER))
- return 0;
- break;
-
- /* Copy any pre data first */
- case ASN1_STATE_PRE_COPY:
-
- ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
- ASN1_STATE_HEADER);
-
- if (ret <= 0)
- goto done;
-
- break;
-
- case ASN1_STATE_HEADER:
- ctx->buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
- assert(ctx->buflen <= ctx->bufsize);
- p = ctx->buf;
- ASN1_put_object(&p, 0, inl, ctx->asn1_tag, ctx->asn1_class);
- ctx->copylen = inl;
- ctx->state = ASN1_STATE_HEADER_COPY;
-
- break;
-
- case ASN1_STATE_HEADER_COPY:
- ret = BIO_write(b->next_bio, ctx->buf + ctx->bufpos, ctx->buflen);
- if (ret <= 0)
- goto done;
-
- ctx->buflen -= ret;
- if (ctx->buflen)
- ctx->bufpos += ret;
- else {
- ctx->bufpos = 0;
- ctx->state = ASN1_STATE_DATA_COPY;
- }
-
- break;
-
- case ASN1_STATE_DATA_COPY:
-
- if (inl > ctx->copylen)
- wrmax = ctx->copylen;
- else
- wrmax = inl;
- ret = BIO_write(b->next_bio, in, wrmax);
- if (ret <= 0)
- break;
- wrlen += ret;
- ctx->copylen -= ret;
- in += ret;
- inl -= ret;
-
- if (ctx->copylen == 0)
- ctx->state = ASN1_STATE_HEADER;
-
- if (inl == 0)
- goto done;
-
- break;
-
- default:
- BIO_clear_retry_flags(b);
- return 0;
-
- }
-
- }
-
- done:
- BIO_clear_retry_flags(b);
- BIO_copy_next_retry(b);
-
- return (wrlen > 0) ? wrlen : ret;
-
-}
-
-static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
- asn1_ps_func *cleanup, asn1_bio_state_t next)
-{
- int ret;
- if (ctx->ex_len <= 0)
- return 1;
- for (;;) {
- ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, ctx->ex_len);
- if (ret <= 0)
- break;
- ctx->ex_len -= ret;
- if (ctx->ex_len > 0)
- ctx->ex_pos += ret;
- else {
- if (cleanup)
- cleanup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg);
- ctx->state = next;
- ctx->ex_pos = 0;
- break;
- }
- }
- return ret;
-}
-
-static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
- asn1_ps_func *setup,
- asn1_bio_state_t ex_state,
- asn1_bio_state_t other_state)
-{
- if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) {
- BIO_clear_retry_flags(b);
- return 0;
- }
- if (ctx->ex_len > 0)
- ctx->state = ex_state;
- else
- ctx->state = other_state;
- return 1;
-}
-
-static int asn1_bio_read(BIO *b, char *in, int inl)
-{
- if (!b->next_bio)
- return 0;
- return BIO_read(b->next_bio, in, inl);
-}
-
-static int asn1_bio_puts(BIO *b, const char *str)
-{
- return asn1_bio_write(b, str, strlen(str));
-}
-
-static int asn1_bio_gets(BIO *b, char *str, int size)
-{
- if (!b->next_bio)
- return 0;
- return BIO_gets(b->next_bio, str, size);
-}
-
-static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb fp)
-{
- if (b->next_bio == NULL)
- return (0);
- return BIO_callback_ctrl(b->next_bio, cmd, fp);
-}
-
-static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2)
-{
- BIO_ASN1_BUF_CTX *ctx;
- BIO_ASN1_EX_FUNCS *ex_func;
- long ret = 1;
- ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
- if (ctx == NULL)
- return 0;
- switch (cmd) {
-
- case BIO_C_SET_PREFIX:
- ex_func = arg2;
- ctx->prefix = ex_func->ex_func;
- ctx->prefix_free = ex_func->ex_free_func;
- break;
-
- case BIO_C_GET_PREFIX:
- ex_func = arg2;
- ex_func->ex_func = ctx->prefix;
- ex_func->ex_free_func = ctx->prefix_free;
- break;
-
- case BIO_C_SET_SUFFIX:
- ex_func = arg2;
- ctx->suffix = ex_func->ex_func;
- ctx->suffix_free = ex_func->ex_free_func;
- break;
-
- case BIO_C_GET_SUFFIX:
- ex_func = arg2;
- ex_func->ex_func = ctx->suffix;
- ex_func->ex_free_func = ctx->suffix_free;
- break;
-
- case BIO_C_SET_EX_ARG:
- ctx->ex_arg = arg2;
- break;
-
- case BIO_C_GET_EX_ARG:
- *(void **)arg2 = ctx->ex_arg;
- break;
-
- case BIO_CTRL_FLUSH:
- if (!b->next_bio)
- return 0;
-
- /* Call post function if possible */
- if (ctx->state == ASN1_STATE_HEADER) {
- if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
- ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
- return 0;
- }
-
- if (ctx->state == ASN1_STATE_POST_COPY) {
- ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
- ASN1_STATE_DONE);
- if (ret <= 0)
- return ret;
- }
-
- if (ctx->state == ASN1_STATE_DONE)
- return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
- else {
- BIO_clear_retry_flags(b);
- return 0;
- }
- break;
-
- default:
- if (!b->next_bio)
- return 0;
- return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
-
- }
-
- return ret;
-}
-
-static int asn1_bio_set_ex(BIO *b, int cmd,
- asn1_ps_func *ex_func, asn1_ps_func *ex_free_func)
-{
- BIO_ASN1_EX_FUNCS extmp;
- extmp.ex_func = ex_func;
- extmp.ex_free_func = ex_free_func;
- return BIO_ctrl(b, cmd, 0, &extmp);
-}
-
-static int asn1_bio_get_ex(BIO *b, int cmd,
- asn1_ps_func **ex_func,
- asn1_ps_func **ex_free_func)
-{
- BIO_ASN1_EX_FUNCS extmp;
- int ret;
- ret = BIO_ctrl(b, cmd, 0, &extmp);
- if (ret > 0) {
- *ex_func = extmp.ex_func;
- *ex_free_func = extmp.ex_free_func;
- }
- return ret;
-}
-
-int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix,
- asn1_ps_func *prefix_free)
-{
- return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
-}
-
-int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix,
- asn1_ps_func **pprefix_free)
-{
- return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
-}
-
-int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix,
- asn1_ps_func *suffix_free)
-{
- return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free);
-}
-
-int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix,
- asn1_ps_func **psuffix_free)
-{
- return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
-}
diff --git a/crypto/asn1/bio_ndef.c b/crypto/asn1/bio_ndef.c
deleted file mode 100644
index 81a8aa7c..00000000
--- a/crypto/asn1/bio_ndef.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.] */
-
-#include <openssl/asn1.h>
-
-#include <assert.h>
-
-#include <openssl/asn1t.h>
-#include <openssl/bio.h>
-#include <openssl/err.h>
-#include <openssl/mem.h>
-
-/* Experimental NDEF ASN1 BIO support routines */
-
-/*
- * The usage is quite simple, initialize an ASN1 structure, get a BIO from it
- * then any data written through the BIO will end up translated to
- * approptiate format on the fly. The data is streamed out and does *not*
- * need to be all held in memory at once. When the BIO is flushed the output
- * is finalized and any signatures etc written out. The BIO is a 'proper'
- * BIO and can handle non blocking I/O correctly. The usage is simple. The
- * implementation is *not*...
- */
-
-/* BIO support data stored in the ASN1 BIO ex_arg */
-
-typedef struct ndef_aux_st {
- /* ASN1 structure this BIO refers to */
- ASN1_VALUE *val;
- const ASN1_ITEM *it;
- /* Top of the BIO chain */
- BIO *ndef_bio;
- /* Output BIO */
- BIO *out;
- /* Boundary where content is inserted */
- unsigned char **boundary;
- /* DER buffer start */
- unsigned char *derbuf;
-} NDEF_SUPPORT;
-
-static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
-static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
- void *parg);
-static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
-static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
- void *parg);
-
-BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
-{
- NDEF_SUPPORT *ndef_aux = NULL;
- BIO *asn_bio = NULL;
- const ASN1_AUX *aux = it->funcs;
- ASN1_STREAM_ARG sarg;
-
- if (!aux || !aux->asn1_cb) {
- OPENSSL_PUT_ERROR(ASN1, ASN1_R_STREAMING_NOT_SUPPORTED);
- return NULL;
- }
- ndef_aux = OPENSSL_malloc(sizeof(NDEF_SUPPORT));
- asn_bio = BIO_new(BIO_f_asn1());
-
- /* ASN1 bio needs to be next to output BIO */
-
- out = BIO_push(asn_bio, out);
-
- if (!ndef_aux || !asn_bio || !out)
- goto err;
-
- BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free);
- BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free);
-
- /*
- * Now let callback prepend any digest, cipher etc BIOs ASN1 structure
- * needs.
- */
-
- sarg.out = out;
- sarg.ndef_bio = NULL;
- sarg.boundary = NULL;
-
- if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0)
- goto err;
-
- ndef_aux->val = val;
- ndef_aux->it = it;
- ndef_aux->ndef_bio = sarg.ndef_bio;
- ndef_aux->boundary = sarg.boundary;
- ndef_aux->out = out;
-
- BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux);
-
- return sarg.ndef_bio;
-
- err:
- if (asn_bio)
- BIO_free(asn_bio);
- if (ndef_aux)
- OPENSSL_free(ndef_aux);
- return NULL;
-}
-
-static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
-{
- NDEF_SUPPORT *ndef_aux;
- unsigned char *p;
- int derlen;
-
- if (!parg)
- return 0;
-
- ndef_aux = *(NDEF_SUPPORT **)parg;
-
- derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
- p = OPENSSL_malloc(derlen);
- if (p == NULL)
- return 0;
-
- ndef_aux->derbuf = p;
- *pbuf = p;
- derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
-
- if (!*ndef_aux->boundary)
- return 0;
-
- *plen = *ndef_aux->boundary - *pbuf;
-
- return 1;
-}
-
-static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
- void *parg)
-{
- NDEF_SUPPORT *ndef_aux;
-
- if (!parg)
- return 0;
-
- ndef_aux = *(NDEF_SUPPORT **)parg;
-
- if (ndef_aux->derbuf)
- OPENSSL_free(ndef_aux->derbuf);
-
- ndef_aux->derbuf = NULL;
- *pbuf = NULL;
- *plen = 0;
- return 1;
-}
-
-static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
- void *parg)
-{
- NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg;
- if (!ndef_prefix_free(b, pbuf, plen, parg))
- return 0;
- OPENSSL_free(*pndef_aux);
- *pndef_aux = NULL;
- return 1;
-}
-
-static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
-{
- NDEF_SUPPORT *ndef_aux;
- unsigned char *p;
- int derlen;
- const ASN1_AUX *aux;
- ASN1_STREAM_ARG sarg;
-
- if (!parg)
- return 0;
-
- ndef_aux = *(NDEF_SUPPORT **)parg;
-
- aux = ndef_aux->it->funcs;
-
- /* Finalize structures */
- sarg.ndef_bio = ndef_aux->ndef_bio;
- sarg.out = ndef_aux->out;
- sarg.boundary = ndef_aux->boundary;
- if (aux->asn1_cb(ASN1_OP_STREAM_POST,
- &ndef_aux->val, ndef_aux->it, &sarg) <= 0)
- return 0;
-
- derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
- p = OPENSSL_malloc(derlen);
- if (p == NULL)
- return 0;
-
- ndef_aux->derbuf = p;
- *pbuf = p;
- derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
-
- if (!*ndef_aux->boundary)
- return 0;
- *pbuf = *ndef_aux->boundary;
- *plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf);
-
- return 1;
-}
diff --git a/crypto/asn1/t_pkey.c b/crypto/asn1/t_pkey.c
deleted file mode 100644
index 2c420894..00000000
--- a/crypto/asn1/t_pkey.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.] */
-
-#include <openssl/asn1.h>
-
-#include <openssl/bio.h>
-#include <openssl/mem.h>
-
-int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num,
- unsigned char *buf, int off)
-{
- int n, i;
- const char *neg;
-
- if (num == NULL)
- return (1);
- neg = (BN_is_negative(num)) ? "-" : "";
- if (!BIO_indent(bp, off, 128))
- return 0;
- if (BN_is_zero(num)) {
- if (BIO_printf(bp, "%s 0\n", number) <= 0)
- return 0;
- return 1;
- }
-
- if (BN_num_bytes(num) <= sizeof(long)) {
- if (BIO_printf(bp, "%s %s%lu (%s0x%lx)\n", number, neg,
- (unsigned long)num->d[0], neg,
- (unsigned long)num->d[0])
- <= 0)
- return (0);
- } else {
- buf[0] = 0;
- if (BIO_printf(bp, "%s%s", number,
- (neg[0] == '-') ? " (Negative)" : "") <= 0)
- return (0);
- n = BN_bn2bin(num, &buf[1]);
-
- if (buf[1] & 0x80)
- n++;
- else
- buf++;
-
- for (i = 0; i < n; i++) {
- if ((i % 15) == 0) {
- if (BIO_puts(bp, "\n") <= 0 || !BIO_indent(bp, off + 4, 128))
- return 0;
- }
- if (BIO_printf(bp, "%02x%s", buf[i], ((i + 1) == n) ? "" : ":")
- <= 0)
- return (0);
- }
- if (BIO_write(bp, "\n", 1) <= 0)
- return (0);
- }
- return (1);
-}
diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c
index fd07fa24..616b587c 100644
--- a/crypto/asn1/tasn_dec.c
+++ b/crypto/asn1/tasn_dec.c
@@ -706,13 +706,12 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
const unsigned char **in, long inlen,
const ASN1_ITEM *it,
int tag, int aclass, char opt, ASN1_TLC *ctx)
- OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS
{
int ret = 0, utype;
long plen;
char cst, inf, free_cont = 0;
const unsigned char *p;
- BUF_MEM buf;
+ BUF_MEM buf = {0, NULL, 0 };
const unsigned char *cont = NULL;
long len;
if (!pval) {
@@ -786,7 +785,6 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
} else {
len = p - cont + plen;
p += plen;
- buf.data = NULL;
}
} else if (cst) {
if (utype == V_ASN1_NULL || utype == V_ASN1_BOOLEAN
@@ -797,9 +795,8 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
return 0;
}
- buf.length = 0;
- buf.max = 0;
- buf.data = NULL;
+ /* Free any returned 'buf' content */
+ free_cont = 1;
/*
* Should really check the internal tags are correct but some things
* may get this wrong. The relevant specs say that constructed string
@@ -807,18 +804,16 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
* So instead just check for UNIVERSAL class and ignore the tag.
*/
if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL, 0)) {
- free_cont = 1;
goto err;
}
len = buf.length;
/* Append a final null to string */
if (!BUF_MEM_grow_clean(&buf, len + 1)) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
- return 0;
+ goto err;
}
buf.data[len] = 0;
cont = (const unsigned char *)buf.data;
- free_cont = 1;
} else {
cont = p;
len = plen;
@@ -826,6 +821,7 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
}
/* We now have content length and type: translate into a structure */
+ /* asn1_ex_c2i may reuse allocated buffer, and so sets free_cont to 0 */
if (!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it))
goto err;
@@ -898,9 +894,7 @@ int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
break;
case V_ASN1_INTEGER:
- case V_ASN1_NEG_INTEGER:
case V_ASN1_ENUMERATED:
- case V_ASN1_NEG_ENUMERATED:
tint = (ASN1_INTEGER **)pval;
if (!c2i_ASN1_INTEGER(tint, &cont, len))
goto err;
diff --git a/crypto/asn1/tasn_enc.c b/crypto/asn1/tasn_enc.c
index a56d08ed..409d1388 100644
--- a/crypto/asn1/tasn_enc.c
+++ b/crypto/asn1/tasn_enc.c
@@ -609,9 +609,7 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
break;
case V_ASN1_INTEGER:
- case V_ASN1_NEG_INTEGER:
case V_ASN1_ENUMERATED:
- case V_ASN1_NEG_ENUMERATED:
/*
* These are all have the same content format as ASN1_INTEGER
*/
diff --git a/crypto/asn1/tasn_prn.c b/crypto/asn1/tasn_prn.c
deleted file mode 100644
index dd20cb4d..00000000
--- a/crypto/asn1/tasn_prn.c
+++ /dev/null
@@ -1,596 +0,0 @@
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.] */
-
-#include <openssl/asn1.h>
-
-#include <time.h>
-
-#include <openssl/asn1t.h>
-#include <openssl/err.h>
-#include <openssl/obj.h>
-#include <openssl/mem.h>
-
-#include "asn1_locl.h"
-
-/*
- * Print routines.
- */
-
-/* ASN1_PCTX routines */
-
-static ASN1_PCTX default_pctx = {
- ASN1_PCTX_FLAGS_SHOW_ABSENT, /* flags */
- 0, /* nm_flags */
- 0, /* cert_flags */
- 0, /* oid_flags */
- 0 /* str_flags */
-};
-
-ASN1_PCTX *ASN1_PCTX_new(void)
-{
- ASN1_PCTX *ret;
- ret = OPENSSL_malloc(sizeof(ASN1_PCTX));
- if (ret == NULL) {
- OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
- ret->flags = 0;
- ret->nm_flags = 0;
- ret->cert_flags = 0;
- ret->oid_flags = 0;
- ret->str_flags = 0;
- return ret;
-}
-
-void ASN1_PCTX_free(ASN1_PCTX *p)
-{
- OPENSSL_free(p);
-}
-
-unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p)
-{
- return p->flags;
-}
-
-void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags)
-{
- p->flags = flags;
-}
-
-unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p)
-{
- return p->nm_flags;
-}
-
-void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags)
-{
- p->nm_flags = flags;
-}
-
-unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p)
-{
- return p->cert_flags;
-}
-
-void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags)
-{
- p->cert_flags = flags;
-}
-
-unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p)
-{
- return p->oid_flags;
-}
-
-void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags)
-{
- p->oid_flags = flags;
-}
-
-unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p)
-{
- return p->str_flags;
-}
-
-void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags)
-{
- p->str_flags = flags;
-}
-
-/* Main print routines */
-
-static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
- const ASN1_ITEM *it,
- const char *fname, const char *sname,
- int nohdr, const ASN1_PCTX *pctx);
-
-int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
- const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx);
-
-static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld,
- const ASN1_ITEM *it, int indent,
- const char *fname, const char *sname,
- const ASN1_PCTX *pctx);
-
-static int asn1_print_fsname(BIO *out, int indent,
- const char *fname, const char *sname,
- const ASN1_PCTX *pctx);
-
-int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent,
- const ASN1_ITEM *it, const ASN1_PCTX *pctx)
-{
- const char *sname;
- if (pctx == NULL)
- pctx = &default_pctx;
- if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME)
- sname = NULL;
- else
- sname = it->sname;
- return asn1_item_print_ctx(out, &ifld, indent, it, NULL, sname, 0, pctx);
-}
-
-static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
- const ASN1_ITEM *it,
- const char *fname, const char *sname,
- int nohdr, const ASN1_PCTX *pctx)
-{
- const ASN1_TEMPLATE *tt;
- const ASN1_EXTERN_FUNCS *ef;
- ASN1_VALUE **tmpfld;
- const ASN1_AUX *aux = it->funcs;
- ASN1_aux_cb *asn1_cb;
- ASN1_PRINT_ARG parg;
- int i;
- if (aux && aux->asn1_cb) {
- parg.out = out;
- parg.indent = indent;
- parg.pctx = pctx;
- asn1_cb = aux->asn1_cb;
- } else
- asn1_cb = 0;
-
- if (*fld == NULL) {
- if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_ABSENT) {
- if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
- return 0;
- if (BIO_puts(out, "<ABSENT>\n") <= 0)
- return 0;
- }
- return 1;
- }
-
- switch (it->itype) {
- case ASN1_ITYPE_PRIMITIVE:
- if (it->templates) {
- if (!asn1_template_print_ctx(out, fld, indent,
- it->templates, pctx))
- return 0;
- break;
- }
- /* fall thru */
- case ASN1_ITYPE_MSTRING:
- if (!asn1_primitive_print(out, fld, it, indent, fname, sname, pctx))
- return 0;
- break;
-
- case ASN1_ITYPE_EXTERN:
- if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
- return 0;
- /* Use new style print routine if possible */
- ef = it->funcs;
- if (ef && ef->asn1_ex_print) {
- i = ef->asn1_ex_print(out, fld, indent, "", pctx);
- if (!i)
- return 0;
- if ((i == 2) && (BIO_puts(out, "\n") <= 0))
- return 0;
- return 1;
- } else if (sname &&
- BIO_printf(out, ":EXTERNAL TYPE %s\n", sname) <= 0)
- return 0;
- break;
-
- case ASN1_ITYPE_CHOICE:
-#if 0
- if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
- return 0;
-#endif
- /* CHOICE type, get selector */
- i = asn1_get_choice_selector(fld, it);
- /* This should never happen... */
- if ((i < 0) || (i >= it->tcount)) {
- if (BIO_printf(out, "ERROR: selector [%d] invalid\n", i) <= 0)
- return 0;
- return 1;
- }
- tt = it->templates + i;
- tmpfld = asn1_get_field_ptr(fld, tt);
- if (!asn1_template_print_ctx(out, tmpfld, indent, tt, pctx))
- return 0;
- break;
-
- case ASN1_ITYPE_SEQUENCE:
- case ASN1_ITYPE_NDEF_SEQUENCE:
- if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
- return 0;
- if (fname || sname) {
- if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
- if (BIO_puts(out, " {\n") <= 0)
- return 0;
- } else {
- if (BIO_puts(out, "\n") <= 0)
- return 0;
- }
- }
-
- if (asn1_cb) {
- i = asn1_cb(ASN1_OP_PRINT_PRE, fld, it, &parg);
- if (i == 0)
- return 0;
- if (i == 2)
- return 1;
- }
-
- /* Print each field entry */
- for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) {
- const ASN1_TEMPLATE *seqtt;
- seqtt = asn1_do_adb(fld, tt, 1);
- if (!seqtt)
- return 0;
- tmpfld = asn1_get_field_ptr(fld, seqtt);
- if (!asn1_template_print_ctx(out, tmpfld,
- indent + 2, seqtt, pctx))
- return 0;
- }
- if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
- if (BIO_printf(out, "%*s}\n", indent, "") < 0)
- return 0;
- }
-
- if (asn1_cb) {
- i = asn1_cb(ASN1_OP_PRINT_POST, fld, it, &parg);
- if (i == 0)
- return 0;
- }
- break;
-
- default:
- BIO_printf(out, "Unprocessed type %d\n", it->itype);
- return 0;
- }
-
- return 1;
-}
-
-int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
- const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx)
-{
- int flags;
- size_t i;
- const char *sname, *fname;
- flags = tt->flags;
- if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME)
- sname = ASN1_ITEM_ptr(tt->item)->sname;
- else
- sname = NULL;
- if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME)
- fname = NULL;
- else
- fname = tt->field_name;
- if (flags & ASN1_TFLG_SK_MASK) {
- const char *tname;
- ASN1_VALUE *skitem;
- STACK_OF(ASN1_VALUE) *stack;
-
- /* SET OF, SEQUENCE OF */
- if (fname) {
- if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SSOF) {
- if (flags & ASN1_TFLG_SET_OF)
- tname = "SET";
- else
- tname = "SEQUENCE";
- if (BIO_printf(out, "%*s%s OF %s {\n",
- indent, "", tname, tt->field_name) <= 0)
- return 0;
- } else if (BIO_printf(out, "%*s%s:\n", indent, "", fname) <= 0)
- return 0;
- }
- stack = (STACK_OF(ASN1_VALUE) *)*fld;
- for (i = 0; i < sk_ASN1_VALUE_num(stack); i++) {
- if ((i > 0) && (BIO_puts(out, "\n") <= 0))
- return 0;
-
- skitem = sk_ASN1_VALUE_value(stack, i);
- if (!asn1_item_print_ctx(out, &skitem, indent + 2,
- ASN1_ITEM_ptr(tt->item), NULL, NULL, 1,
- pctx))
- return 0;
- }
- if (!i && BIO_printf(out, "%*s<EMPTY>\n", indent + 2, "") <= 0)
- return 0;
- if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
- if (BIO_printf(out, "%*s}\n", indent, "") <= 0)
- return 0;
- }
- return 1;
- }
- return asn1_item_print_ctx(out, fld, indent, ASN1_ITEM_ptr(tt->item),
- fname, sname, 0, pctx);
-}
-
-static int asn1_print_fsname(BIO *out, int indent,
- const char *fname, const char *sname,
- const ASN1_PCTX *pctx)
-{
- static char spaces[] = " ";
- const int nspaces = sizeof(spaces) - 1;
-
-#if 0
- if (!sname && !fname)
- return 1;
-#endif
-
- while (indent > nspaces) {
- if (BIO_write(out, spaces, nspaces) != nspaces)
- return 0;
- indent -= nspaces;
- }
- if (BIO_write(out, spaces, indent) != indent)
- return 0;
- if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME)
- sname = NULL;
- if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME)
- fname = NULL;
- if (!sname && !fname)
- return 1;
- if (fname) {
- if (BIO_puts(out, fname) <= 0)
- return 0;
- }
- if (sname) {
- if (fname) {
- if (BIO_printf(out, " (%s)", sname) <= 0)
- return 0;
- } else {
- if (BIO_puts(out, sname) <= 0)
- return 0;
- }
- }
- if (BIO_write(out, ": ", 2) != 2)
- return 0;
- return 1;
-}
-
-static int asn1_print_boolean_ctx(BIO *out, int boolval,
- const ASN1_PCTX *pctx)
-{
- const char *str;
- switch (boolval) {
- case -1:
- str = "BOOL ABSENT";
- break;
-
- case 0:
- str = "FALSE";
- break;
-
- default:
- str = "TRUE";
- break;
-
- }
-
- if (BIO_puts(out, str) <= 0)
- return 0;
- return 1;
-
-}
-
-static int asn1_print_integer_ctx(BIO *out, ASN1_INTEGER *str,
- const ASN1_PCTX *pctx)
-{
- BIGNUM *bn = NULL;
- char *s = NULL;
- int ret = 1;
-
- bn = ASN1_INTEGER_to_BN(str, NULL);
- if (bn == NULL) {
- return 0;
- }
- s = BN_bn2dec(bn);
- BN_free(bn);
- if (s == NULL) {
- return 0;
- }
-
- if (BIO_puts(out, s) <= 0) {
- ret = 0;
- }
- OPENSSL_free(s);
- return ret;
-}
-
-static int asn1_print_oid_ctx(BIO *out, const ASN1_OBJECT *oid,
- const ASN1_PCTX *pctx)
-{
- char objbuf[80];
- const char *ln;
- ln = OBJ_nid2ln(OBJ_obj2nid(oid));
- if (!ln)
- ln = "";
- OBJ_obj2txt(objbuf, sizeof objbuf, oid, 1);
- if (BIO_printf(out, "%s (%s)", ln, objbuf) <= 0)
- return 0;
- return 1;
-}
-
-static int asn1_print_obstring_ctx(BIO *out, ASN1_STRING *str, int indent,
- const ASN1_PCTX *pctx)
-{
- if (str->type == V_ASN1_BIT_STRING) {
- if (BIO_printf(out, " (%ld unused bits)\n", str->flags & 0x7) <= 0)
- return 0;
- } else if (BIO_puts(out, "\n") <= 0)
- return 0;
- if (str->length > 0
- && !BIO_hexdump(out, str->data, str->length, indent + 2)) {
- return 0;
- }
- return 1;
-}
-
-static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld,
- const ASN1_ITEM *it, int indent,
- const char *fname, const char *sname,
- const ASN1_PCTX *pctx)
-{
- long utype;
- ASN1_STRING *str;
- int ret = 1, needlf = 1;
- const char *pname;
- const ASN1_PRIMITIVE_FUNCS *pf;
- pf = it->funcs;
- if (!asn1_print_fsname(out, indent, fname, sname, pctx))
- return 0;
- if (pf && pf->prim_print)
- return pf->prim_print(out, fld, it, indent, pctx);
- str = (ASN1_STRING *)*fld;
- if (it->itype == ASN1_ITYPE_MSTRING)
- utype = str->type & ~V_ASN1_NEG;
- else
- utype = it->utype;
- if (utype == V_ASN1_ANY) {
- ASN1_TYPE *atype = (ASN1_TYPE *)*fld;
- utype = atype->type;
- fld = &atype->value.asn1_value;
- str = (ASN1_STRING *)*fld;
- if (pctx->flags & ASN1_PCTX_FLAGS_NO_ANY_TYPE)
- pname = NULL;
- else
- pname = ASN1_tag2str(utype);
- } else {
- if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_TYPE)
- pname = ASN1_tag2str(utype);
- else
- pname = NULL;
- }
-
- if (utype == V_ASN1_NULL) {
- if (BIO_puts(out, "NULL\n") <= 0)
- return 0;
- return 1;
- }
-
- if (pname) {
- if (BIO_puts(out, pname) <= 0)
- return 0;
- if (BIO_puts(out, ":") <= 0)
- return 0;
- }
-
- switch (utype) {
- case V_ASN1_BOOLEAN:
- {
- int boolval = *(int *)fld;
- if (boolval == -1)
- boolval = it->size;
- ret = asn1_print_boolean_ctx(out, boolval, pctx);
- }
- break;
-
- case V_ASN1_INTEGER:
- case V_ASN1_ENUMERATED:
- ret = asn1_print_integer_ctx(out, str, pctx);
- break;
-
- case V_ASN1_UTCTIME:
- ret = ASN1_UTCTIME_print(out, str);
- break;
-
- case V_ASN1_GENERALIZEDTIME:
- ret = ASN1_GENERALIZEDTIME_print(out, str);
- break;
-
- case V_ASN1_OBJECT:
- ret = asn1_print_oid_ctx(out, (const ASN1_OBJECT *)*fld, pctx);
- break;
-
- case V_ASN1_OCTET_STRING:
- case V_ASN1_BIT_STRING:
- ret = asn1_print_obstring_ctx(out, str, indent, pctx);
- needlf = 0;
- break;
-
- case V_ASN1_SEQUENCE:
- case V_ASN1_SET:
- case V_ASN1_OTHER:
- if (BIO_puts(out, "\n") <= 0)
- return 0;
- if (ASN1_parse_dump(out, str->data, str->length, indent, 0) <= 0)
- ret = 0;
- needlf = 0;
- break;
-
- default:
- ret = ASN1_STRING_print_ex(out, str, pctx->str_flags);
-
- }
- if (!ret)
- return 0;
- if (needlf && BIO_puts(out, "\n") <= 0)
- return 0;
- return 1;
-}
diff --git a/crypto/base64/base64.c b/crypto/base64/base64.c
index 4822fb89..0763a3e4 100644
--- a/crypto/base64/base64.c
+++ b/crypto/base64/base64.c
@@ -60,118 +60,119 @@
#include <limits.h>
#include <string.h>
+#include <openssl/type_check.h>
+
+
+/* Encoding. */
static const unsigned char data_bin2ascii[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
#define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f])
-/* 64 char lines
- * pad input with 0
- * left over chars are set to =
- * 1 byte => xx==
- * 2 bytes => xxx=
- * 3 bytes => xxxx
- */
-#define BIN_PER_LINE (64/4*3)
-#define CHUNKS_PER_LINE (64/4)
-#define CHAR_PER_LINE (64+1)
-
-/* 0xF0 is a EOLN
- * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
- * 0xF2 is EOF
- * 0xE0 is ignore at start of line.
- * 0xFF is error */
-
-#define B64_EOLN 0xF0
-#define B64_CR 0xF1
-#define B64_EOF 0xF2
-#define B64_WS 0xE0
-#define B64_ERROR 0xFF
-#define B64_NOT_BASE64(a) (((a) | 0x13) == 0xF3)
-
-static const uint8_t data_ascii2bin[128] = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0xFF,
- 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
- 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
- 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
- 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
- 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
- 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-};
+OPENSSL_COMPILE_ASSERT(sizeof(((EVP_ENCODE_CTX *)(NULL))->data) % 3 == 0,
+ data_length_must_be_multiple_of_base64_chunk_size);
-static uint8_t conv_ascii2bin(uint8_t a) {
- if (a >= 128) {
- return 0xFF;
+int EVP_EncodedLength(size_t *out_len, size_t len) {
+ if (len + 2 < len) {
+ return 0;
+ }
+ len += 2;
+ len /= 3;
+
+ if (((len << 2) >> 2) != len) {
+ return 0;
+ }
+ len <<= 2;
+
+ if (len + 1 < len) {
+ return 0;
}
- return data_ascii2bin[a];
+ len++;
+
+ *out_len = len;
+ return 1;
}
void EVP_EncodeInit(EVP_ENCODE_CTX *ctx) {
- ctx->length = 48;
- ctx->num = 0;
- ctx->line_num = 0;
+ memset(ctx, 0, sizeof(EVP_ENCODE_CTX));
}
void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
const uint8_t *in, size_t in_len) {
- unsigned i, j;
- unsigned total = 0;
+ size_t total = 0;
*out_len = 0;
if (in_len == 0) {
return;
}
- assert(ctx->length <= sizeof(ctx->enc_data));
+ assert(ctx->data_used < sizeof(ctx->data));
- if (ctx->num + in_len < ctx->length) {
- memcpy(&ctx->enc_data[ctx->num], in, in_len);
- ctx->num += in_len;
+ if (sizeof(ctx->data) - ctx->data_used > in_len) {
+ memcpy(&ctx->data[ctx->data_used], in, in_len);
+ ctx->data_used += in_len;
return;
}
- if (ctx->num != 0) {
- i = ctx->length - ctx->num;
- memcpy(&ctx->enc_data[ctx->num], in, i);
- in += i;
- in_len -= i;
- j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length);
- ctx->num = 0;
- out += j;
+
+ if (ctx->data_used != 0) {
+ const size_t todo = sizeof(ctx->data) - ctx->data_used;
+ memcpy(&ctx->data[ctx->data_used], in, todo);
+ in += todo;
+ in_len -= todo;
+
+ size_t encoded = EVP_EncodeBlock(out, ctx->data, sizeof(ctx->data));
+ ctx->data_used = 0;
+
+ out += encoded;
*(out++) = '\n';
*out = '\0';
- total = j + 1;
+
+ total = encoded + 1;
}
- while (in_len >= ctx->length) {
- j = EVP_EncodeBlock(out, in, ctx->length);
- in += ctx->length;
- in_len -= ctx->length;
- out += j;
+
+ while (in_len >= sizeof(ctx->data)) {
+ size_t encoded = EVP_EncodeBlock(out, in, sizeof(ctx->data));
+ in += sizeof(ctx->data);
+ in_len -= sizeof(ctx->data);
+
+ out += encoded;
*(out++) = '\n';
*out = '\0';
- total += j + 1;
+
+ if (total + encoded + 1 < total) {
+ *out_len = 0;
+ return;
+ }
+
+ total += encoded + 1;
}
+
if (in_len != 0) {
- memcpy(&ctx->enc_data[0], in, in_len);
+ memcpy(ctx->data, in, in_len);
+ }
+
+ ctx->data_used = in_len;
+
+ if (total > INT_MAX) {
+ /* We cannot signal an error, but we can at least avoid making *out_len
+ * negative. */
+ total = 0;
}
- ctx->num = in_len;
*out_len = total;
}
void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) {
- unsigned ret = 0;
-
- if (ctx->num != 0) {
- ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num);
- out[ret++] = '\n';
- out[ret] = '\0';
- ctx->num = 0;
+ if (ctx->data_used == 0) {
+ *out_len = 0;
+ return;
}
- *out_len = ret;
+
+ size_t encoded = EVP_EncodeBlock(out, ctx->data, ctx->data_used);
+ out[encoded++] = '\n';
+ out[encoded] = '\0';
+ ctx->data_used = 0;
+ *out_len = encoded;
}
size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
@@ -206,246 +207,223 @@ size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
return ret;
}
+
+/* Decoding. */
+
int EVP_DecodedLength(size_t *out_len, size_t len) {
if (len % 4 != 0) {
return 0;
}
+
*out_len = (len / 4) * 3;
return 1;
}
-int EVP_DecodeBase64(uint8_t *out, size_t *out_len, size_t max_out,
- const uint8_t *in, size_t in_len) {
- uint8_t a, b, c, d;
- size_t pad_len = 0, len = 0, max_len, i;
- uint32_t l;
+void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) {
+ memset(ctx, 0, sizeof(EVP_ENCODE_CTX));
+}
+
+/* kBase64ASCIIToBinData maps characters (c < 128) to their base64 value, or
+ * else 0xff if they are invalid. As a special case, the padding character
+ * ('=') is mapped to zero. */
+static const uint8_t kBase64ASCIIToBinData[128] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+ 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static uint8_t base64_ascii_to_bin(uint8_t a) {
+ if (a >= 128) {
+ return 0xFF;
+ }
+
+ return kBase64ASCIIToBinData[a];
+}
- if (!EVP_DecodedLength(&max_len, in_len) || max_out < max_len) {
+/* base64_decode_quad decodes a single “quad” (i.e. four characters) of base64
+ * data and writes up to three bytes to |out|. It sets |*out_num_bytes| to the
+ * number of bytes written, which will be less than three if the quad ended
+ * with padding. It returns one on success or zero on error. */
+static int base64_decode_quad(uint8_t *out, size_t *out_num_bytes,
+ const uint8_t *in) {
+ const uint8_t a = base64_ascii_to_bin(in[0]);
+ const uint8_t b = base64_ascii_to_bin(in[1]);
+ const uint8_t c = base64_ascii_to_bin(in[2]);
+ const uint8_t d = base64_ascii_to_bin(in[3]);
+ if (a == 0xff || b == 0xff || c == 0xff || d == 0xff) {
return 0;
}
- for (i = 0; i < in_len; i += 4) {
- a = conv_ascii2bin(*(in++));
- b = conv_ascii2bin(*(in++));
- if (i + 4 == in_len && in[1] == '=') {
- if (in[0] == '=') {
- pad_len = 2;
- } else {
- pad_len = 1;
- }
- }
- if (pad_len < 2) {
- c = conv_ascii2bin(*(in++));
- } else {
- c = 0;
- }
- if (pad_len < 1) {
- d = conv_ascii2bin(*(in++));
- } else {
- d = 0;
- }
- if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) {
+ const uint32_t v = ((uint32_t)a) << 18 | ((uint32_t)b) << 12 |
+ ((uint32_t)c) << 6 | (uint32_t)d;
+
+ const unsigned padding_pattern = (in[0] == '=') << 3 |
+ (in[1] == '=') << 2 |
+ (in[2] == '=') << 1 |
+ (in[3] == '=');
+
+ switch (padding_pattern) {
+ case 0:
+ /* The common case of no padding. */
+ *out_num_bytes = 3;
+ out[0] = v >> 16;
+ out[1] = v >> 8;
+ out[2] = v;
+ break;
+
+ case 1: /* xxx= */
+ *out_num_bytes = 2;
+ out[0] = v >> 16;
+ out[1] = v >> 8;
+ break;
+
+ case 3: /* xx== */
+ *out_num_bytes = 1;
+ out[0] = v >> 16;
+ break;
+
+ default:
return 0;
- }
- l = ((((uint32_t)a) << 18L) | (((uint32_t)b) << 12L) |
- (((uint32_t)c) << 6L) | (((uint32_t)d)));
- *(out++) = (uint8_t)(l >> 16L) & 0xff;
- if (pad_len < 2) {
- *(out++) = (uint8_t)(l >> 8L) & 0xff;
- }
- if (pad_len < 1) {
- *(out++) = (uint8_t)(l) & 0xff;
- }
- len += 3 - pad_len;
}
- *out_len = len;
- return 1;
-}
-void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) {
- ctx->length = 30;
- ctx->num = 0;
- ctx->line_num = 0;
- ctx->expect_nl = 0;
+ return 1;
}
int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
const uint8_t *in, size_t in_len) {
- int seof = -1, eof = 0, rv = -1, v, tmp, exp_nl;
- uint8_t *d;
- unsigned i, n, ln, ret = 0;
-
- n = ctx->num;
- d = ctx->enc_data;
- ln = ctx->line_num;
- exp_nl = ctx->expect_nl;
-
- /* last line of input. */
- if (in_len == 0 || (n == 0 && conv_ascii2bin(in[0]) == B64_EOF)) {
- rv = 0;
- goto end;
+ *out_len = 0;
+
+ if (ctx->error_encountered) {
+ return -1;
}
- /* We parse the input data */
+ size_t bytes_out = 0, i;
for (i = 0; i < in_len; i++) {
- /* If the current line is > 80 characters, scream alot */
- if (ln >= 80) {
- rv = -1;
- goto end;
+ const char c = in[i];
+ switch (c) {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ continue;
}
- /* Get char and put it into the buffer */
- tmp = *(in++);
- v = conv_ascii2bin(tmp);
- /* only save the good data :-) */
- if (!B64_NOT_BASE64(v)) {
- assert(n < sizeof(ctx->enc_data));
- d[n++] = tmp;
- ln++;
- } else if (v == B64_ERROR) {
- rv = -1;
- goto end;
+ if (base64_ascii_to_bin(c) == 0xff || ctx->eof_seen) {
+ ctx->error_encountered = 1;
+ return -1;
}
- /* have we seen a '=' which is 'definitly' the last
- * input line. seof will point to the character that
- * holds it. and eof will hold how many characters to
- * chop off. */
- if (tmp == '=') {
- if (seof == -1) {
- seof = n;
- }
- eof++;
- if (eof > 2) {
- /* There are, at most, two equals signs at the end of base64 data. */
- rv = -1;
- goto end;
+ ctx->data[ctx->data_used++] = c;
+ if (ctx->data_used == 4) {
+ size_t num_bytes_resulting;
+ if (!base64_decode_quad(out, &num_bytes_resulting, ctx->data)) {
+ ctx->error_encountered = 1;
+ return -1;
}
- }
- if (v == B64_CR) {
- ln = 0;
- if (exp_nl) {
- continue;
- }
- }
+ ctx->data_used = 0;
+ bytes_out += num_bytes_resulting;
+ out += num_bytes_resulting;
- /* eoln */
- if (v == B64_EOLN) {
- ln = 0;
- if (exp_nl) {
- exp_nl = 0;
- continue;
- }
- }
- exp_nl = 0;
-
- /* If we are at the end of input and it looks like a
- * line, process it. */
- if ((i + 1) == in_len && (((n & 3) == 0) || eof)) {
- v = B64_EOF;
- /* In case things were given us in really small
- records (so two '=' were given in separate
- updates), eof may contain the incorrect number
- of ending bytes to skip, so let's redo the count */
- eof = 0;
- if (d[n - 1] == '=') {
- eof++;
+ if (num_bytes_resulting < 3) {
+ ctx->eof_seen = 1;
}
- if (d[n - 2] == '=') {
- eof++;
- }
- /* There will never be more than two '=' */
}
+ }
- if ((v == B64_EOF && (n & 3) == 0) || n >= 64) {
- /* This is needed to work correctly on 64 byte input
- * lines. We process the line and then need to
- * accept the '\n' */
- if (v != B64_EOF && n >= 64) {
- exp_nl = 1;
- }
- if (n > 0) {
- /* TODO(davidben): Switch this to EVP_DecodeBase64. */
- v = EVP_DecodeBlock(out, d, n);
- n = 0;
- if (v < 0) {
- rv = 0;
- goto end;
- }
- if (eof > v) {
- rv = -1;
- goto end;
- }
- ret += (v - eof);
- } else {
- eof = 1;
- v = 0;
- }
+ if (bytes_out > INT_MAX) {
+ ctx->error_encountered = 1;
+ *out_len = 0;
+ return -1;
+ }
+ *out_len = bytes_out;
- /* This is the case where we have had a short
- * but valid input line */
- if (v < (int)ctx->length && eof) {
- rv = 0;
- goto end;
- } else {
- ctx->length = v;
- }
+ if (ctx->eof_seen) {
+ return 0;
+ }
- if (seof >= 0) {
- rv = 0;
- goto end;
- }
- out += v;
- }
+ return 1;
+}
+
+int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) {
+ *out_len = 0;
+ if (ctx->error_encountered || ctx->data_used != 0) {
+ return -1;
}
- rv = 1;
-
-end:
- *out_len = ret;
- ctx->num = n;
- ctx->line_num = ln;
- ctx->expect_nl = exp_nl;
- return rv;
+
+ return 1;
}
-int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *outl) {
- int i;
+int EVP_DecodeBase64(uint8_t *out, size_t *out_len, size_t max_out,
+ const uint8_t *in, size_t in_len) {
+ *out_len = 0;
- *outl = 0;
- if (ctx->num != 0) {
- /* TODO(davidben): Switch this to EVP_DecodeBase64. */
- i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num);
- if (i < 0) {
- return -1;
+ if (in_len % 4 != 0) {
+ return 0;
+ }
+
+ size_t max_len;
+ if (!EVP_DecodedLength(&max_len, in_len) ||
+ max_out < max_len) {
+ return 0;
+ }
+
+ size_t i, bytes_out = 0;
+ for (i = 0; i < in_len; i += 4) {
+ size_t num_bytes_resulting;
+
+ if (!base64_decode_quad(out, &num_bytes_resulting, &in[i])) {
+ return 0;
+ }
+
+ bytes_out += num_bytes_resulting;
+ out += num_bytes_resulting;
+ if (num_bytes_resulting != 3 && i != in_len - 4) {
+ return 0;
}
- ctx->num = 0;
- *outl = i;
- return 1;
- } else {
- return 1;
}
+
+ *out_len = bytes_out;
+ return 1;
}
int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
- size_t dst_len;
+ /* Trim spaces and tabs from the beginning of the input. */
+ while (src_len > 0) {
+ if (src[0] != ' ' && src[0] != '\t') {
+ break;
+ }
- /* trim white space from the start of the line. */
- while (conv_ascii2bin(*src) == B64_WS && src_len > 0) {
src++;
src_len--;
}
- /* strip off stuff at the end of the line
- * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */
- while (src_len > 3 && B64_NOT_BASE64(conv_ascii2bin(src[src_len - 1]))) {
- src_len--;
- }
+ /* Trim newlines, spaces and tabs from the end of the line. */
+ while (src_len > 0) {
+ switch (src[src_len-1]) {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ src_len--;
+ continue;
+ }
- if (!EVP_DecodedLength(&dst_len, src_len) || dst_len > INT_MAX) {
- return -1;
+ break;
}
- if (!EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) {
+
+ size_t dst_len;
+ if (!EVP_DecodedLength(&dst_len, src_len) ||
+ dst_len > INT_MAX ||
+ !EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) {
return -1;
}
@@ -458,21 +436,3 @@ int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
return dst_len;
}
-
-int EVP_EncodedLength(size_t *out_len, size_t len) {
- if (len + 2 < len) {
- return 0;
- }
- len += 2;
- len /= 3;
- if (((len << 2) >> 2) != len) {
- return 0;
- }
- len <<= 2;
- if (len + 1 < len) {
- return 0;
- }
- len++;
- *out_len = len;
- return 1;
-}
diff --git a/crypto/base64/base64_test.cc b/crypto/base64/base64_test.cc
index da016e66..a6087732 100644
--- a/crypto/base64/base64_test.cc
+++ b/crypto/base64/base64_test.cc
@@ -15,76 +15,203 @@
#include <stdio.h>
#include <string.h>
+#include <string>
+#include <vector>
+
#include <openssl/base64.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
+enum encoding_relation {
+ // canonical indicates that the encoding is the expected encoding of the
+ // input.
+ canonical,
+ // valid indicates that the encoding is /a/ valid encoding of the input, but
+ // need not be the canonical one.
+ valid,
+ // invalid indicates that the encoded data is valid.
+ invalid,
+};
+
struct TestVector {
+ enum encoding_relation relation;
const char *decoded;
const char *encoded;
};
// Test vectors from RFC 4648.
static const TestVector kTestVectors[] = {
- { "", "" },
- { "f" , "Zg==" },
- { "fo", "Zm8=" },
- { "foo", "Zm9v" },
- { "foob", "Zm9vYg==" },
- { "fooba", "Zm9vYmE=" },
- { "foobar", "Zm9vYmFy" },
+ {canonical, "", ""},
+ {canonical, "f", "Zg==\n"},
+ {canonical, "fo", "Zm8=\n"},
+ {canonical, "foo", "Zm9v\n"},
+ {canonical, "foob", "Zm9vYg==\n"},
+ {canonical, "fooba", "Zm9vYmE=\n"},
+ {canonical, "foobar", "Zm9vYmFy\n"},
+ {valid, "foobar", "Zm9vYmFy\n\n"},
+ {valid, "foobar", " Zm9vYmFy\n\n"},
+ {valid, "foobar", " Z m 9 v Y m F y\n\n"},
+ {invalid, "", "Zm9vYmFy=\n"},
+ {invalid, "", "Zm9vYmFy==\n"},
+ {invalid, "", "Zm9vYmFy===\n"},
+ {invalid, "", "Z"},
+ {invalid, "", "Z\n"},
+ {invalid, "", "ab!c"},
+ {invalid, "", "ab=c"},
+ {invalid, "", "abc"},
+
+ {canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA==\n"},
+ {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA\n==\n"},
+ {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n=\n"},
+ {invalid, "",
+ "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n==\n"},
+ {canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh"
+ "4eHh4eHh4\n"},
+ {canonical,
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh"
+ "4eHh4eHh4eHh4eA==\n"},
+ {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh\n4eHh4eHh"
+ "4eHh4eHh4eHh4eA==\n"},
+ {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e"
+ "Hh4eHh4eHh4eA==\n"},
+ {invalid, "",
+ "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=="
+ "\neHh4eHh4eHh4eHh4eHh4eHh4\n"},
+
+ // A '-' has traditionally been treated as the end of the data by OpenSSL
+ // and anything following would be ignored. BoringSSL does not accept this
+ // non-standard extension.
+ {invalid, "", "Zm9vYmFy-anythinggoes"},
+ {invalid, "", "Zm9vYmFy\n-anythinggoes"},
+
+ // CVE-2015-0292
+ {invalid, "",
+ "ZW5jb2RlIG1lCg==========================================================="
+ "=======\n"},
};
static const size_t kNumTests = sizeof(kTestVectors) / sizeof(kTestVectors[0]);
-static bool TestEncode() {
- for (size_t i = 0; i < kNumTests; i++) {
+// RemoveNewlines returns a copy of |in| with all '\n' characters removed.
+static std::string RemoveNewlines(const char *in) {
+ std::string ret;
+ const size_t in_len = strlen(in);
+
+ size_t i;
+ for (i = 0; i < in_len; i++) {
+ if (in[i] != '\n') {
+ ret.push_back(in[i]);
+ }
+ }
+
+ return ret;
+}
+
+static bool TestEncodeBlock() {
+ for (unsigned i = 0; i < kNumTests; i++) {
const TestVector *t = &kTestVectors[i];
- uint8_t out[9];
- size_t len = EVP_EncodeBlock(out, (const uint8_t*)t->decoded,
- strlen(t->decoded));
- if (len != strlen(t->encoded) ||
- memcmp(out, t->encoded, len) != 0) {
+ if (t->relation != canonical) {
+ continue;
+ }
+
+ const size_t decoded_len = strlen(t->decoded);
+ size_t max_encoded_len;
+ if (!EVP_EncodedLength(&max_encoded_len, decoded_len)) {
+ fprintf(stderr, "#%u: EVP_EncodedLength failed\n", i);
+ return false;
+ }
+
+ std::vector<uint8_t> out_vec(max_encoded_len);
+ uint8_t *out = out_vec.data();
+ size_t len = EVP_EncodeBlock(out, (const uint8_t *)t->decoded, decoded_len);
+
+ std::string encoded(RemoveNewlines(t->encoded));
+ if (len != encoded.size() ||
+ memcmp(out, encoded.data(), len) != 0) {
fprintf(stderr, "encode(\"%s\") = \"%.*s\", want \"%s\"\n",
- t->decoded, (int)len, (const char*)out, t->encoded);
+ t->decoded, (int)len, (const char*)out, encoded.c_str());
return false;
}
}
+
return true;
}
-static bool TestDecode() {
- uint8_t out[6];
+static bool TestDecodeBase64() {
size_t len;
- for (size_t i = 0; i < kNumTests; i++) {
- // Test the normal API.
+ for (unsigned i = 0; i < kNumTests; i++) {
const TestVector *t = &kTestVectors[i];
- size_t expected_len = strlen(t->decoded);
- if (!EVP_DecodeBase64(out, &len, sizeof(out),
- (const uint8_t*)t->encoded, strlen(t->encoded))) {
- fprintf(stderr, "decode(\"%s\") failed\n", t->encoded);
- return false;
+
+ if (t->relation == valid) {
+ // The non-canonical encodings will generally have odd whitespace etc
+ // that |EVP_DecodeBase64| will reject.
+ continue;
}
- if (len != strlen(t->decoded) ||
- memcmp(out, t->decoded, len) != 0) {
- fprintf(stderr, "decode(\"%s\") = \"%.*s\", want \"%s\"\n",
- t->encoded, (int)len, (const char*)out, t->decoded);
- return false;
+
+ const std::string encoded(RemoveNewlines(t->encoded));
+ std::vector<uint8_t> out_vec(encoded.size());
+ uint8_t *out = out_vec.data();
+
+ int ok = EVP_DecodeBase64(out, &len, out_vec.size(),
+ (const uint8_t *)encoded.data(), encoded.size());
+
+ if (t->relation == invalid) {
+ if (ok) {
+ fprintf(stderr, "decode(\"%s\") didn't fail but should have\n",
+ encoded.c_str());
+ return false;
+ }
+ } else if (t->relation == canonical) {
+ if (!ok) {
+ fprintf(stderr, "decode(\"%s\") failed\n", encoded.c_str());
+ return false;
+ }
+
+ if (len != strlen(t->decoded) ||
+ memcmp(out, t->decoded, len) != 0) {
+ fprintf(stderr, "decode(\"%s\") = \"%.*s\", want \"%s\"\n",
+ encoded.c_str(), (int)len, (const char*)out, t->decoded);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool TestDecodeBlock() {
+ for (unsigned i = 0; i < kNumTests; i++) {
+ const TestVector *t = &kTestVectors[i];
+ if (t->relation != canonical) {
+ continue;
}
+ std::string encoded(RemoveNewlines(t->encoded));
+
+ std::vector<uint8_t> out_vec(encoded.size());
+ uint8_t *out = out_vec.data();
+
// Test that the padding behavior of the deprecated API is preserved.
- int ret = EVP_DecodeBlock(out, (const uint8_t*)t->encoded,
- strlen(t->encoded));
+ int ret =
+ EVP_DecodeBlock(out, (const uint8_t *)encoded.data(), encoded.size());
if (ret < 0) {
- fprintf(stderr, "decode(\"%s\") failed\n", t->encoded);
+ fprintf(stderr, "EVP_DecodeBlock(\"%s\") failed\n", t->encoded);
return false;
}
if (ret % 3 != 0) {
fprintf(stderr, "EVP_DecodeBlock did not ignore padding\n");
return false;
}
+ size_t expected_len = strlen(t->decoded);
if (expected_len % 3 != 0) {
ret -= 3 - (expected_len % 3);
}
@@ -96,19 +223,155 @@ static bool TestDecode() {
}
}
- if (EVP_DecodeBase64(out, &len, sizeof(out), (const uint8_t*)"a!bc", 4)) {
- fprintf(stderr, "Failed to reject invalid characters in the middle.\n");
- return false;
- }
+ return true;
+}
+
+static bool TestEncodeDecode() {
+ for (unsigned test_num = 0; test_num < kNumTests; test_num++) {
+ const TestVector *t = &kTestVectors[test_num];
+
+ EVP_ENCODE_CTX ctx;
+ const size_t decoded_len = strlen(t->decoded);
+
+ if (t->relation == canonical) {
+ size_t max_encoded_len;
+ if (!EVP_EncodedLength(&max_encoded_len, decoded_len)) {
+ fprintf(stderr, "#%u: EVP_EncodedLength failed\n", test_num);
+ return false;
+ }
+
+ // EVP_EncodeUpdate will output new lines every 64 bytes of output so we
+ // need slightly more than |EVP_EncodedLength| returns. */
+ max_encoded_len += (max_encoded_len + 63) >> 6;
+ std::vector<uint8_t> out_vec(max_encoded_len);
+ uint8_t *out = out_vec.data();
+
+ EVP_EncodeInit(&ctx);
+
+ int out_len;
+ EVP_EncodeUpdate(&ctx, out, &out_len,
+ reinterpret_cast<const uint8_t *>(t->decoded),
+ decoded_len);
+ size_t total = out_len;
+
+ EVP_EncodeFinal(&ctx, out + total, &out_len);
+ total += out_len;
+
+ if (total != strlen(t->encoded) || memcmp(out, t->encoded, total) != 0) {
+ fprintf(stderr, "#%u: EVP_EncodeUpdate produced different output: '%s' (%u)\n",
+ test_num, out, static_cast<unsigned>(total));
+ return false;
+ }
+ }
+
+ std::vector<uint8_t> out_vec(strlen(t->encoded));
+ uint8_t *out = out_vec.data();
+
+ EVP_DecodeInit(&ctx);
+ int out_len;
+ size_t total = 0;
+ int ret = EVP_DecodeUpdate(&ctx, out, &out_len,
+ reinterpret_cast<const uint8_t *>(t->encoded),
+ strlen(t->encoded));
+ if (ret != -1) {
+ total = out_len;
+ ret = EVP_DecodeFinal(&ctx, out + total, &out_len);
+ total += out_len;
+ }
+
+ switch (t->relation) {
+ case canonical:
+ case valid:
+ if (ret == -1) {
+ fprintf(stderr, "#%u: EVP_DecodeUpdate failed\n", test_num);
+ return false;
+ }
+ if (total != decoded_len || memcmp(out, t->decoded, decoded_len)) {
+ fprintf(stderr, "#%u: EVP_DecodeUpdate produced incorrect output\n",
+ test_num);
+ return false;
+ }
+ break;
- if (EVP_DecodeBase64(out, &len, sizeof(out), (const uint8_t*)"a=bc", 4)) {
- fprintf(stderr, "Failed to reject invalid characters in the middle.\n");
- return false;
+ case invalid:
+ if (ret != -1) {
+ fprintf(stderr, "#%u: EVP_DecodeUpdate was successful but shouldn't have been\n", test_num);
+ return false;
+ }
+ break;
+ }
}
- if (EVP_DecodeBase64(out, &len, sizeof(out), (const uint8_t*)"abc", 4)) {
- fprintf(stderr, "Failed to reject invalid input length.\n");
- return false;
+ return true;
+}
+
+static bool TestDecodeUpdateStreaming() {
+ for (unsigned test_num = 0; test_num < kNumTests; test_num++) {
+ const TestVector *t = &kTestVectors[test_num];
+ if (t->relation == invalid) {
+ continue;
+ }
+
+ const size_t encoded_len = strlen(t->encoded);
+
+ std::vector<uint8_t> out(encoded_len);
+
+ for (size_t chunk_size = 1; chunk_size <= encoded_len; chunk_size++) {
+ size_t out_len = 0;
+ EVP_ENCODE_CTX ctx;
+ EVP_DecodeInit(&ctx);
+
+ for (size_t i = 0; i < encoded_len;) {
+ size_t todo = encoded_len - i;
+ if (todo > chunk_size) {
+ todo = chunk_size;
+ }
+
+ int bytes_written;
+ int ret = EVP_DecodeUpdate(
+ &ctx, out.data() + out_len, &bytes_written,
+ reinterpret_cast<const uint8_t *>(t->encoded + i), todo);
+ i += todo;
+
+ switch (ret) {
+ case -1:
+ fprintf(stderr, "#%u: EVP_DecodeUpdate returned error\n", test_num);
+ return 0;
+ case 0:
+ out_len += bytes_written;
+ if (i == encoded_len ||
+ (i + 1 == encoded_len && t->encoded[i] == '\n') ||
+ /* If there was an '-' in the input (which means “EOF”) then
+ * this loop will continue to test that |EVP_DecodeUpdate| will
+ * ignore the remainder of the input. */
+ strchr(t->encoded, '-') != nullptr) {
+ break;
+ }
+
+ fprintf(stderr,
+ "#%u: EVP_DecodeUpdate returned zero before end of "
+ "encoded data\n",
+ test_num);
+ return 0;
+ default:
+ out_len += bytes_written;
+ }
+ }
+
+ int bytes_written;
+ int ret = EVP_DecodeFinal(&ctx, out.data() + out_len, &bytes_written);
+ if (ret == -1) {
+ fprintf(stderr, "#%u: EVP_DecodeFinal returned error\n", test_num);
+ return 0;
+ }
+ out_len += bytes_written;
+
+ if (out_len != strlen(t->decoded) ||
+ memcmp(out.data(), t->decoded, out_len) != 0) {
+ fprintf(stderr, "#%u: incorrect output\n", test_num);
+ return 0;
+ }
+ }
}
return true;
@@ -117,8 +380,11 @@ static bool TestDecode() {
int main(void) {
CRYPTO_library_init();
- if (!TestEncode() ||
- !TestDecode()) {
+ if (!TestEncodeBlock() ||
+ !TestDecodeBase64() ||
+ !TestDecodeBlock() ||
+ !TestDecodeUpdateStreaming() ||
+ !TestEncodeDecode()) {
return 1;
}
diff --git a/crypto/bio/bio_mem.c b/crypto/bio/bio_mem.c
index 6864f6f1..844fba7e 100644
--- a/crypto/bio/bio_mem.c
+++ b/crypto/bio/bio_mem.c
@@ -64,7 +64,7 @@
#include <openssl/mem.h>
-BIO *BIO_new_mem_buf(void *buf, int len) {
+BIO *BIO_new_mem_buf(const void *buf, int len) {
BIO *ret;
BUF_MEM *b;
const size_t size = len < 0 ? strlen((char *)buf) : (size_t)len;
@@ -80,7 +80,8 @@ BIO *BIO_new_mem_buf(void *buf, int len) {
}
b = (BUF_MEM *)ret->ptr;
- b->data = buf;
+ /* BIO_FLAGS_MEM_RDONLY ensures |b->data| is not written to. */
+ b->data = (void *)buf;
b->length = size;
b->max = size;
diff --git a/crypto/bio/bio_test.cc b/crypto/bio/bio_test.cc
index bc755c10..f2eb20ba 100644
--- a/crypto/bio/bio_test.cc
+++ b/crypto/bio/bio_test.cc
@@ -27,10 +27,10 @@
#include <unistd.h>
#else
#include <io.h>
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
#include <ws2tcpip.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include <openssl/bio.h>
@@ -331,7 +331,7 @@ static bool TestPrintf() {
static bool ReadASN1(bool should_succeed, const uint8_t *data, size_t data_len,
size_t expected_len, size_t max_len) {
- ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(data), data_len));
+ ScopedBIO bio(BIO_new_mem_buf(data, data_len));
uint8_t *out;
size_t out_len;
diff --git a/crypto/bio/connect.c b/crypto/bio/connect.c
index 0b0bf131..7e544474 100644
--- a/crypto/bio/connect.c
+++ b/crypto/bio/connect.c
@@ -58,7 +58,6 @@
#include <assert.h>
#include <errno.h>
-#include <stdio.h>
#include <string.h>
#if !defined(OPENSSL_WINDOWS)
@@ -67,10 +66,10 @@
#include <arpa/inet.h>
#include <unistd.h>
#else
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
#include <ws2tcpip.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include <openssl/buf.h>
@@ -539,6 +538,16 @@ int BIO_set_conn_port(BIO *bio, const char *port_str) {
return BIO_ctrl(bio, BIO_C_SET_CONNECT, 1, (void*) port_str);
}
+int BIO_set_conn_int_port(BIO *bio, const int *port) {
+ char buf[DECIMAL_SIZE(int) + 1];
+ BIO_snprintf(buf, sizeof(buf), "%d", *port);
+ return BIO_set_conn_port(bio, buf);
+}
+
int BIO_set_nbio(BIO *bio, int on) {
return BIO_ctrl(bio, BIO_C_SET_NBIO, on, NULL);
}
+
+int BIO_do_connect(BIO *bio) {
+ return BIO_ctrl(bio, BIO_C_DO_STATE_MACHINE, 0, NULL);
+}
diff --git a/crypto/bio/fd.c b/crypto/bio/fd.c
index 0b3484c9..13833df5 100644
--- a/crypto/bio/fd.c
+++ b/crypto/bio/fd.c
@@ -63,15 +63,17 @@
#include <unistd.h>
#else
#include <io.h>
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include <openssl/buf.h>
#include <openssl/err.h>
#include <openssl/mem.h>
+#include "internal.h"
+
static int bio_fd_non_fatal_error(int err) {
if (
@@ -106,20 +108,25 @@ static int bio_fd_non_fatal_error(int err) {
}
#if defined(OPENSSL_WINDOWS)
-int bio_fd_should_retry(int i) {
- if (i == -1) {
- return bio_fd_non_fatal_error((int)GetLastError());
- }
- return 0;
-}
+ #define BORINGSSL_ERRNO (int)GetLastError()
+ #define BORINGSSL_CLOSE _close
+ #define BORINGSSL_LSEEK _lseek
+ #define BORINGSSL_READ _read
+ #define BORINGSSL_WRITE _write
#else
+ #define BORINGSSL_ERRNO errno
+ #define BORINGSSL_CLOSE close
+ #define BORINGSSL_LSEEK lseek
+ #define BORINGSSL_READ read
+ #define BORINGSSL_WRITE write
+#endif
+
int bio_fd_should_retry(int i) {
if (i == -1) {
- return bio_fd_non_fatal_error(errno);
+ return bio_fd_non_fatal_error(BORINGSSL_ERRNO);
}
return 0;
}
-#endif
BIO *BIO_new_fd(int fd, int close_flag) {
BIO *ret = BIO_new(BIO_s_fd());
@@ -143,7 +150,7 @@ static int fd_free(BIO *bio) {
if (bio->shutdown) {
if (bio->init) {
- close(bio->num);
+ BORINGSSL_CLOSE(bio->num);
}
bio->init = 0;
}
@@ -153,7 +160,7 @@ static int fd_free(BIO *bio) {
static int fd_read(BIO *b, char *out, int outl) {
int ret = 0;
- ret = read(b->num, out, outl);
+ ret = BORINGSSL_READ(b->num, out, outl);
BIO_clear_retry_flags(b);
if (ret <= 0) {
if (bio_fd_should_retry(ret)) {
@@ -165,7 +172,7 @@ static int fd_read(BIO *b, char *out, int outl) {
}
static int fd_write(BIO *b, const char *in, int inl) {
- int ret = write(b->num, in, inl);
+ int ret = BORINGSSL_WRITE(b->num, in, inl);
BIO_clear_retry_flags(b);
if (ret <= 0) {
if (bio_fd_should_retry(ret)) {
@@ -186,14 +193,14 @@ static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) {
case BIO_C_FILE_SEEK:
ret = 0;
if (b->init) {
- ret = (long)lseek(b->num, num, SEEK_SET);
+ ret = (long)BORINGSSL_LSEEK(b->num, num, SEEK_SET);
}
break;
case BIO_C_FILE_TELL:
case BIO_CTRL_INFO:
ret = 0;
if (b->init) {
- ret = (long)lseek(b->num, 0, SEEK_CUR);
+ ret = (long)BORINGSSL_LSEEK(b->num, 0, SEEK_CUR);
}
break;
case BIO_C_SET_FD:
diff --git a/crypto/bio/file.c b/crypto/bio/file.c
index 9e29b43c..b903bc28 100644
--- a/crypto/bio/file.c
+++ b/crypto/bio/file.c
@@ -87,47 +87,11 @@
#define BIO_FP_WRITE 0x04
#define BIO_FP_APPEND 0x08
-static FILE *open_file(const char *filename, const char *mode) {
-#if defined(OPENSSL_WINDOWS) && defined(CP_UTF8)
- int sz, len_0 = (int)strlen(filename) + 1;
- DWORD flags;
-
- /* Basically there are three cases to cover: a) filename is pure ASCII
- * string; b) actual UTF-8 encoded string and c) locale-ized string, i.e. one
- * containing 8-bit characters that are meaningful in current system locale.
- * If filename is pure ASCII or real UTF-8 encoded string,
- * MultiByteToWideChar succeeds and _wfopen works. If filename is locale-ized
- * string, chances are that MultiByteToWideChar fails reporting
- * ERROR_NO_UNICODE_TRANSLATION, in which case we fall back to fopen... */
- if ((sz = MultiByteToWideChar(CP_UTF8, (flags = MB_ERR_INVALID_CHARS),
- filename, len_0, NULL, 0)) > 0 ||
- (GetLastError() == ERROR_INVALID_FLAGS &&
- (sz = MultiByteToWideChar(CP_UTF8, (flags = 0), filename, len_0, NULL,
- 0)) > 0)) {
- WCHAR wmode[8];
- WCHAR *wfilename = _alloca(sz * sizeof(WCHAR));
-
- if (MultiByteToWideChar(CP_UTF8, flags, filename, len_0, wfilename, sz) &&
- MultiByteToWideChar(CP_UTF8, 0, mode, strlen(mode) + 1, wmode,
- sizeof(wmode) / sizeof(wmode[0])) &&
- (file = _wfopen(wfilename, wmode)) == NULL &&
- (errno == ENOENT ||
- errno == EBADF)) /* UTF-8 decode succeeded, but no file, filename
- * could still have been locale-ized... */
- return fopen(filename, mode);
- } else if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
- return fopen(filename, mode);
- }
-#else
- return fopen(filename, mode);
-#endif
-}
-
BIO *BIO_new_file(const char *filename, const char *mode) {
BIO *ret;
FILE *file;
- file = open_file(filename, mode);
+ file = fopen(filename, mode);
if (file == NULL) {
OPENSSL_PUT_SYSTEM_ERROR();
@@ -256,7 +220,7 @@ static long file_ctrl(BIO *b, int cmd, long num, void *ptr) {
ret = 0;
break;
}
- fp = open_file(ptr, p);
+ fp = fopen(ptr, p);
if (fp == NULL) {
OPENSSL_PUT_SYSTEM_ERROR();
ERR_add_error_data(5, "fopen('", ptr, "','", p, "')");
diff --git a/crypto/bio/internal.h b/crypto/bio/internal.h
index d9a34f18..4ec77fad 100644
--- a/crypto/bio/internal.h
+++ b/crypto/bio/internal.h
@@ -67,6 +67,9 @@ typedef unsigned short u_short;
#include <sys/types.h>
#include <sys/socket.h>
#else
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
+#include <winsock2.h>
+OPENSSL_MSVC_PRAGMA(warning(pop))
typedef int socklen_t;
#endif
diff --git a/crypto/bio/pair.c b/crypto/bio/pair.c
index fba4be2c..2da2d203 100644
--- a/crypto/bio/pair.c
+++ b/crypto/bio/pair.c
@@ -742,7 +742,7 @@ static const BIO_METHOD methods_biop = {
bio_free, NULL /* no bio_callback_ctrl */
};
-const BIO_METHOD *bio_s_bio(void) { return &methods_biop; }
+static const BIO_METHOD *bio_s_bio(void) { return &methods_biop; }
int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1,
BIO** bio2_p, size_t writebuf2) {
diff --git a/crypto/bio/socket.c b/crypto/bio/socket.c
index 98f32a62..0520c3e8 100644
--- a/crypto/bio/socket.c
+++ b/crypto/bio/socket.c
@@ -63,9 +63,9 @@
#if !defined(OPENSSL_WINDOWS)
#include <unistd.h>
#else
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma comment(lib, "Ws2_32.lib")
#endif
@@ -110,7 +110,11 @@ static int sock_read(BIO *b, char *out, int outl) {
}
bio_clear_socket_error();
+#if defined(OPENSSL_WINDOWS)
ret = recv(b->num, out, outl, 0);
+#else
+ ret = read(b->num, out, outl);
+#endif
BIO_clear_retry_flags(b);
if (ret <= 0) {
if (bio_fd_should_retry(ret)) {
@@ -124,7 +128,11 @@ static int sock_write(BIO *b, const char *in, int inl) {
int ret;
bio_clear_socket_error();
+#if defined(OPENSSL_WINDOWS)
ret = send(b->num, in, inl, 0);
+#else
+ ret = write(b->num, in, inl);
+#endif
BIO_clear_retry_flags(b);
if (ret <= 0) {
if (bio_fd_should_retry(ret)) {
diff --git a/crypto/bio/socket_helper.c b/crypto/bio/socket_helper.c
index 4ddc094d..95007884 100644
--- a/crypto/bio/socket_helper.c
+++ b/crypto/bio/socket_helper.c
@@ -26,10 +26,10 @@
#include <netdb.h>
#include <unistd.h>
#else
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <winsock2.h>
#include <ws2tcpip.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include "internal.h"
diff --git a/crypto/bn/asm/armv4-mont.pl b/crypto/bn/asm/armv4-mont.pl
index afcbdf62..b7511128 100644
--- a/crypto/bn/asm/armv4-mont.pl
+++ b/crypto/bn/asm/armv4-mont.pl
@@ -107,7 +107,7 @@ bn_mul_mont:
#ifdef __APPLE__
ldr r0,[r0]
#endif
- tst r0,#1 @ NEON available?
+ tst r0,#ARMV7_NEON @ NEON available?
ldmia sp, {r0,r2}
beq .Lialu
add sp,sp,#8
diff --git a/crypto/bn/asm/rsaz-avx2.pl b/crypto/bn/asm/rsaz-avx2.pl
index bbceccb3..6b57bd0b 100644..100755
--- a/crypto/bn/asm/rsaz-avx2.pl
+++ b/crypto/bn/asm/rsaz-avx2.pl
@@ -427,7 +427,7 @@ $TEMP2 = $B2;
$TEMP3 = $Y1;
$TEMP4 = $Y2;
$code.=<<___;
- #we need to fix indexes 32-39 to avoid overflow
+ # we need to fix indices 32-39 to avoid overflow
vmovdqu 32*8(%rsp), $ACC8 # 32*8-192($tp0),
vmovdqu 32*9(%rsp), $ACC1 # 32*9-192($tp0)
vmovdqu 32*10(%rsp), $ACC2 # 32*10-192($tp0)
@@ -1576,68 +1576,128 @@ rsaz_1024_scatter5_avx2:
.type rsaz_1024_gather5_avx2,\@abi-omnipotent
.align 32
rsaz_1024_gather5_avx2:
+ vzeroupper
+ mov %rsp,%r11
___
$code.=<<___ if ($win64);
lea -0x88(%rsp),%rax
- vzeroupper
.LSEH_begin_rsaz_1024_gather5:
# I can't trust assembler to use specific encoding:-(
- .byte 0x48,0x8d,0x60,0xe0 #lea -0x20(%rax),%rsp
- .byte 0xc5,0xf8,0x29,0x70,0xe0 #vmovaps %xmm6,-0x20(%rax)
- .byte 0xc5,0xf8,0x29,0x78,0xf0 #vmovaps %xmm7,-0x10(%rax)
- .byte 0xc5,0x78,0x29,0x40,0x00 #vmovaps %xmm8,0(%rax)
- .byte 0xc5,0x78,0x29,0x48,0x10 #vmovaps %xmm9,0x10(%rax)
- .byte 0xc5,0x78,0x29,0x50,0x20 #vmovaps %xmm10,0x20(%rax)
- .byte 0xc5,0x78,0x29,0x58,0x30 #vmovaps %xmm11,0x30(%rax)
- .byte 0xc5,0x78,0x29,0x60,0x40 #vmovaps %xmm12,0x40(%rax)
- .byte 0xc5,0x78,0x29,0x68,0x50 #vmovaps %xmm13,0x50(%rax)
- .byte 0xc5,0x78,0x29,0x70,0x60 #vmovaps %xmm14,0x60(%rax)
- .byte 0xc5,0x78,0x29,0x78,0x70 #vmovaps %xmm15,0x70(%rax)
+ .byte 0x48,0x8d,0x60,0xe0 # lea -0x20(%rax),%rsp
+ .byte 0xc5,0xf8,0x29,0x70,0xe0 # vmovaps %xmm6,-0x20(%rax)
+ .byte 0xc5,0xf8,0x29,0x78,0xf0 # vmovaps %xmm7,-0x10(%rax)
+ .byte 0xc5,0x78,0x29,0x40,0x00 # vmovaps %xmm8,0(%rax)
+ .byte 0xc5,0x78,0x29,0x48,0x10 # vmovaps %xmm9,0x10(%rax)
+ .byte 0xc5,0x78,0x29,0x50,0x20 # vmovaps %xmm10,0x20(%rax)
+ .byte 0xc5,0x78,0x29,0x58,0x30 # vmovaps %xmm11,0x30(%rax)
+ .byte 0xc5,0x78,0x29,0x60,0x40 # vmovaps %xmm12,0x40(%rax)
+ .byte 0xc5,0x78,0x29,0x68,0x50 # vmovaps %xmm13,0x50(%rax)
+ .byte 0xc5,0x78,0x29,0x70,0x60 # vmovaps %xmm14,0x60(%rax)
+ .byte 0xc5,0x78,0x29,0x78,0x70 # vmovaps %xmm15,0x70(%rax)
___
$code.=<<___;
- lea .Lgather_table(%rip),%r11
- mov $power,%eax
- and \$3,$power
- shr \$2,%eax # cache line number
- shl \$4,$power # offset within cache line
-
- vmovdqu -32(%r11),%ymm7 # .Lgather_permd
- vpbroadcastb 8(%r11,%rax), %xmm8
- vpbroadcastb 7(%r11,%rax), %xmm9
- vpbroadcastb 6(%r11,%rax), %xmm10
- vpbroadcastb 5(%r11,%rax), %xmm11
- vpbroadcastb 4(%r11,%rax), %xmm12
- vpbroadcastb 3(%r11,%rax), %xmm13
- vpbroadcastb 2(%r11,%rax), %xmm14
- vpbroadcastb 1(%r11,%rax), %xmm15
-
- lea 64($inp,$power),$inp
- mov \$64,%r11 # size optimization
- mov \$9,%eax
- jmp .Loop_gather_1024
+ lea -0x100(%rsp),%rsp
+ and \$-32, %rsp
+ lea .Linc(%rip), %r10
+ lea -128(%rsp),%rax # control u-op density
+
+ vmovd $power, %xmm4
+ vmovdqa (%r10),%ymm0
+ vmovdqa 32(%r10),%ymm1
+ vmovdqa 64(%r10),%ymm5
+ vpbroadcastd %xmm4,%ymm4
+
+ vpaddd %ymm5, %ymm0, %ymm2
+ vpcmpeqd %ymm4, %ymm0, %ymm0
+ vpaddd %ymm5, %ymm1, %ymm3
+ vpcmpeqd %ymm4, %ymm1, %ymm1
+ vmovdqa %ymm0, 32*0+128(%rax)
+ vpaddd %ymm5, %ymm2, %ymm0
+ vpcmpeqd %ymm4, %ymm2, %ymm2
+ vmovdqa %ymm1, 32*1+128(%rax)
+ vpaddd %ymm5, %ymm3, %ymm1
+ vpcmpeqd %ymm4, %ymm3, %ymm3
+ vmovdqa %ymm2, 32*2+128(%rax)
+ vpaddd %ymm5, %ymm0, %ymm2
+ vpcmpeqd %ymm4, %ymm0, %ymm0
+ vmovdqa %ymm3, 32*3+128(%rax)
+ vpaddd %ymm5, %ymm1, %ymm3
+ vpcmpeqd %ymm4, %ymm1, %ymm1
+ vmovdqa %ymm0, 32*4+128(%rax)
+ vpaddd %ymm5, %ymm2, %ymm8
+ vpcmpeqd %ymm4, %ymm2, %ymm2
+ vmovdqa %ymm1, 32*5+128(%rax)
+ vpaddd %ymm5, %ymm3, %ymm9
+ vpcmpeqd %ymm4, %ymm3, %ymm3
+ vmovdqa %ymm2, 32*6+128(%rax)
+ vpaddd %ymm5, %ymm8, %ymm10
+ vpcmpeqd %ymm4, %ymm8, %ymm8
+ vmovdqa %ymm3, 32*7+128(%rax)
+ vpaddd %ymm5, %ymm9, %ymm11
+ vpcmpeqd %ymm4, %ymm9, %ymm9
+ vpaddd %ymm5, %ymm10, %ymm12
+ vpcmpeqd %ymm4, %ymm10, %ymm10
+ vpaddd %ymm5, %ymm11, %ymm13
+ vpcmpeqd %ymm4, %ymm11, %ymm11
+ vpaddd %ymm5, %ymm12, %ymm14
+ vpcmpeqd %ymm4, %ymm12, %ymm12
+ vpaddd %ymm5, %ymm13, %ymm15
+ vpcmpeqd %ymm4, %ymm13, %ymm13
+ vpcmpeqd %ymm4, %ymm14, %ymm14
+ vpcmpeqd %ymm4, %ymm15, %ymm15
+
+ vmovdqa -32(%r10),%ymm7 # .Lgather_permd
+ lea 128($inp), $inp
+ mov \$9,$power
-.align 32
.Loop_gather_1024:
- vpand -64($inp), %xmm8,%xmm0
- vpand ($inp), %xmm9,%xmm1
- vpand 64($inp), %xmm10,%xmm2
- vpand ($inp,%r11,2), %xmm11,%xmm3
- vpor %xmm0,%xmm1,%xmm1
- vpand 64($inp,%r11,2), %xmm12,%xmm4
- vpor %xmm2,%xmm3,%xmm3
- vpand ($inp,%r11,4), %xmm13,%xmm5
- vpor %xmm1,%xmm3,%xmm3
- vpand 64($inp,%r11,4), %xmm14,%xmm6
- vpor %xmm4,%xmm5,%xmm5
- vpand -128($inp,%r11,8), %xmm15,%xmm2
- lea ($inp,%r11,8),$inp
- vpor %xmm3,%xmm5,%xmm5
- vpor %xmm2,%xmm6,%xmm6
- vpor %xmm5,%xmm6,%xmm6
- vpermd %ymm6,%ymm7,%ymm6
- vmovdqu %ymm6,($out)
+ vmovdqa 32*0-128($inp), %ymm0
+ vmovdqa 32*1-128($inp), %ymm1
+ vmovdqa 32*2-128($inp), %ymm2
+ vmovdqa 32*3-128($inp), %ymm3
+ vpand 32*0+128(%rax), %ymm0, %ymm0
+ vpand 32*1+128(%rax), %ymm1, %ymm1
+ vpand 32*2+128(%rax), %ymm2, %ymm2
+ vpor %ymm0, %ymm1, %ymm4
+ vpand 32*3+128(%rax), %ymm3, %ymm3
+ vmovdqa 32*4-128($inp), %ymm0
+ vmovdqa 32*5-128($inp), %ymm1
+ vpor %ymm2, %ymm3, %ymm5
+ vmovdqa 32*6-128($inp), %ymm2
+ vmovdqa 32*7-128($inp), %ymm3
+ vpand 32*4+128(%rax), %ymm0, %ymm0
+ vpand 32*5+128(%rax), %ymm1, %ymm1
+ vpand 32*6+128(%rax), %ymm2, %ymm2
+ vpor %ymm0, %ymm4, %ymm4
+ vpand 32*7+128(%rax), %ymm3, %ymm3
+ vpand 32*8-128($inp), %ymm8, %ymm0
+ vpor %ymm1, %ymm5, %ymm5
+ vpand 32*9-128($inp), %ymm9, %ymm1
+ vpor %ymm2, %ymm4, %ymm4
+ vpand 32*10-128($inp),%ymm10, %ymm2
+ vpor %ymm3, %ymm5, %ymm5
+ vpand 32*11-128($inp),%ymm11, %ymm3
+ vpor %ymm0, %ymm4, %ymm4
+ vpand 32*12-128($inp),%ymm12, %ymm0
+ vpor %ymm1, %ymm5, %ymm5
+ vpand 32*13-128($inp),%ymm13, %ymm1
+ vpor %ymm2, %ymm4, %ymm4
+ vpand 32*14-128($inp),%ymm14, %ymm2
+ vpor %ymm3, %ymm5, %ymm5
+ vpand 32*15-128($inp),%ymm15, %ymm3
+ lea 32*16($inp), $inp
+ vpor %ymm0, %ymm4, %ymm4
+ vpor %ymm1, %ymm5, %ymm5
+ vpor %ymm2, %ymm4, %ymm4
+ vpor %ymm3, %ymm5, %ymm5
+
+ vpor %ymm5, %ymm4, %ymm4
+ vextracti128 \$1, %ymm4, %xmm5 # upper half is cleared
+ vpor %xmm4, %xmm5, %xmm5
+ vpermd %ymm5,%ymm7,%ymm5
+ vmovdqu %ymm5,($out)
lea 32($out),$out
- dec %eax
+ dec $power
jnz .Loop_gather_1024
vpxor %ymm0,%ymm0,%ymm0
@@ -1645,20 +1705,20 @@ $code.=<<___;
vzeroupper
___
$code.=<<___ if ($win64);
- movaps (%rsp),%xmm6
- movaps 0x10(%rsp),%xmm7
- movaps 0x20(%rsp),%xmm8
- movaps 0x30(%rsp),%xmm9
- movaps 0x40(%rsp),%xmm10
- movaps 0x50(%rsp),%xmm11
- movaps 0x60(%rsp),%xmm12
- movaps 0x70(%rsp),%xmm13
- movaps 0x80(%rsp),%xmm14
- movaps 0x90(%rsp),%xmm15
- lea 0xa8(%rsp),%rsp
+ movaps -0xa8(%r11),%xmm6
+ movaps -0x98(%r11),%xmm7
+ movaps -0x88(%r11),%xmm8
+ movaps -0x78(%r11),%xmm9
+ movaps -0x68(%r11),%xmm10
+ movaps -0x58(%r11),%xmm11
+ movaps -0x48(%r11),%xmm12
+ movaps -0x38(%r11),%xmm13
+ movaps -0x28(%r11),%xmm14
+ movaps -0x18(%r11),%xmm15
.LSEH_end_rsaz_1024_gather5:
___
$code.=<<___;
+ lea (%r11),%rsp
ret
.size rsaz_1024_gather5_avx2,.-rsaz_1024_gather5_avx2
___
@@ -1692,8 +1752,10 @@ $code.=<<___;
.long 0,2,4,6,7,7,7,7
.Lgather_permd:
.long 0,7,1,7,2,7,3,7
-.Lgather_table:
- .byte 0,0,0,0,0,0,0,0, 0xff,0,0,0,0,0,0,0
+.Linc:
+ .long 0,0,0,0, 1,1,1,1
+ .long 2,2,2,2, 3,3,3,3
+ .long 4,4,4,4, 4,4,4,4
.align 64
___
@@ -1821,18 +1883,19 @@ rsaz_se_handler:
.rva rsaz_se_handler
.rva .Lmul_1024_body,.Lmul_1024_epilogue
.LSEH_info_rsaz_1024_gather5:
- .byte 0x01,0x33,0x16,0x00
- .byte 0x36,0xf8,0x09,0x00 #vmovaps 0x90(rsp),xmm15
- .byte 0x31,0xe8,0x08,0x00 #vmovaps 0x80(rsp),xmm14
- .byte 0x2c,0xd8,0x07,0x00 #vmovaps 0x70(rsp),xmm13
- .byte 0x27,0xc8,0x06,0x00 #vmovaps 0x60(rsp),xmm12
- .byte 0x22,0xb8,0x05,0x00 #vmovaps 0x50(rsp),xmm11
- .byte 0x1d,0xa8,0x04,0x00 #vmovaps 0x40(rsp),xmm10
- .byte 0x18,0x98,0x03,0x00 #vmovaps 0x30(rsp),xmm9
- .byte 0x13,0x88,0x02,0x00 #vmovaps 0x20(rsp),xmm8
- .byte 0x0e,0x78,0x01,0x00 #vmovaps 0x10(rsp),xmm7
- .byte 0x09,0x68,0x00,0x00 #vmovaps 0x00(rsp),xmm6
- .byte 0x04,0x01,0x15,0x00 #sub rsp,0xa8
+ .byte 0x01,0x36,0x17,0x0b
+ .byte 0x36,0xf8,0x09,0x00 # vmovaps 0x90(rsp),xmm15
+ .byte 0x31,0xe8,0x08,0x00 # vmovaps 0x80(rsp),xmm14
+ .byte 0x2c,0xd8,0x07,0x00 # vmovaps 0x70(rsp),xmm13
+ .byte 0x27,0xc8,0x06,0x00 # vmovaps 0x60(rsp),xmm12
+ .byte 0x22,0xb8,0x05,0x00 # vmovaps 0x50(rsp),xmm11
+ .byte 0x1d,0xa8,0x04,0x00 # vmovaps 0x40(rsp),xmm10
+ .byte 0x18,0x98,0x03,0x00 # vmovaps 0x30(rsp),xmm9
+ .byte 0x13,0x88,0x02,0x00 # vmovaps 0x20(rsp),xmm8
+ .byte 0x0e,0x78,0x01,0x00 # vmovaps 0x10(rsp),xmm7
+ .byte 0x09,0x68,0x00,0x00 # vmovaps 0x00(rsp),xmm6
+ .byte 0x04,0x01,0x15,0x00 # sub rsp,0xa8
+ .byte 0x00,0xb3,0x00,0x00 # set_frame r11
___
}
diff --git a/crypto/bn/asm/rsaz-x86_64.pl b/crypto/bn/asm/rsaz-x86_64.pl
index 4113d533..c38bde95 100644..100755
--- a/crypto/bn/asm/rsaz-x86_64.pl
+++ b/crypto/bn/asm/rsaz-x86_64.pl
@@ -902,9 +902,76 @@ rsaz_512_mul_gather4:
push %r14
push %r15
- mov $pwr, $pwr
- subq \$128+24, %rsp
+ subq \$`128+24+($win64?0xb0:0)`, %rsp
+___
+$code.=<<___ if ($win64);
+ movaps %xmm6,0xa0(%rsp)
+ movaps %xmm7,0xb0(%rsp)
+ movaps %xmm8,0xc0(%rsp)
+ movaps %xmm9,0xd0(%rsp)
+ movaps %xmm10,0xe0(%rsp)
+ movaps %xmm11,0xf0(%rsp)
+ movaps %xmm12,0x100(%rsp)
+ movaps %xmm13,0x110(%rsp)
+ movaps %xmm14,0x120(%rsp)
+ movaps %xmm15,0x130(%rsp)
+___
+$code.=<<___;
.Lmul_gather4_body:
+ movd $pwr,%xmm8
+ movdqa .Linc+16(%rip),%xmm1 # 00000002000000020000000200000002
+ movdqa .Linc(%rip),%xmm0 # 00000001000000010000000000000000
+
+ pshufd \$0,%xmm8,%xmm8 # broadcast $power
+ movdqa %xmm1,%xmm7
+ movdqa %xmm1,%xmm2
+___
+########################################################################
+# calculate mask by comparing 0..15 to $power
+#
+for($i=0;$i<4;$i++) {
+$code.=<<___;
+ paddd %xmm`$i`,%xmm`$i+1`
+ pcmpeqd %xmm8,%xmm`$i`
+ movdqa %xmm7,%xmm`$i+3`
+___
+}
+for(;$i<7;$i++) {
+$code.=<<___;
+ paddd %xmm`$i`,%xmm`$i+1`
+ pcmpeqd %xmm8,%xmm`$i`
+___
+}
+$code.=<<___;
+ pcmpeqd %xmm8,%xmm7
+
+ movdqa 16*0($bp),%xmm8
+ movdqa 16*1($bp),%xmm9
+ movdqa 16*2($bp),%xmm10
+ movdqa 16*3($bp),%xmm11
+ pand %xmm0,%xmm8
+ movdqa 16*4($bp),%xmm12
+ pand %xmm1,%xmm9
+ movdqa 16*5($bp),%xmm13
+ pand %xmm2,%xmm10
+ movdqa 16*6($bp),%xmm14
+ pand %xmm3,%xmm11
+ movdqa 16*7($bp),%xmm15
+ leaq 128($bp), %rbp
+ pand %xmm4,%xmm12
+ pand %xmm5,%xmm13
+ pand %xmm6,%xmm14
+ pand %xmm7,%xmm15
+ por %xmm10,%xmm8
+ por %xmm11,%xmm9
+ por %xmm12,%xmm8
+ por %xmm13,%xmm9
+ por %xmm14,%xmm8
+ por %xmm15,%xmm9
+
+ por %xmm9,%xmm8
+ pshufd \$0x4e,%xmm8,%xmm9
+ por %xmm9,%xmm8
___
$code.=<<___ if ($addx);
movl \$0x80100,%r11d
@@ -913,45 +980,38 @@ $code.=<<___ if ($addx);
je .Lmulx_gather
___
$code.=<<___;
- movl 64($bp,$pwr,4), %eax
- movq $out, %xmm0 # off-load arguments
- movl ($bp,$pwr,4), %ebx
- movq $mod, %xmm1
- movq $n0, 128(%rsp)
+ movq %xmm8,%rbx
+
+ movq $n0, 128(%rsp) # off-load arguments
+ movq $out, 128+8(%rsp)
+ movq $mod, 128+16(%rsp)
- shlq \$32, %rax
- or %rax, %rbx
movq ($ap), %rax
movq 8($ap), %rcx
- leaq 128($bp,$pwr,4), %rbp
mulq %rbx # 0 iteration
movq %rax, (%rsp)
movq %rcx, %rax
movq %rdx, %r8
mulq %rbx
- movd (%rbp), %xmm4
addq %rax, %r8
movq 16($ap), %rax
movq %rdx, %r9
adcq \$0, %r9
mulq %rbx
- movd 64(%rbp), %xmm5
addq %rax, %r9
movq 24($ap), %rax
movq %rdx, %r10
adcq \$0, %r10
mulq %rbx
- pslldq \$4, %xmm5
addq %rax, %r10
movq 32($ap), %rax
movq %rdx, %r11
adcq \$0, %r11
mulq %rbx
- por %xmm5, %xmm4
addq %rax, %r11
movq 40($ap), %rax
movq %rdx, %r12
@@ -964,14 +1024,12 @@ $code.=<<___;
adcq \$0, %r13
mulq %rbx
- leaq 128(%rbp), %rbp
addq %rax, %r13
movq 56($ap), %rax
movq %rdx, %r14
adcq \$0, %r14
mulq %rbx
- movq %xmm4, %rbx
addq %rax, %r14
movq ($ap), %rax
movq %rdx, %r15
@@ -983,6 +1041,35 @@ $code.=<<___;
.align 32
.Loop_mul_gather:
+ movdqa 16*0(%rbp),%xmm8
+ movdqa 16*1(%rbp),%xmm9
+ movdqa 16*2(%rbp),%xmm10
+ movdqa 16*3(%rbp),%xmm11
+ pand %xmm0,%xmm8
+ movdqa 16*4(%rbp),%xmm12
+ pand %xmm1,%xmm9
+ movdqa 16*5(%rbp),%xmm13
+ pand %xmm2,%xmm10
+ movdqa 16*6(%rbp),%xmm14
+ pand %xmm3,%xmm11
+ movdqa 16*7(%rbp),%xmm15
+ leaq 128(%rbp), %rbp
+ pand %xmm4,%xmm12
+ pand %xmm5,%xmm13
+ pand %xmm6,%xmm14
+ pand %xmm7,%xmm15
+ por %xmm10,%xmm8
+ por %xmm11,%xmm9
+ por %xmm12,%xmm8
+ por %xmm13,%xmm9
+ por %xmm14,%xmm8
+ por %xmm15,%xmm9
+
+ por %xmm9,%xmm8
+ pshufd \$0x4e,%xmm8,%xmm9
+ por %xmm9,%xmm8
+ movq %xmm8,%rbx
+
mulq %rbx
addq %rax, %r8
movq 8($ap), %rax
@@ -991,7 +1078,6 @@ $code.=<<___;
adcq \$0, %r8
mulq %rbx
- movd (%rbp), %xmm4
addq %rax, %r9
movq 16($ap), %rax
adcq \$0, %rdx
@@ -1000,7 +1086,6 @@ $code.=<<___;
adcq \$0, %r9
mulq %rbx
- movd 64(%rbp), %xmm5
addq %rax, %r10
movq 24($ap), %rax
adcq \$0, %rdx
@@ -1009,7 +1094,6 @@ $code.=<<___;
adcq \$0, %r10
mulq %rbx
- pslldq \$4, %xmm5
addq %rax, %r11
movq 32($ap), %rax
adcq \$0, %rdx
@@ -1018,7 +1102,6 @@ $code.=<<___;
adcq \$0, %r11
mulq %rbx
- por %xmm5, %xmm4
addq %rax, %r12
movq 40($ap), %rax
adcq \$0, %rdx
@@ -1043,7 +1126,6 @@ $code.=<<___;
adcq \$0, %r14
mulq %rbx
- movq %xmm4, %rbx
addq %rax, %r15
movq ($ap), %rax
adcq \$0, %rdx
@@ -1051,7 +1133,6 @@ $code.=<<___;
movq %rdx, %r15
adcq \$0, %r15
- leaq 128(%rbp), %rbp
leaq 8(%rdi), %rdi
decl %ecx
@@ -1066,8 +1147,8 @@ $code.=<<___;
movq %r14, 48(%rdi)
movq %r15, 56(%rdi)
- movq %xmm0, $out
- movq %xmm1, %rbp
+ movq 128+8(%rsp), $out
+ movq 128+16(%rsp), %rbp
movq (%rsp), %r8
movq 8(%rsp), %r9
@@ -1085,45 +1166,37 @@ $code.=<<___ if ($addx);
.align 32
.Lmulx_gather:
- mov 64($bp,$pwr,4), %eax
- movq $out, %xmm0 # off-load arguments
- lea 128($bp,$pwr,4), %rbp
- mov ($bp,$pwr,4), %edx
- movq $mod, %xmm1
- mov $n0, 128(%rsp)
+ movq %xmm8,%rdx
+
+ mov $n0, 128(%rsp) # off-load arguments
+ mov $out, 128+8(%rsp)
+ mov $mod, 128+16(%rsp)
- shl \$32, %rax
- or %rax, %rdx
mulx ($ap), %rbx, %r8 # 0 iteration
mov %rbx, (%rsp)
xor %edi, %edi # cf=0, of=0
mulx 8($ap), %rax, %r9
- movd (%rbp), %xmm4
mulx 16($ap), %rbx, %r10
- movd 64(%rbp), %xmm5
adcx %rax, %r8
mulx 24($ap), %rax, %r11
- pslldq \$4, %xmm5
adcx %rbx, %r9
mulx 32($ap), %rbx, %r12
- por %xmm5, %xmm4
adcx %rax, %r10
mulx 40($ap), %rax, %r13
adcx %rbx, %r11
mulx 48($ap), %rbx, %r14
- lea 128(%rbp), %rbp
adcx %rax, %r12
mulx 56($ap), %rax, %r15
- movq %xmm4, %rdx
adcx %rbx, %r13
adcx %rax, %r14
+ .byte 0x67
mov %r8, %rbx
adcx %rdi, %r15 # %rdi is 0
@@ -1132,24 +1205,48 @@ $code.=<<___ if ($addx);
.align 32
.Loop_mulx_gather:
- mulx ($ap), %rax, %r8
+ movdqa 16*0(%rbp),%xmm8
+ movdqa 16*1(%rbp),%xmm9
+ movdqa 16*2(%rbp),%xmm10
+ movdqa 16*3(%rbp),%xmm11
+ pand %xmm0,%xmm8
+ movdqa 16*4(%rbp),%xmm12
+ pand %xmm1,%xmm9
+ movdqa 16*5(%rbp),%xmm13
+ pand %xmm2,%xmm10
+ movdqa 16*6(%rbp),%xmm14
+ pand %xmm3,%xmm11
+ movdqa 16*7(%rbp),%xmm15
+ leaq 128(%rbp), %rbp
+ pand %xmm4,%xmm12
+ pand %xmm5,%xmm13
+ pand %xmm6,%xmm14
+ pand %xmm7,%xmm15
+ por %xmm10,%xmm8
+ por %xmm11,%xmm9
+ por %xmm12,%xmm8
+ por %xmm13,%xmm9
+ por %xmm14,%xmm8
+ por %xmm15,%xmm9
+
+ por %xmm9,%xmm8
+ pshufd \$0x4e,%xmm8,%xmm9
+ por %xmm9,%xmm8
+ movq %xmm8,%rdx
+
+ .byte 0xc4,0x62,0xfb,0xf6,0x86,0x00,0x00,0x00,0x00 # mulx ($ap), %rax, %r8
adcx %rax, %rbx
adox %r9, %r8
mulx 8($ap), %rax, %r9
- .byte 0x66,0x0f,0x6e,0xa5,0x00,0x00,0x00,0x00 # movd (%rbp), %xmm4
adcx %rax, %r8
adox %r10, %r9
mulx 16($ap), %rax, %r10
- movd 64(%rbp), %xmm5
- lea 128(%rbp), %rbp
adcx %rax, %r9
adox %r11, %r10
.byte 0xc4,0x62,0xfb,0xf6,0x9e,0x18,0x00,0x00,0x00 # mulx 24($ap), %rax, %r11
- pslldq \$4, %xmm5
- por %xmm5, %xmm4
adcx %rax, %r10
adox %r12, %r11
@@ -1163,10 +1260,10 @@ $code.=<<___ if ($addx);
.byte 0xc4,0x62,0xfb,0xf6,0xb6,0x30,0x00,0x00,0x00 # mulx 48($ap), %rax, %r14
adcx %rax, %r13
+ .byte 0x67
adox %r15, %r14
mulx 56($ap), %rax, %r15
- movq %xmm4, %rdx
mov %rbx, 64(%rsp,%rcx,8)
adcx %rax, %r14
adox %rdi, %r15
@@ -1185,10 +1282,10 @@ $code.=<<___ if ($addx);
mov %r14, 64+48(%rsp)
mov %r15, 64+56(%rsp)
- movq %xmm0, $out
- movq %xmm1, %rbp
+ mov 128(%rsp), %rdx # pull arguments
+ mov 128+8(%rsp), $out
+ mov 128+16(%rsp), %rbp
- mov 128(%rsp), %rdx # pull $n0
mov (%rsp), %r8
mov 8(%rsp), %r9
mov 16(%rsp), %r10
@@ -1216,6 +1313,21 @@ $code.=<<___;
call __rsaz_512_subtract
leaq 128+24+48(%rsp), %rax
+___
+$code.=<<___ if ($win64);
+ movaps 0xa0-0xc8(%rax),%xmm6
+ movaps 0xb0-0xc8(%rax),%xmm7
+ movaps 0xc0-0xc8(%rax),%xmm8
+ movaps 0xd0-0xc8(%rax),%xmm9
+ movaps 0xe0-0xc8(%rax),%xmm10
+ movaps 0xf0-0xc8(%rax),%xmm11
+ movaps 0x100-0xc8(%rax),%xmm12
+ movaps 0x110-0xc8(%rax),%xmm13
+ movaps 0x120-0xc8(%rax),%xmm14
+ movaps 0x130-0xc8(%rax),%xmm15
+ lea 0xb0(%rax),%rax
+___
+$code.=<<___;
movq -48(%rax), %r15
movq -40(%rax), %r14
movq -32(%rax), %r13
@@ -1245,7 +1357,7 @@ rsaz_512_mul_scatter4:
mov $pwr, $pwr
subq \$128+24, %rsp
.Lmul_scatter4_body:
- leaq ($tbl,$pwr,4), $tbl
+ leaq ($tbl,$pwr,8), $tbl
movq $out, %xmm0 # off-load arguments
movq $mod, %xmm1
movq $tbl, %xmm2
@@ -1316,30 +1428,14 @@ $code.=<<___;
call __rsaz_512_subtract
- movl %r8d, 64*0($inp) # scatter
- shrq \$32, %r8
- movl %r9d, 64*2($inp)
- shrq \$32, %r9
- movl %r10d, 64*4($inp)
- shrq \$32, %r10
- movl %r11d, 64*6($inp)
- shrq \$32, %r11
- movl %r12d, 64*8($inp)
- shrq \$32, %r12
- movl %r13d, 64*10($inp)
- shrq \$32, %r13
- movl %r14d, 64*12($inp)
- shrq \$32, %r14
- movl %r15d, 64*14($inp)
- shrq \$32, %r15
- movl %r8d, 64*1($inp)
- movl %r9d, 64*3($inp)
- movl %r10d, 64*5($inp)
- movl %r11d, 64*7($inp)
- movl %r12d, 64*9($inp)
- movl %r13d, 64*11($inp)
- movl %r14d, 64*13($inp)
- movl %r15d, 64*15($inp)
+ movq %r8, 128*0($inp) # scatter
+ movq %r9, 128*1($inp)
+ movq %r10, 128*2($inp)
+ movq %r11, 128*3($inp)
+ movq %r12, 128*4($inp)
+ movq %r13, 128*5($inp)
+ movq %r14, 128*6($inp)
+ movq %r15, 128*7($inp)
leaq 128+24+48(%rsp), %rax
movq -48(%rax), %r15
@@ -1943,16 +2039,14 @@ $code.=<<___;
.type rsaz_512_scatter4,\@abi-omnipotent
.align 16
rsaz_512_scatter4:
- leaq ($out,$power,4), $out
+ leaq ($out,$power,8), $out
movl \$8, %r9d
jmp .Loop_scatter
.align 16
.Loop_scatter:
movq ($inp), %rax
leaq 8($inp), $inp
- movl %eax, ($out)
- shrq \$32, %rax
- movl %eax, 64($out)
+ movq %rax, ($out)
leaq 128($out), $out
decl %r9d
jnz .Loop_scatter
@@ -1963,22 +2057,106 @@ rsaz_512_scatter4:
.type rsaz_512_gather4,\@abi-omnipotent
.align 16
rsaz_512_gather4:
- leaq ($inp,$power,4), $inp
+___
+$code.=<<___ if ($win64);
+.LSEH_begin_rsaz_512_gather4:
+ .byte 0x48,0x81,0xec,0xa8,0x00,0x00,0x00 # sub $0xa8,%rsp
+ .byte 0x0f,0x29,0x34,0x24 # movaps %xmm6,(%rsp)
+ .byte 0x0f,0x29,0x7c,0x24,0x10 # movaps %xmm7,0x10(%rsp)
+ .byte 0x44,0x0f,0x29,0x44,0x24,0x20 # movaps %xmm8,0x20(%rsp)
+ .byte 0x44,0x0f,0x29,0x4c,0x24,0x30 # movaps %xmm9,0x30(%rsp)
+ .byte 0x44,0x0f,0x29,0x54,0x24,0x40 # movaps %xmm10,0x40(%rsp)
+ .byte 0x44,0x0f,0x29,0x5c,0x24,0x50 # movaps %xmm11,0x50(%rsp)
+ .byte 0x44,0x0f,0x29,0x64,0x24,0x60 # movaps %xmm12,0x60(%rsp)
+ .byte 0x44,0x0f,0x29,0x6c,0x24,0x70 # movaps %xmm13,0x70(%rsp)
+ .byte 0x44,0x0f,0x29,0xb4,0x24,0x80,0,0,0 # movaps %xmm14,0x80(%rsp)
+ .byte 0x44,0x0f,0x29,0xbc,0x24,0x90,0,0,0 # movaps %xmm15,0x90(%rsp)
+___
+$code.=<<___;
+ movd $power,%xmm8
+ movdqa .Linc+16(%rip),%xmm1 # 00000002000000020000000200000002
+ movdqa .Linc(%rip),%xmm0 # 00000001000000010000000000000000
+
+ pshufd \$0,%xmm8,%xmm8 # broadcast $power
+ movdqa %xmm1,%xmm7
+ movdqa %xmm1,%xmm2
+___
+########################################################################
+# calculate mask by comparing 0..15 to $power
+#
+for($i=0;$i<4;$i++) {
+$code.=<<___;
+ paddd %xmm`$i`,%xmm`$i+1`
+ pcmpeqd %xmm8,%xmm`$i`
+ movdqa %xmm7,%xmm`$i+3`
+___
+}
+for(;$i<7;$i++) {
+$code.=<<___;
+ paddd %xmm`$i`,%xmm`$i+1`
+ pcmpeqd %xmm8,%xmm`$i`
+___
+}
+$code.=<<___;
+ pcmpeqd %xmm8,%xmm7
movl \$8, %r9d
jmp .Loop_gather
.align 16
.Loop_gather:
- movl ($inp), %eax
- movl 64($inp), %r8d
+ movdqa 16*0($inp),%xmm8
+ movdqa 16*1($inp),%xmm9
+ movdqa 16*2($inp),%xmm10
+ movdqa 16*3($inp),%xmm11
+ pand %xmm0,%xmm8
+ movdqa 16*4($inp),%xmm12
+ pand %xmm1,%xmm9
+ movdqa 16*5($inp),%xmm13
+ pand %xmm2,%xmm10
+ movdqa 16*6($inp),%xmm14
+ pand %xmm3,%xmm11
+ movdqa 16*7($inp),%xmm15
leaq 128($inp), $inp
- shlq \$32, %r8
- or %r8, %rax
- movq %rax, ($out)
+ pand %xmm4,%xmm12
+ pand %xmm5,%xmm13
+ pand %xmm6,%xmm14
+ pand %xmm7,%xmm15
+ por %xmm10,%xmm8
+ por %xmm11,%xmm9
+ por %xmm12,%xmm8
+ por %xmm13,%xmm9
+ por %xmm14,%xmm8
+ por %xmm15,%xmm9
+
+ por %xmm9,%xmm8
+ pshufd \$0x4e,%xmm8,%xmm9
+ por %xmm9,%xmm8
+ movq %xmm8,($out)
leaq 8($out), $out
decl %r9d
jnz .Loop_gather
+___
+$code.=<<___ if ($win64);
+ movaps 0x00(%rsp),%xmm6
+ movaps 0x10(%rsp),%xmm7
+ movaps 0x20(%rsp),%xmm8
+ movaps 0x30(%rsp),%xmm9
+ movaps 0x40(%rsp),%xmm10
+ movaps 0x50(%rsp),%xmm11
+ movaps 0x60(%rsp),%xmm12
+ movaps 0x70(%rsp),%xmm13
+ movaps 0x80(%rsp),%xmm14
+ movaps 0x90(%rsp),%xmm15
+ add \$0xa8,%rsp
+___
+$code.=<<___;
ret
+.LSEH_end_rsaz_512_gather4:
.size rsaz_512_gather4,.-rsaz_512_gather4
+
+.align 64
+.Linc:
+ .long 0,0, 1,1
+ .long 2,2, 2,2
___
}
@@ -2026,6 +2204,18 @@ se_handler:
lea 128+24+48(%rax),%rax
+ lea .Lmul_gather4_epilogue(%rip),%rbx
+ cmp %r10,%rbx
+ jne .Lse_not_in_mul_gather4
+
+ lea 0xb0(%rax),%rax
+
+ lea -48-0xa8(%rax),%rsi
+ lea 512($context),%rdi
+ mov \$20,%ecx
+ .long 0xa548f3fc # cld; rep movsq
+
+.Lse_not_in_mul_gather4:
mov -8(%rax),%rbx
mov -16(%rax),%rbp
mov -24(%rax),%r12
@@ -2077,7 +2267,7 @@ se_handler:
pop %rdi
pop %rsi
ret
-.size sqr_handler,.-sqr_handler
+.size se_handler,.-se_handler
.section .pdata
.align 4
@@ -2101,6 +2291,10 @@ se_handler:
.rva .LSEH_end_rsaz_512_mul_by_one
.rva .LSEH_info_rsaz_512_mul_by_one
+ .rva .LSEH_begin_rsaz_512_gather4
+ .rva .LSEH_end_rsaz_512_gather4
+ .rva .LSEH_info_rsaz_512_gather4
+
.section .xdata
.align 8
.LSEH_info_rsaz_512_sqr:
@@ -2123,6 +2317,19 @@ se_handler:
.byte 9,0,0,0
.rva se_handler
.rva .Lmul_by_one_body,.Lmul_by_one_epilogue # HandlerData[]
+.LSEH_info_rsaz_512_gather4:
+ .byte 0x01,0x46,0x16,0x00
+ .byte 0x46,0xf8,0x09,0x00 # vmovaps 0x90(rsp),xmm15
+ .byte 0x3d,0xe8,0x08,0x00 # vmovaps 0x80(rsp),xmm14
+ .byte 0x34,0xd8,0x07,0x00 # vmovaps 0x70(rsp),xmm13
+ .byte 0x2e,0xc8,0x06,0x00 # vmovaps 0x60(rsp),xmm12
+ .byte 0x28,0xb8,0x05,0x00 # vmovaps 0x50(rsp),xmm11
+ .byte 0x22,0xa8,0x04,0x00 # vmovaps 0x40(rsp),xmm10
+ .byte 0x1c,0x98,0x03,0x00 # vmovaps 0x30(rsp),xmm9
+ .byte 0x16,0x88,0x02,0x00 # vmovaps 0x20(rsp),xmm8
+ .byte 0x10,0x78,0x01,0x00 # vmovaps 0x10(rsp),xmm7
+ .byte 0x0b,0x68,0x00,0x00 # vmovaps 0x00(rsp),xmm6
+ .byte 0x07,0x01,0x15,0x00 # sub rsp,0xa8
___
}
diff --git a/crypto/bn/asm/x86_64-gcc.c b/crypto/bn/asm/x86_64-gcc.c
index d78a8514..214c12af 100644
--- a/crypto/bn/asm/x86_64-gcc.c
+++ b/crypto/bn/asm/x86_64-gcc.c
@@ -186,14 +186,6 @@ void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) {
}
}
-BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) {
- BN_ULONG ret, waste;
-
- asm("divq %4" : "=a"(ret), "=d"(waste) : "a"(l), "d"(h), "g"(d) : "cc");
-
- return ret;
-}
-
BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
int n) {
BN_ULONG ret;
diff --git a/crypto/bn/asm/x86_64-mont.pl b/crypto/bn/asm/x86_64-mont.pl
index 04c4beaf..1ca2b1ef 100644..100755
--- a/crypto/bn/asm/x86_64-mont.pl
+++ b/crypto/bn/asm/x86_64-mont.pl
@@ -761,100 +761,126 @@ bn_sqr8x_mont:
# 4096. this is done to allow memory disambiguation logic
# do its job.
#
- lea -64(%rsp,$num,4),%r11
+ lea -64(%rsp,$num,2),%r11
mov ($n0),$n0 # *n0
sub $aptr,%r11
and \$4095,%r11
cmp %r11,%r10
jb .Lsqr8x_sp_alt
sub %r11,%rsp # align with $aptr
- lea -64(%rsp,$num,4),%rsp # alloca(frame+4*$num)
+ lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
jmp .Lsqr8x_sp_done
.align 32
.Lsqr8x_sp_alt:
- lea 4096-64(,$num,4),%r10 # 4096-frame-4*$num
- lea -64(%rsp,$num,4),%rsp # alloca(frame+4*$num)
+ lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num
+ lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
sub %r10,%r11
mov \$0,%r10
cmovc %r10,%r11
sub %r11,%rsp
.Lsqr8x_sp_done:
and \$-64,%rsp
- mov $num,%r10
+ mov $num,%r10
neg $num
- lea 64(%rsp,$num,2),%r11 # copy of modulus
mov $n0, 32(%rsp)
mov %rax, 40(%rsp) # save original %rsp
.Lsqr8x_body:
- mov $num,$i
- movq %r11, %xmm2 # save pointer to modulus copy
- shr \$3+2,$i
- mov OPENSSL_ia32cap_P+8(%rip),%eax
- jmp .Lsqr8x_copy_n
-
-.align 32
-.Lsqr8x_copy_n:
- movq 8*0($nptr),%xmm0
- movq 8*1($nptr),%xmm1
- movq 8*2($nptr),%xmm3
- movq 8*3($nptr),%xmm4
- lea 8*4($nptr),$nptr
- movdqa %xmm0,16*0(%r11)
- movdqa %xmm1,16*1(%r11)
- movdqa %xmm3,16*2(%r11)
- movdqa %xmm4,16*3(%r11)
- lea 16*4(%r11),%r11
- dec $i
- jnz .Lsqr8x_copy_n
-
+ movq $nptr, %xmm2 # save pointer to modulus
pxor %xmm0,%xmm0
movq $rptr,%xmm1 # save $rptr
movq %r10, %xmm3 # -$num
___
$code.=<<___ if ($addx);
+ mov OPENSSL_ia32cap_P+8(%rip),%eax
and \$0x80100,%eax
cmp \$0x80100,%eax
jne .Lsqr8x_nox
call bn_sqrx8x_internal # see x86_64-mont5 module
-
- pxor %xmm0,%xmm0
- lea 48(%rsp),%rax
- lea 64(%rsp,$num,2),%rdx
- shr \$3+2,$num
- mov 40(%rsp),%rsi # restore %rsp
- jmp .Lsqr8x_zero
+ # %rax top-most carry
+ # %rbp nptr
+ # %rcx -8*num
+ # %r8 end of tp[2*num]
+ lea (%r8,%rcx),%rbx
+ mov %rcx,$num
+ mov %rcx,%rdx
+ movq %xmm1,$rptr
+ sar \$3+2,%rcx # %cf=0
+ jmp .Lsqr8x_sub
.align 32
.Lsqr8x_nox:
___
$code.=<<___;
call bn_sqr8x_internal # see x86_64-mont5 module
+ # %rax top-most carry
+ # %rbp nptr
+ # %r8 -8*num
+ # %rdi end of tp[2*num]
+ lea (%rdi,$num),%rbx
+ mov $num,%rcx
+ mov $num,%rdx
+ movq %xmm1,$rptr
+ sar \$3+2,%rcx # %cf=0
+ jmp .Lsqr8x_sub
+.align 32
+.Lsqr8x_sub:
+ mov 8*0(%rbx),%r12
+ mov 8*1(%rbx),%r13
+ mov 8*2(%rbx),%r14
+ mov 8*3(%rbx),%r15
+ lea 8*4(%rbx),%rbx
+ sbb 8*0(%rbp),%r12
+ sbb 8*1(%rbp),%r13
+ sbb 8*2(%rbp),%r14
+ sbb 8*3(%rbp),%r15
+ lea 8*4(%rbp),%rbp
+ mov %r12,8*0($rptr)
+ mov %r13,8*1($rptr)
+ mov %r14,8*2($rptr)
+ mov %r15,8*3($rptr)
+ lea 8*4($rptr),$rptr
+ inc %rcx # preserves %cf
+ jnz .Lsqr8x_sub
+
+ sbb \$0,%rax # top-most carry
+ lea (%rbx,$num),%rbx # rewind
+ lea ($rptr,$num),$rptr # rewind
+
+ movq %rax,%xmm1
pxor %xmm0,%xmm0
- lea 48(%rsp),%rax
- lea 64(%rsp,$num,2),%rdx
- shr \$3+2,$num
+ pshufd \$0,%xmm1,%xmm1
mov 40(%rsp),%rsi # restore %rsp
- jmp .Lsqr8x_zero
+ jmp .Lsqr8x_cond_copy
.align 32
-.Lsqr8x_zero:
- movdqa %xmm0,16*0(%rax) # wipe t
- movdqa %xmm0,16*1(%rax)
- movdqa %xmm0,16*2(%rax)
- movdqa %xmm0,16*3(%rax)
- lea 16*4(%rax),%rax
- movdqa %xmm0,16*0(%rdx) # wipe n
- movdqa %xmm0,16*1(%rdx)
- movdqa %xmm0,16*2(%rdx)
- movdqa %xmm0,16*3(%rdx)
- lea 16*4(%rdx),%rdx
- dec $num
- jnz .Lsqr8x_zero
+.Lsqr8x_cond_copy:
+ movdqa 16*0(%rbx),%xmm2
+ movdqa 16*1(%rbx),%xmm3
+ lea 16*2(%rbx),%rbx
+ movdqu 16*0($rptr),%xmm4
+ movdqu 16*1($rptr),%xmm5
+ lea 16*2($rptr),$rptr
+ movdqa %xmm0,-16*2(%rbx) # zero tp
+ movdqa %xmm0,-16*1(%rbx)
+ movdqa %xmm0,-16*2(%rbx,%rdx)
+ movdqa %xmm0,-16*1(%rbx,%rdx)
+ pcmpeqd %xmm1,%xmm0
+ pand %xmm1,%xmm2
+ pand %xmm1,%xmm3
+ pand %xmm0,%xmm4
+ pand %xmm0,%xmm5
+ pxor %xmm0,%xmm0
+ por %xmm2,%xmm4
+ por %xmm3,%xmm5
+ movdqu %xmm4,-16*2($rptr)
+ movdqu %xmm5,-16*1($rptr)
+ add \$32,$num
+ jnz .Lsqr8x_cond_copy
mov \$1,%rax
mov -48(%rsi),%r15
@@ -1121,64 +1147,75 @@ $code.=<<___;
adc $zero,%r15 # modulo-scheduled
sub 0*8($tptr),$zero # pull top-most carry
adc %r15,%r14
- mov -8($nptr),$mi
sbb %r15,%r15 # top-most carry
mov %r14,-1*8($tptr)
cmp 16(%rsp),$bptr
jne .Lmulx4x_outer
- sub %r14,$mi # compare top-most words
- sbb $mi,$mi
- or $mi,%r15
-
- neg $num
- xor %rdx,%rdx
+ lea 64(%rsp),$tptr
+ sub $num,$nptr # rewind $nptr
+ neg %r15
+ mov $num,%rdx
+ shr \$3+2,$num # %cf=0
mov 32(%rsp),$rptr # restore rp
+ jmp .Lmulx4x_sub
+
+.align 32
+.Lmulx4x_sub:
+ mov 8*0($tptr),%r11
+ mov 8*1($tptr),%r12
+ mov 8*2($tptr),%r13
+ mov 8*3($tptr),%r14
+ lea 8*4($tptr),$tptr
+ sbb 8*0($nptr),%r11
+ sbb 8*1($nptr),%r12
+ sbb 8*2($nptr),%r13
+ sbb 8*3($nptr),%r14
+ lea 8*4($nptr),$nptr
+ mov %r11,8*0($rptr)
+ mov %r12,8*1($rptr)
+ mov %r13,8*2($rptr)
+ mov %r14,8*3($rptr)
+ lea 8*4($rptr),$rptr
+ dec $num # preserves %cf
+ jnz .Lmulx4x_sub
+
+ sbb \$0,%r15 # top-most carry
lea 64(%rsp),$tptr
+ sub %rdx,$rptr # rewind
+ movq %r15,%xmm1
pxor %xmm0,%xmm0
- mov 0*8($nptr,$num),%r8
- mov 1*8($nptr,$num),%r9
- neg %r8
- jmp .Lmulx4x_sub_entry
+ pshufd \$0,%xmm1,%xmm1
+ mov 40(%rsp),%rsi # restore %rsp
+ jmp .Lmulx4x_cond_copy
.align 32
-.Lmulx4x_sub:
- mov 0*8($nptr,$num),%r8
- mov 1*8($nptr,$num),%r9
- not %r8
-.Lmulx4x_sub_entry:
- mov 2*8($nptr,$num),%r10
- not %r9
- and %r15,%r8
- mov 3*8($nptr,$num),%r11
- not %r10
- and %r15,%r9
- not %r11
- and %r15,%r10
- and %r15,%r11
-
- neg %rdx # mov %rdx,%cf
- adc 0*8($tptr),%r8
- adc 1*8($tptr),%r9
- movdqa %xmm0,($tptr)
- adc 2*8($tptr),%r10
- adc 3*8($tptr),%r11
- movdqa %xmm0,16($tptr)
- lea 4*8($tptr),$tptr
- sbb %rdx,%rdx # mov %cf,%rdx
-
- mov %r8,0*8($rptr)
- mov %r9,1*8($rptr)
- mov %r10,2*8($rptr)
- mov %r11,3*8($rptr)
- lea 4*8($rptr),$rptr
+.Lmulx4x_cond_copy:
+ movdqa 16*0($tptr),%xmm2
+ movdqa 16*1($tptr),%xmm3
+ lea 16*2($tptr),$tptr
+ movdqu 16*0($rptr),%xmm4
+ movdqu 16*1($rptr),%xmm5
+ lea 16*2($rptr),$rptr
+ movdqa %xmm0,-16*2($tptr) # zero tp
+ movdqa %xmm0,-16*1($tptr)
+ pcmpeqd %xmm1,%xmm0
+ pand %xmm1,%xmm2
+ pand %xmm1,%xmm3
+ pand %xmm0,%xmm4
+ pand %xmm0,%xmm5
+ pxor %xmm0,%xmm0
+ por %xmm2,%xmm4
+ por %xmm3,%xmm5
+ movdqu %xmm4,-16*2($rptr)
+ movdqu %xmm5,-16*1($rptr)
+ sub \$32,%rdx
+ jnz .Lmulx4x_cond_copy
- add \$32,$num
- jnz .Lmulx4x_sub
+ mov %rdx,($tptr)
- mov 40(%rsp),%rsi # restore %rsp
mov \$1,%rax
mov -48(%rsi),%r15
mov -40(%rsi),%r14
diff --git a/crypto/bn/asm/x86_64-mont5.pl b/crypto/bn/asm/x86_64-mont5.pl
index 3c5a8fc9..ced3acba 100644..100755
--- a/crypto/bn/asm/x86_64-mont5.pl
+++ b/crypto/bn/asm/x86_64-mont5.pl
@@ -86,58 +86,111 @@ $code.=<<___;
.Lmul_enter:
mov ${num}d,${num}d
mov %rsp,%rax
- mov `($win64?56:8)`(%rsp),%r10d # load 7th argument
+ movd `($win64?56:8)`(%rsp),%xmm5 # load 7th argument
+ lea .Linc(%rip),%r10
push %rbx
push %rbp
push %r12
push %r13
push %r14
push %r15
-___
-$code.=<<___ if ($win64);
- lea -0x28(%rsp),%rsp
- movaps %xmm6,(%rsp)
- movaps %xmm7,0x10(%rsp)
-___
-$code.=<<___;
+
lea 2($num),%r11
neg %r11
- lea (%rsp,%r11,8),%rsp # tp=alloca(8*(num+2))
+ lea -264(%rsp,%r11,8),%rsp # tp=alloca(8*(num+2)+256+8)
and \$-1024,%rsp # minimize TLB usage
mov %rax,8(%rsp,$num,8) # tp[num+1]=%rsp
.Lmul_body:
- mov $bp,%r12 # reassign $bp
+ lea 128($bp),%r12 # reassign $bp (+size optimization)
___
$bp="%r12";
$STRIDE=2**5*8; # 5 is "window size"
$N=$STRIDE/4; # should match cache line size
$code.=<<___;
- mov %r10,%r11
- shr \$`log($N/8)/log(2)`,%r10
- and \$`$N/8-1`,%r11
- not %r10
- lea .Lmagic_masks(%rip),%rax
- and \$`2**5/($N/8)-1`,%r10 # 5 is "window size"
- lea 96($bp,%r11,8),$bp # pointer within 1st cache line
- movq 0(%rax,%r10,8),%xmm4 # set of masks denoting which
- movq 8(%rax,%r10,8),%xmm5 # cache line contains element
- movq 16(%rax,%r10,8),%xmm6 # denoted by 7th argument
- movq 24(%rax,%r10,8),%xmm7
-
- movq `0*$STRIDE/4-96`($bp),%xmm0
- movq `1*$STRIDE/4-96`($bp),%xmm1
- pand %xmm4,%xmm0
- movq `2*$STRIDE/4-96`($bp),%xmm2
- pand %xmm5,%xmm1
- movq `3*$STRIDE/4-96`($bp),%xmm3
- pand %xmm6,%xmm2
- por %xmm1,%xmm0
- pand %xmm7,%xmm3
+ movdqa 0(%r10),%xmm0 # 00000001000000010000000000000000
+ movdqa 16(%r10),%xmm1 # 00000002000000020000000200000002
+ lea 24-112(%rsp,$num,8),%r10# place the mask after tp[num+3] (+ICache optimization)
+ and \$-16,%r10
+
+ pshufd \$0,%xmm5,%xmm5 # broadcast index
+ movdqa %xmm1,%xmm4
+ movdqa %xmm1,%xmm2
+___
+########################################################################
+# calculate mask by comparing 0..31 to index and save result to stack
+#
+$code.=<<___;
+ paddd %xmm0,%xmm1
+ pcmpeqd %xmm5,%xmm0 # compare to 1,0
+ .byte 0x67
+ movdqa %xmm4,%xmm3
+___
+for($k=0;$k<$STRIDE/16-4;$k+=4) {
+$code.=<<___;
+ paddd %xmm1,%xmm2
+ pcmpeqd %xmm5,%xmm1 # compare to 3,2
+ movdqa %xmm0,`16*($k+0)+112`(%r10)
+ movdqa %xmm4,%xmm0
+
+ paddd %xmm2,%xmm3
+ pcmpeqd %xmm5,%xmm2 # compare to 5,4
+ movdqa %xmm1,`16*($k+1)+112`(%r10)
+ movdqa %xmm4,%xmm1
+
+ paddd %xmm3,%xmm0
+ pcmpeqd %xmm5,%xmm3 # compare to 7,6
+ movdqa %xmm2,`16*($k+2)+112`(%r10)
+ movdqa %xmm4,%xmm2
+
+ paddd %xmm0,%xmm1
+ pcmpeqd %xmm5,%xmm0
+ movdqa %xmm3,`16*($k+3)+112`(%r10)
+ movdqa %xmm4,%xmm3
+___
+}
+$code.=<<___; # last iteration can be optimized
+ paddd %xmm1,%xmm2
+ pcmpeqd %xmm5,%xmm1
+ movdqa %xmm0,`16*($k+0)+112`(%r10)
+
+ paddd %xmm2,%xmm3
+ .byte 0x67
+ pcmpeqd %xmm5,%xmm2
+ movdqa %xmm1,`16*($k+1)+112`(%r10)
+
+ pcmpeqd %xmm5,%xmm3
+ movdqa %xmm2,`16*($k+2)+112`(%r10)
+ pand `16*($k+0)-128`($bp),%xmm0 # while it's still in register
+
+ pand `16*($k+1)-128`($bp),%xmm1
+ pand `16*($k+2)-128`($bp),%xmm2
+ movdqa %xmm3,`16*($k+3)+112`(%r10)
+ pand `16*($k+3)-128`($bp),%xmm3
por %xmm2,%xmm0
+ por %xmm3,%xmm1
+___
+for($k=0;$k<$STRIDE/16-4;$k+=4) {
+$code.=<<___;
+ movdqa `16*($k+0)-128`($bp),%xmm4
+ movdqa `16*($k+1)-128`($bp),%xmm5
+ movdqa `16*($k+2)-128`($bp),%xmm2
+ pand `16*($k+0)+112`(%r10),%xmm4
+ movdqa `16*($k+3)-128`($bp),%xmm3
+ pand `16*($k+1)+112`(%r10),%xmm5
+ por %xmm4,%xmm0
+ pand `16*($k+2)+112`(%r10),%xmm2
+ por %xmm5,%xmm1
+ pand `16*($k+3)+112`(%r10),%xmm3
+ por %xmm2,%xmm0
+ por %xmm3,%xmm1
+___
+}
+$code.=<<___;
+ por %xmm1,%xmm0
+ pshufd \$0x4e,%xmm0,%xmm1
+ por %xmm1,%xmm0
lea $STRIDE($bp),$bp
- por %xmm3,%xmm0
-
movq %xmm0,$m0 # m0=bp[0]
mov ($n0),$n0 # pull n0[0] value
@@ -146,29 +199,14 @@ $code.=<<___;
xor $i,$i # i=0
xor $j,$j # j=0
- movq `0*$STRIDE/4-96`($bp),%xmm0
- movq `1*$STRIDE/4-96`($bp),%xmm1
- pand %xmm4,%xmm0
- movq `2*$STRIDE/4-96`($bp),%xmm2
- pand %xmm5,%xmm1
-
mov $n0,$m1
mulq $m0 # ap[0]*bp[0]
mov %rax,$lo0
mov ($np),%rax
- movq `3*$STRIDE/4-96`($bp),%xmm3
- pand %xmm6,%xmm2
- por %xmm1,%xmm0
- pand %xmm7,%xmm3
-
imulq $lo0,$m1 # "tp[0]"*n0
mov %rdx,$hi0
- por %xmm2,%xmm0
- lea $STRIDE($bp),$bp
- por %xmm3,%xmm0
-
mulq $m1 # np[0]*m1
add %rax,$lo0 # discarded
mov 8($ap),%rax
@@ -199,16 +237,14 @@ $code.=<<___;
mulq $m1 # np[j]*m1
cmp $num,$j
- jne .L1st
-
- movq %xmm0,$m0 # bp[1]
+ jne .L1st # note that upon exit $j==$num, so
+ # they can be used interchangeably
add %rax,$hi1
- mov ($ap),%rax # ap[0]
adc \$0,%rdx
add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0]
adc \$0,%rdx
- mov $hi1,-16(%rsp,$j,8) # tp[j-1]
+ mov $hi1,-16(%rsp,$num,8) # tp[num-1]
mov %rdx,$hi1
mov $lo0,$hi0
@@ -222,33 +258,48 @@ $code.=<<___;
jmp .Louter
.align 16
.Louter:
+ lea 24+128(%rsp,$num,8),%rdx # where 256-byte mask is (+size optimization)
+ and \$-16,%rdx
+ pxor %xmm4,%xmm4
+ pxor %xmm5,%xmm5
+___
+for($k=0;$k<$STRIDE/16;$k+=4) {
+$code.=<<___;
+ movdqa `16*($k+0)-128`($bp),%xmm0
+ movdqa `16*($k+1)-128`($bp),%xmm1
+ movdqa `16*($k+2)-128`($bp),%xmm2
+ movdqa `16*($k+3)-128`($bp),%xmm3
+ pand `16*($k+0)-128`(%rdx),%xmm0
+ pand `16*($k+1)-128`(%rdx),%xmm1
+ por %xmm0,%xmm4
+ pand `16*($k+2)-128`(%rdx),%xmm2
+ por %xmm1,%xmm5
+ pand `16*($k+3)-128`(%rdx),%xmm3
+ por %xmm2,%xmm4
+ por %xmm3,%xmm5
+___
+}
+$code.=<<___;
+ por %xmm5,%xmm4
+ pshufd \$0x4e,%xmm4,%xmm0
+ por %xmm4,%xmm0
+ lea $STRIDE($bp),$bp
+
+ mov ($ap),%rax # ap[0]
+ movq %xmm0,$m0 # m0=bp[i]
+
xor $j,$j # j=0
mov $n0,$m1
mov (%rsp),$lo0
- movq `0*$STRIDE/4-96`($bp),%xmm0
- movq `1*$STRIDE/4-96`($bp),%xmm1
- pand %xmm4,%xmm0
- movq `2*$STRIDE/4-96`($bp),%xmm2
- pand %xmm5,%xmm1
-
mulq $m0 # ap[0]*bp[i]
add %rax,$lo0 # ap[0]*bp[i]+tp[0]
mov ($np),%rax
adc \$0,%rdx
- movq `3*$STRIDE/4-96`($bp),%xmm3
- pand %xmm6,%xmm2
- por %xmm1,%xmm0
- pand %xmm7,%xmm3
-
imulq $lo0,$m1 # tp[0]*n0
mov %rdx,$hi0
- por %xmm2,%xmm0
- lea $STRIDE($bp),$bp
- por %xmm3,%xmm0
-
mulq $m1 # np[0]*m1
add %rax,$lo0 # discarded
mov 8($ap),%rax
@@ -282,17 +333,14 @@ $code.=<<___;
mulq $m1 # np[j]*m1
cmp $num,$j
- jne .Linner
-
- movq %xmm0,$m0 # bp[i+1]
-
+ jne .Linner # note that upon exit $j==$num, so
+ # they can be used interchangeably
add %rax,$hi1
- mov ($ap),%rax # ap[0]
adc \$0,%rdx
add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j]
- mov (%rsp,$j,8),$lo0
+ mov (%rsp,$num,8),$lo0
adc \$0,%rdx
- mov $hi1,-16(%rsp,$j,8) # tp[j-1]
+ mov $hi1,-16(%rsp,$num,8) # tp[num-1]
mov %rdx,$hi1
xor %rdx,%rdx
@@ -338,12 +386,7 @@ $code.=<<___;
mov 8(%rsp,$num,8),%rsi # restore %rsp
mov \$1,%rax
-___
-$code.=<<___ if ($win64);
- movaps -88(%rsi),%xmm6
- movaps -72(%rsi),%xmm7
-___
-$code.=<<___;
+
mov -48(%rsi),%r15
mov -40(%rsi),%r14
mov -32(%rsi),%r13
@@ -365,8 +408,8 @@ bn_mul4x_mont_gather5:
.Lmul4x_enter:
___
$code.=<<___ if ($addx);
- and \$0x80100,%r11d
- cmp \$0x80100,%r11d
+ and \$0x80108,%r11d
+ cmp \$0x80108,%r11d # check for AD*X+BMI2+BMI1
je .Lmulx4x_enter
___
$code.=<<___;
@@ -378,39 +421,34 @@ $code.=<<___;
push %r13
push %r14
push %r15
-___
-$code.=<<___ if ($win64);
- lea -0x28(%rsp),%rsp
- movaps %xmm6,(%rsp)
- movaps %xmm7,0x10(%rsp)
-___
-$code.=<<___;
+
.byte 0x67
- mov ${num}d,%r10d
- shl \$3,${num}d
- shl \$3+2,%r10d # 4*$num
+ shl \$3,${num}d # convert $num to bytes
+ lea ($num,$num,2),%r10 # 3*$num in bytes
neg $num # -$num
##############################################################
- # ensure that stack frame doesn't alias with $aptr+4*$num
- # modulo 4096, which covers ret[num], am[num] and n[2*num]
- # (see bn_exp.c). this is done to allow memory disambiguation
- # logic do its magic. [excessive frame is allocated in order
- # to allow bn_from_mont8x to clear it.]
+ # Ensure that stack frame doesn't alias with $rptr+3*$num
+ # modulo 4096, which covers ret[num], am[num] and n[num]
+ # (see bn_exp.c). This is done to allow memory disambiguation
+ # logic do its magic. [Extra [num] is allocated in order
+ # to align with bn_power5's frame, which is cleansed after
+ # completing exponentiation. Extra 256 bytes is for power mask
+ # calculated from 7th argument, the index.]
#
- lea -64(%rsp,$num,2),%r11
- sub $ap,%r11
+ lea -320(%rsp,$num,2),%r11
+ sub $rp,%r11
and \$4095,%r11
cmp %r11,%r10
jb .Lmul4xsp_alt
- sub %r11,%rsp # align with $ap
- lea -64(%rsp,$num,2),%rsp # alloca(128+num*8)
+ sub %r11,%rsp # align with $rp
+ lea -320(%rsp,$num,2),%rsp # alloca(frame+2*num*8+256)
jmp .Lmul4xsp_done
.align 32
.Lmul4xsp_alt:
- lea 4096-64(,$num,2),%r10
- lea -64(%rsp,$num,2),%rsp # alloca(128+num*8)
+ lea 4096-320(,$num,2),%r10
+ lea -320(%rsp,$num,2),%rsp # alloca(frame+2*num*8+256)
sub %r10,%r11
mov \$0,%r10
cmovc %r10,%r11
@@ -426,12 +464,7 @@ $code.=<<___;
mov 40(%rsp),%rsi # restore %rsp
mov \$1,%rax
-___
-$code.=<<___ if ($win64);
- movaps -88(%rsi),%xmm6
- movaps -72(%rsi),%xmm7
-___
-$code.=<<___;
+
mov -48(%rsi),%r15
mov -40(%rsi),%r14
mov -32(%rsi),%r13
@@ -446,9 +479,10 @@ $code.=<<___;
.type mul4x_internal,\@abi-omnipotent
.align 32
mul4x_internal:
- shl \$5,$num
- mov `($win64?56:8)`(%rax),%r10d # load 7th argument
- lea 256(%rdx,$num),%r13
+ shl \$5,$num # $num was in bytes
+ movd `($win64?56:8)`(%rax),%xmm5 # load 7th argument, index
+ lea .Linc(%rip),%rax
+ lea 128(%rdx,$num),%r13 # end of powers table (+size optimization)
shr \$5,$num # restore $num
___
$bp="%r12";
@@ -456,44 +490,92 @@ ___
$N=$STRIDE/4; # should match cache line size
$tp=$i;
$code.=<<___;
- mov %r10,%r11
- shr \$`log($N/8)/log(2)`,%r10
- and \$`$N/8-1`,%r11
- not %r10
- lea .Lmagic_masks(%rip),%rax
- and \$`2**5/($N/8)-1`,%r10 # 5 is "window size"
- lea 96(%rdx,%r11,8),$bp # pointer within 1st cache line
- movq 0(%rax,%r10,8),%xmm4 # set of masks denoting which
- movq 8(%rax,%r10,8),%xmm5 # cache line contains element
- add \$7,%r11
- movq 16(%rax,%r10,8),%xmm6 # denoted by 7th argument
- movq 24(%rax,%r10,8),%xmm7
- and \$7,%r11
-
- movq `0*$STRIDE/4-96`($bp),%xmm0
- lea $STRIDE($bp),$tp # borrow $tp
- movq `1*$STRIDE/4-96`($bp),%xmm1
- pand %xmm4,%xmm0
- movq `2*$STRIDE/4-96`($bp),%xmm2
- pand %xmm5,%xmm1
- movq `3*$STRIDE/4-96`($bp),%xmm3
- pand %xmm6,%xmm2
- .byte 0x67
- por %xmm1,%xmm0
- movq `0*$STRIDE/4-96`($tp),%xmm1
- .byte 0x67
- pand %xmm7,%xmm3
- .byte 0x67
- por %xmm2,%xmm0
- movq `1*$STRIDE/4-96`($tp),%xmm2
+ movdqa 0(%rax),%xmm0 # 00000001000000010000000000000000
+ movdqa 16(%rax),%xmm1 # 00000002000000020000000200000002
+ lea 88-112(%rsp,$num),%r10 # place the mask after tp[num+1] (+ICache optimization)
+ lea 128(%rdx),$bp # size optimization
+
+ pshufd \$0,%xmm5,%xmm5 # broadcast index
+ movdqa %xmm1,%xmm4
+ .byte 0x67,0x67
+ movdqa %xmm1,%xmm2
+___
+########################################################################
+# calculate mask by comparing 0..31 to index and save result to stack
+#
+$code.=<<___;
+ paddd %xmm0,%xmm1
+ pcmpeqd %xmm5,%xmm0 # compare to 1,0
.byte 0x67
- pand %xmm4,%xmm1
+ movdqa %xmm4,%xmm3
+___
+for($i=0;$i<$STRIDE/16-4;$i+=4) {
+$code.=<<___;
+ paddd %xmm1,%xmm2
+ pcmpeqd %xmm5,%xmm1 # compare to 3,2
+ movdqa %xmm0,`16*($i+0)+112`(%r10)
+ movdqa %xmm4,%xmm0
+
+ paddd %xmm2,%xmm3
+ pcmpeqd %xmm5,%xmm2 # compare to 5,4
+ movdqa %xmm1,`16*($i+1)+112`(%r10)
+ movdqa %xmm4,%xmm1
+
+ paddd %xmm3,%xmm0
+ pcmpeqd %xmm5,%xmm3 # compare to 7,6
+ movdqa %xmm2,`16*($i+2)+112`(%r10)
+ movdqa %xmm4,%xmm2
+
+ paddd %xmm0,%xmm1
+ pcmpeqd %xmm5,%xmm0
+ movdqa %xmm3,`16*($i+3)+112`(%r10)
+ movdqa %xmm4,%xmm3
+___
+}
+$code.=<<___; # last iteration can be optimized
+ paddd %xmm1,%xmm2
+ pcmpeqd %xmm5,%xmm1
+ movdqa %xmm0,`16*($i+0)+112`(%r10)
+
+ paddd %xmm2,%xmm3
.byte 0x67
- por %xmm3,%xmm0
- movq `2*$STRIDE/4-96`($tp),%xmm3
+ pcmpeqd %xmm5,%xmm2
+ movdqa %xmm1,`16*($i+1)+112`(%r10)
+ pcmpeqd %xmm5,%xmm3
+ movdqa %xmm2,`16*($i+2)+112`(%r10)
+ pand `16*($i+0)-128`($bp),%xmm0 # while it's still in register
+
+ pand `16*($i+1)-128`($bp),%xmm1
+ pand `16*($i+2)-128`($bp),%xmm2
+ movdqa %xmm3,`16*($i+3)+112`(%r10)
+ pand `16*($i+3)-128`($bp),%xmm3
+ por %xmm2,%xmm0
+ por %xmm3,%xmm1
+___
+for($i=0;$i<$STRIDE/16-4;$i+=4) {
+$code.=<<___;
+ movdqa `16*($i+0)-128`($bp),%xmm4
+ movdqa `16*($i+1)-128`($bp),%xmm5
+ movdqa `16*($i+2)-128`($bp),%xmm2
+ pand `16*($i+0)+112`(%r10),%xmm4
+ movdqa `16*($i+3)-128`($bp),%xmm3
+ pand `16*($i+1)+112`(%r10),%xmm5
+ por %xmm4,%xmm0
+ pand `16*($i+2)+112`(%r10),%xmm2
+ por %xmm5,%xmm1
+ pand `16*($i+3)+112`(%r10),%xmm3
+ por %xmm2,%xmm0
+ por %xmm3,%xmm1
+___
+}
+$code.=<<___;
+ por %xmm1,%xmm0
+ pshufd \$0x4e,%xmm0,%xmm1
+ por %xmm1,%xmm0
+ lea $STRIDE($bp),$bp
movq %xmm0,$m0 # m0=bp[0]
- movq `3*$STRIDE/4-96`($tp),%xmm0
+
mov %r13,16+8(%rsp) # save end of b[num]
mov $rp, 56+8(%rsp) # save $rp
@@ -507,26 +589,10 @@ $code.=<<___;
mov %rax,$A[0]
mov ($np),%rax
- pand %xmm5,%xmm2
- pand %xmm6,%xmm3
- por %xmm2,%xmm1
-
imulq $A[0],$m1 # "tp[0]"*n0
- ##############################################################
- # $tp is chosen so that writing to top-most element of the
- # vector occurs just "above" references to powers table,
- # "above" modulo cache-line size, which effectively precludes
- # possibility of memory disambiguation logic failure when
- # accessing the table.
- #
- lea 64+8(%rsp,%r11,8),$tp
+ lea 64+8(%rsp),$tp
mov %rdx,$A[1]
- pand %xmm7,%xmm0
- por %xmm3,%xmm1
- lea 2*$STRIDE($bp),$bp
- por %xmm1,%xmm0
-
mulq $m1 # np[0]*m1
add %rax,$A[0] # discarded
mov 8($ap,$num),%rax
@@ -535,7 +601,7 @@ $code.=<<___;
mulq $m0
add %rax,$A[1]
- mov 16*1($np),%rax # interleaved with 0, therefore 16*n
+ mov 8*1($np),%rax
adc \$0,%rdx
mov %rdx,$A[0]
@@ -545,7 +611,7 @@ $code.=<<___;
adc \$0,%rdx
add $A[1],$N[1]
lea 4*8($num),$j # j=4
- lea 16*4($np),$np
+ lea 8*4($np),$np
adc \$0,%rdx
mov $N[1],($tp)
mov %rdx,$N[0]
@@ -555,7 +621,7 @@ $code.=<<___;
.L1st4x:
mulq $m0 # ap[j]*bp[0]
add %rax,$A[0]
- mov -16*2($np),%rax
+ mov -8*2($np),%rax
lea 32($tp),$tp
adc \$0,%rdx
mov %rdx,$A[1]
@@ -571,7 +637,7 @@ $code.=<<___;
mulq $m0 # ap[j]*bp[0]
add %rax,$A[1]
- mov -16*1($np),%rax
+ mov -8*1($np),%rax
adc \$0,%rdx
mov %rdx,$A[0]
@@ -586,7 +652,7 @@ $code.=<<___;
mulq $m0 # ap[j]*bp[0]
add %rax,$A[0]
- mov 16*0($np),%rax
+ mov 8*0($np),%rax
adc \$0,%rdx
mov %rdx,$A[1]
@@ -601,7 +667,7 @@ $code.=<<___;
mulq $m0 # ap[j]*bp[0]
add %rax,$A[1]
- mov 16*1($np),%rax
+ mov 8*1($np),%rax
adc \$0,%rdx
mov %rdx,$A[0]
@@ -610,7 +676,7 @@ $code.=<<___;
mov 16($ap,$j),%rax
adc \$0,%rdx
add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0]
- lea 16*4($np),$np
+ lea 8*4($np),$np
adc \$0,%rdx
mov $N[1],($tp) # tp[j-1]
mov %rdx,$N[0]
@@ -620,7 +686,7 @@ $code.=<<___;
mulq $m0 # ap[j]*bp[0]
add %rax,$A[0]
- mov -16*2($np),%rax
+ mov -8*2($np),%rax
lea 32($tp),$tp
adc \$0,%rdx
mov %rdx,$A[1]
@@ -636,7 +702,7 @@ $code.=<<___;
mulq $m0 # ap[j]*bp[0]
add %rax,$A[1]
- mov -16*1($np),%rax
+ mov -8*1($np),%rax
adc \$0,%rdx
mov %rdx,$A[0]
@@ -649,8 +715,7 @@ $code.=<<___;
mov $N[1],-16($tp) # tp[j-1]
mov %rdx,$N[0]
- movq %xmm0,$m0 # bp[1]
- lea ($np,$num,2),$np # rewind $np
+ lea ($np,$num),$np # rewind $np
xor $N[1],$N[1]
add $A[0],$N[0]
@@ -661,6 +726,33 @@ $code.=<<___;
.align 32
.Louter4x:
+ lea 16+128($tp),%rdx # where 256-byte mask is (+size optimization)
+ pxor %xmm4,%xmm4
+ pxor %xmm5,%xmm5
+___
+for($i=0;$i<$STRIDE/16;$i+=4) {
+$code.=<<___;
+ movdqa `16*($i+0)-128`($bp),%xmm0
+ movdqa `16*($i+1)-128`($bp),%xmm1
+ movdqa `16*($i+2)-128`($bp),%xmm2
+ movdqa `16*($i+3)-128`($bp),%xmm3
+ pand `16*($i+0)-128`(%rdx),%xmm0
+ pand `16*($i+1)-128`(%rdx),%xmm1
+ por %xmm0,%xmm4
+ pand `16*($i+2)-128`(%rdx),%xmm2
+ por %xmm1,%xmm5
+ pand `16*($i+3)-128`(%rdx),%xmm3
+ por %xmm2,%xmm4
+ por %xmm3,%xmm5
+___
+}
+$code.=<<___;
+ por %xmm5,%xmm4
+ pshufd \$0x4e,%xmm4,%xmm0
+ por %xmm4,%xmm0
+ lea $STRIDE($bp),$bp
+ movq %xmm0,$m0 # m0=bp[i]
+
mov ($tp,$num),$A[0]
mov $n0,$m1
mulq $m0 # ap[0]*bp[i]
@@ -668,25 +760,11 @@ $code.=<<___;
mov ($np),%rax
adc \$0,%rdx
- movq `0*$STRIDE/4-96`($bp),%xmm0
- movq `1*$STRIDE/4-96`($bp),%xmm1
- pand %xmm4,%xmm0
- movq `2*$STRIDE/4-96`($bp),%xmm2
- pand %xmm5,%xmm1
- movq `3*$STRIDE/4-96`($bp),%xmm3
-
imulq $A[0],$m1 # tp[0]*n0
- .byte 0x67
mov %rdx,$A[1]
mov $N[1],($tp) # store upmost overflow bit
- pand %xmm6,%xmm2
- por %xmm1,%xmm0
- pand %xmm7,%xmm3
- por %xmm2,%xmm0
lea ($tp,$num),$tp # rewind $tp
- lea $STRIDE($bp),$bp
- por %xmm3,%xmm0
mulq $m1 # np[0]*m1
add %rax,$A[0] # "$N[0]", discarded
@@ -696,7 +774,7 @@ $code.=<<___;
mulq $m0 # ap[j]*bp[i]
add %rax,$A[1]
- mov 16*1($np),%rax # interleaved with 0, therefore 16*n
+ mov 8*1($np),%rax
adc \$0,%rdx
add 8($tp),$A[1] # +tp[1]
adc \$0,%rdx
@@ -708,7 +786,7 @@ $code.=<<___;
adc \$0,%rdx
add $A[1],$N[1] # np[j]*m1+ap[j]*bp[i]+tp[j]
lea 4*8($num),$j # j=4
- lea 16*4($np),$np
+ lea 8*4($np),$np
adc \$0,%rdx
mov %rdx,$N[0]
jmp .Linner4x
@@ -717,7 +795,7 @@ $code.=<<___;
.Linner4x:
mulq $m0 # ap[j]*bp[i]
add %rax,$A[0]
- mov -16*2($np),%rax
+ mov -8*2($np),%rax
adc \$0,%rdx
add 16($tp),$A[0] # ap[j]*bp[i]+tp[j]
lea 32($tp),$tp
@@ -735,7 +813,7 @@ $code.=<<___;
mulq $m0 # ap[j]*bp[i]
add %rax,$A[1]
- mov -16*1($np),%rax
+ mov -8*1($np),%rax
adc \$0,%rdx
add -8($tp),$A[1]
adc \$0,%rdx
@@ -752,7 +830,7 @@ $code.=<<___;
mulq $m0 # ap[j]*bp[i]
add %rax,$A[0]
- mov 16*0($np),%rax
+ mov 8*0($np),%rax
adc \$0,%rdx
add ($tp),$A[0] # ap[j]*bp[i]+tp[j]
adc \$0,%rdx
@@ -769,7 +847,7 @@ $code.=<<___;
mulq $m0 # ap[j]*bp[i]
add %rax,$A[1]
- mov 16*1($np),%rax
+ mov 8*1($np),%rax
adc \$0,%rdx
add 8($tp),$A[1]
adc \$0,%rdx
@@ -780,7 +858,7 @@ $code.=<<___;
mov 16($ap,$j),%rax
adc \$0,%rdx
add $A[1],$N[1]
- lea 16*4($np),$np
+ lea 8*4($np),$np
adc \$0,%rdx
mov $N[0],-8($tp) # tp[j-1]
mov %rdx,$N[0]
@@ -790,7 +868,7 @@ $code.=<<___;
mulq $m0 # ap[j]*bp[i]
add %rax,$A[0]
- mov -16*2($np),%rax
+ mov -8*2($np),%rax
adc \$0,%rdx
add 16($tp),$A[0] # ap[j]*bp[i]+tp[j]
lea 32($tp),$tp
@@ -809,7 +887,7 @@ $code.=<<___;
mulq $m0 # ap[j]*bp[i]
add %rax,$A[1]
mov $m1,%rax
- mov -16*1($np),$m1
+ mov -8*1($np),$m1
adc \$0,%rdx
add -8($tp),$A[1]
adc \$0,%rdx
@@ -824,9 +902,8 @@ $code.=<<___;
mov $N[0],-24($tp) # tp[j-1]
mov %rdx,$N[0]
- movq %xmm0,$m0 # bp[i+1]
mov $N[1],-16($tp) # tp[j-1]
- lea ($np,$num,2),$np # rewind $np
+ lea ($np,$num),$np # rewind $np
xor $N[1],$N[1]
add $A[0],$N[0]
@@ -840,16 +917,23 @@ $code.=<<___;
___
if (1) {
$code.=<<___;
+ xor %rax,%rax
sub $N[0],$m1 # compare top-most words
adc $j,$j # $j is zero
or $j,$N[1]
- xor \$1,$N[1]
+ sub $N[1],%rax # %rax=-$N[1]
lea ($tp,$num),%rbx # tptr in .sqr4x_sub
- lea ($np,$N[1],8),%rbp # nptr in .sqr4x_sub
+ mov ($np),%r12
+ lea ($np),%rbp # nptr in .sqr4x_sub
mov %r9,%rcx
- sar \$3+2,%rcx # cf=0
+ sar \$3+2,%rcx
mov 56+8(%rsp),%rdi # rptr in .sqr4x_sub
- jmp .Lsqr4x_sub
+ dec %r12 # so that after 'not' we get -n[0]
+ xor %r10,%r10
+ mov 8*1(%rbp),%r13
+ mov 8*2(%rbp),%r14
+ mov 8*3(%rbp),%r15
+ jmp .Lsqr4x_sub_entry
___
} else {
my @ri=("%rax",$bp,$m0,$m1);
@@ -916,8 +1000,8 @@ bn_power5:
___
$code.=<<___ if ($addx);
mov OPENSSL_ia32cap_P+8(%rip),%r11d
- and \$0x80100,%r11d
- cmp \$0x80100,%r11d
+ and \$0x80108,%r11d
+ cmp \$0x80108,%r11d # check for AD*X+BMI2+BMI1
je .Lpowerx5_enter
___
$code.=<<___;
@@ -928,38 +1012,32 @@ $code.=<<___;
push %r13
push %r14
push %r15
-___
-$code.=<<___ if ($win64);
- lea -0x28(%rsp),%rsp
- movaps %xmm6,(%rsp)
- movaps %xmm7,0x10(%rsp)
-___
-$code.=<<___;
- mov ${num}d,%r10d
+
shl \$3,${num}d # convert $num to bytes
- shl \$3+2,%r10d # 4*$num
+ lea ($num,$num,2),%r10d # 3*$num
neg $num
mov ($n0),$n0 # *n0
##############################################################
- # ensure that stack frame doesn't alias with $aptr+4*$num
- # modulo 4096, which covers ret[num], am[num] and n[2*num]
- # (see bn_exp.c). this is done to allow memory disambiguation
- # logic do its magic.
+ # Ensure that stack frame doesn't alias with $rptr+3*$num
+ # modulo 4096, which covers ret[num], am[num] and n[num]
+ # (see bn_exp.c). This is done to allow memory disambiguation
+ # logic do its magic. [Extra 256 bytes is for power mask
+ # calculated from 7th argument, the index.]
#
- lea -64(%rsp,$num,2),%r11
- sub $aptr,%r11
+ lea -320(%rsp,$num,2),%r11
+ sub $rptr,%r11
and \$4095,%r11
cmp %r11,%r10
jb .Lpwr_sp_alt
sub %r11,%rsp # align with $aptr
- lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
+ lea -320(%rsp,$num,2),%rsp # alloca(frame+2*num*8+256)
jmp .Lpwr_sp_done
.align 32
.Lpwr_sp_alt:
- lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num
- lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
+ lea 4096-320(,$num,2),%r10
+ lea -320(%rsp,$num,2),%rsp # alloca(frame+2*num*8+256)
sub %r10,%r11
mov \$0,%r10
cmovc %r10,%r11
@@ -981,16 +1059,21 @@ $code.=<<___;
mov $n0, 32(%rsp)
mov %rax, 40(%rsp) # save original %rsp
.Lpower5_body:
- movq $rptr,%xmm1 # save $rptr
+ movq $rptr,%xmm1 # save $rptr, used in sqr8x
movq $nptr,%xmm2 # save $nptr
- movq %r10, %xmm3 # -$num
+ movq %r10, %xmm3 # -$num, used in sqr8x
movq $bptr,%xmm4
call __bn_sqr8x_internal
+ call __bn_post4x_internal
call __bn_sqr8x_internal
+ call __bn_post4x_internal
call __bn_sqr8x_internal
+ call __bn_post4x_internal
call __bn_sqr8x_internal
+ call __bn_post4x_internal
call __bn_sqr8x_internal
+ call __bn_post4x_internal
movq %xmm2,$nptr
movq %xmm4,$bptr
@@ -1551,9 +1634,9 @@ my ($nptr,$tptr,$carry,$m0)=("%rbp","%rdi","%rsi","%rbx");
$code.=<<___;
movq %xmm2,$nptr
-sqr8x_reduction:
+__bn_sqr8x_reduction:
xor %rax,%rax
- lea ($nptr,$num,2),%rcx # end of n[]
+ lea ($nptr,$num),%rcx # end of n[]
lea 48+8(%rsp,$num,2),%rdx # end of t[] buffer
mov %rcx,0+8(%rsp)
lea 48+8(%rsp,$num),$tptr # end of initial t[] window
@@ -1579,21 +1662,21 @@ sqr8x_reduction:
.byte 0x67
mov $m0,%r8
imulq 32+8(%rsp),$m0 # n0*a[0]
- mov 16*0($nptr),%rax # n[0]
+ mov 8*0($nptr),%rax # n[0]
mov \$8,%ecx
jmp .L8x_reduce
.align 32
.L8x_reduce:
mulq $m0
- mov 16*1($nptr),%rax # n[1]
+ mov 8*1($nptr),%rax # n[1]
neg %r8
mov %rdx,%r8
adc \$0,%r8
mulq $m0
add %rax,%r9
- mov 16*2($nptr),%rax
+ mov 8*2($nptr),%rax
adc \$0,%rdx
add %r9,%r8
mov $m0,48-8+8(%rsp,%rcx,8) # put aside n0*a[i]
@@ -1602,7 +1685,7 @@ sqr8x_reduction:
mulq $m0
add %rax,%r10
- mov 16*3($nptr),%rax
+ mov 8*3($nptr),%rax
adc \$0,%rdx
add %r10,%r9
mov 32+8(%rsp),$carry # pull n0, borrow $carry
@@ -1611,7 +1694,7 @@ sqr8x_reduction:
mulq $m0
add %rax,%r11
- mov 16*4($nptr),%rax
+ mov 8*4($nptr),%rax
adc \$0,%rdx
imulq %r8,$carry # modulo-scheduled
add %r11,%r10
@@ -1620,7 +1703,7 @@ sqr8x_reduction:
mulq $m0
add %rax,%r12
- mov 16*5($nptr),%rax
+ mov 8*5($nptr),%rax
adc \$0,%rdx
add %r12,%r11
mov %rdx,%r12
@@ -1628,7 +1711,7 @@ sqr8x_reduction:
mulq $m0
add %rax,%r13
- mov 16*6($nptr),%rax
+ mov 8*6($nptr),%rax
adc \$0,%rdx
add %r13,%r12
mov %rdx,%r13
@@ -1636,7 +1719,7 @@ sqr8x_reduction:
mulq $m0
add %rax,%r14
- mov 16*7($nptr),%rax
+ mov 8*7($nptr),%rax
adc \$0,%rdx
add %r14,%r13
mov %rdx,%r14
@@ -1645,7 +1728,7 @@ sqr8x_reduction:
mulq $m0
mov $carry,$m0 # n0*a[i]
add %rax,%r15
- mov 16*0($nptr),%rax # n[0]
+ mov 8*0($nptr),%rax # n[0]
adc \$0,%rdx
add %r15,%r14
mov %rdx,%r15
@@ -1654,7 +1737,7 @@ sqr8x_reduction:
dec %ecx
jnz .L8x_reduce
- lea 16*8($nptr),$nptr
+ lea 8*8($nptr),$nptr
xor %rax,%rax
mov 8+8(%rsp),%rdx # pull end of t[]
cmp 0+8(%rsp),$nptr # end of n[]?
@@ -1673,21 +1756,21 @@ sqr8x_reduction:
mov 48+56+8(%rsp),$m0 # pull n0*a[0]
mov \$8,%ecx
- mov 16*0($nptr),%rax
+ mov 8*0($nptr),%rax
jmp .L8x_tail
.align 32
.L8x_tail:
mulq $m0
add %rax,%r8
- mov 16*1($nptr),%rax
+ mov 8*1($nptr),%rax
mov %r8,($tptr) # save result
mov %rdx,%r8
adc \$0,%r8
mulq $m0
add %rax,%r9
- mov 16*2($nptr),%rax
+ mov 8*2($nptr),%rax
adc \$0,%rdx
add %r9,%r8
lea 8($tptr),$tptr # $tptr++
@@ -1696,7 +1779,7 @@ sqr8x_reduction:
mulq $m0
add %rax,%r10
- mov 16*3($nptr),%rax
+ mov 8*3($nptr),%rax
adc \$0,%rdx
add %r10,%r9
mov %rdx,%r10
@@ -1704,7 +1787,7 @@ sqr8x_reduction:
mulq $m0
add %rax,%r11
- mov 16*4($nptr),%rax
+ mov 8*4($nptr),%rax
adc \$0,%rdx
add %r11,%r10
mov %rdx,%r11
@@ -1712,7 +1795,7 @@ sqr8x_reduction:
mulq $m0
add %rax,%r12
- mov 16*5($nptr),%rax
+ mov 8*5($nptr),%rax
adc \$0,%rdx
add %r12,%r11
mov %rdx,%r12
@@ -1720,7 +1803,7 @@ sqr8x_reduction:
mulq $m0
add %rax,%r13
- mov 16*6($nptr),%rax
+ mov 8*6($nptr),%rax
adc \$0,%rdx
add %r13,%r12
mov %rdx,%r13
@@ -1728,7 +1811,7 @@ sqr8x_reduction:
mulq $m0
add %rax,%r14
- mov 16*7($nptr),%rax
+ mov 8*7($nptr),%rax
adc \$0,%rdx
add %r14,%r13
mov %rdx,%r14
@@ -1739,14 +1822,14 @@ sqr8x_reduction:
add %rax,%r15
adc \$0,%rdx
add %r15,%r14
- mov 16*0($nptr),%rax # pull n[0]
+ mov 8*0($nptr),%rax # pull n[0]
mov %rdx,%r15
adc \$0,%r15
dec %ecx
jnz .L8x_tail
- lea 16*8($nptr),$nptr
+ lea 8*8($nptr),$nptr
mov 8+8(%rsp),%rdx # pull end of t[]
cmp 0+8(%rsp),$nptr # end of n[]?
jae .L8x_tail_done # break out of loop
@@ -1792,7 +1875,7 @@ sqr8x_reduction:
adc 8*6($tptr),%r14
adc 8*7($tptr),%r15
adc \$0,%rax # top-most carry
- mov -16($nptr),%rcx # np[num-1]
+ mov -8($nptr),%rcx # np[num-1]
xor $carry,$carry
movq %xmm2,$nptr # restore $nptr
@@ -1810,6 +1893,8 @@ sqr8x_reduction:
cmp %rdx,$tptr # end of t[]?
jb .L8x_reduction_loop
+ ret
+.size bn_sqr8x_internal,.-bn_sqr8x_internal
___
}
##############################################################
@@ -1818,48 +1903,62 @@ ___
{
my ($tptr,$nptr)=("%rbx","%rbp");
$code.=<<___;
- #xor %rsi,%rsi # %rsi was $carry above
- sub %r15,%rcx # compare top-most words
+.type __bn_post4x_internal,\@abi-omnipotent
+.align 32
+__bn_post4x_internal:
+ mov 8*0($nptr),%r12
lea (%rdi,$num),$tptr # %rdi was $tptr above
- adc %rsi,%rsi
mov $num,%rcx
- or %rsi,%rax
movq %xmm1,$rptr # restore $rptr
- xor \$1,%rax
+ neg %rax
movq %xmm1,$aptr # prepare for back-to-back call
- lea ($nptr,%rax,8),$nptr
- sar \$3+2,%rcx # cf=0
- jmp .Lsqr4x_sub
+ sar \$3+2,%rcx
+ dec %r12 # so that after 'not' we get -n[0]
+ xor %r10,%r10
+ mov 8*1($nptr),%r13
+ mov 8*2($nptr),%r14
+ mov 8*3($nptr),%r15
+ jmp .Lsqr4x_sub_entry
-.align 32
+.align 16
.Lsqr4x_sub:
- .byte 0x66
- mov 8*0($tptr),%r12
- mov 8*1($tptr),%r13
- sbb 16*0($nptr),%r12
- mov 8*2($tptr),%r14
- sbb 16*1($nptr),%r13
- mov 8*3($tptr),%r15
- lea 8*4($tptr),$tptr
- sbb 16*2($nptr),%r14
+ mov 8*0($nptr),%r12
+ mov 8*1($nptr),%r13
+ mov 8*2($nptr),%r14
+ mov 8*3($nptr),%r15
+.Lsqr4x_sub_entry:
+ lea 8*4($nptr),$nptr
+ not %r12
+ not %r13
+ not %r14
+ not %r15
+ and %rax,%r12
+ and %rax,%r13
+ and %rax,%r14
+ and %rax,%r15
+
+ neg %r10 # mov %r10,%cf
+ adc 8*0($tptr),%r12
+ adc 8*1($tptr),%r13
+ adc 8*2($tptr),%r14
+ adc 8*3($tptr),%r15
mov %r12,8*0($rptr)
- sbb 16*3($nptr),%r15
- lea 16*4($nptr),$nptr
+ lea 8*4($tptr),$tptr
mov %r13,8*1($rptr)
+ sbb %r10,%r10 # mov %cf,%r10
mov %r14,8*2($rptr)
mov %r15,8*3($rptr)
lea 8*4($rptr),$rptr
inc %rcx # pass %cf
jnz .Lsqr4x_sub
-___
-}
-$code.=<<___;
+
mov $num,%r10 # prepare for back-to-back call
neg $num # restore $num
ret
-.size bn_sqr8x_internal,.-bn_sqr8x_internal
+.size __bn_post4x_internal,.-__bn_post4x_internal
___
+}
{
$code.=<<___;
.globl bn_from_montgomery
@@ -1883,39 +1982,32 @@ bn_from_mont8x:
push %r13
push %r14
push %r15
-___
-$code.=<<___ if ($win64);
- lea -0x28(%rsp),%rsp
- movaps %xmm6,(%rsp)
- movaps %xmm7,0x10(%rsp)
-___
-$code.=<<___;
- .byte 0x67
- mov ${num}d,%r10d
+
shl \$3,${num}d # convert $num to bytes
- shl \$3+2,%r10d # 4*$num
+ lea ($num,$num,2),%r10 # 3*$num in bytes
neg $num
mov ($n0),$n0 # *n0
##############################################################
- # ensure that stack frame doesn't alias with $aptr+4*$num
- # modulo 4096, which covers ret[num], am[num] and n[2*num]
- # (see bn_exp.c). this is done to allow memory disambiguation
- # logic do its magic.
+ # Ensure that stack frame doesn't alias with $rptr+3*$num
+ # modulo 4096, which covers ret[num], am[num] and n[num]
+ # (see bn_exp.c). The stack is allocated to aligned with
+ # bn_power5's frame, and as bn_from_montgomery happens to be
+ # last operation, we use the opportunity to cleanse it.
#
- lea -64(%rsp,$num,2),%r11
- sub $aptr,%r11
+ lea -320(%rsp,$num,2),%r11
+ sub $rptr,%r11
and \$4095,%r11
cmp %r11,%r10
jb .Lfrom_sp_alt
sub %r11,%rsp # align with $aptr
- lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
+ lea -320(%rsp,$num,2),%rsp # alloca(frame+2*$num*8+256)
jmp .Lfrom_sp_done
.align 32
.Lfrom_sp_alt:
- lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num
- lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
+ lea 4096-320(,$num,2),%r10
+ lea -320(%rsp,$num,2),%rsp # alloca(frame+2*$num*8+256)
sub %r10,%r11
mov \$0,%r10
cmovc %r10,%r11
@@ -1969,12 +2061,13 @@ $code.=<<___;
___
$code.=<<___ if ($addx);
mov OPENSSL_ia32cap_P+8(%rip),%r11d
- and \$0x80100,%r11d
- cmp \$0x80100,%r11d
+ and \$0x80108,%r11d
+ cmp \$0x80108,%r11d # check for AD*X+BMI2+BMI1
jne .Lfrom_mont_nox
lea (%rax,$num),$rptr
- call sqrx8x_reduction
+ call __bn_sqrx8x_reduction
+ call __bn_postx4x_internal
pxor %xmm0,%xmm0
lea 48(%rsp),%rax
@@ -1985,7 +2078,8 @@ $code.=<<___ if ($addx);
.Lfrom_mont_nox:
___
$code.=<<___;
- call sqr8x_reduction
+ call __bn_sqr8x_reduction
+ call __bn_post4x_internal
pxor %xmm0,%xmm0
lea 48(%rsp),%rax
@@ -2025,7 +2119,6 @@ $code.=<<___;
.align 32
bn_mulx4x_mont_gather5:
.Lmulx4x_enter:
- .byte 0x67
mov %rsp,%rax
push %rbx
push %rbp
@@ -2033,40 +2126,33 @@ bn_mulx4x_mont_gather5:
push %r13
push %r14
push %r15
-___
-$code.=<<___ if ($win64);
- lea -0x28(%rsp),%rsp
- movaps %xmm6,(%rsp)
- movaps %xmm7,0x10(%rsp)
-___
-$code.=<<___;
- .byte 0x67
- mov ${num}d,%r10d
+
shl \$3,${num}d # convert $num to bytes
- shl \$3+2,%r10d # 4*$num
+ lea ($num,$num,2),%r10 # 3*$num in bytes
neg $num # -$num
mov ($n0),$n0 # *n0
##############################################################
- # ensure that stack frame doesn't alias with $aptr+4*$num
- # modulo 4096, which covers a[num], ret[num] and n[2*num]
- # (see bn_exp.c). this is done to allow memory disambiguation
- # logic do its magic. [excessive frame is allocated in order
- # to allow bn_from_mont8x to clear it.]
+ # Ensure that stack frame doesn't alias with $rptr+3*$num
+ # modulo 4096, which covers ret[num], am[num] and n[num]
+ # (see bn_exp.c). This is done to allow memory disambiguation
+ # logic do its magic. [Extra [num] is allocated in order
+ # to align with bn_power5's frame, which is cleansed after
+ # completing exponentiation. Extra 256 bytes is for power mask
+ # calculated from 7th argument, the index.]
#
- lea -64(%rsp,$num,2),%r11
- sub $ap,%r11
+ lea -320(%rsp,$num,2),%r11
+ sub $rp,%r11
and \$4095,%r11
cmp %r11,%r10
jb .Lmulx4xsp_alt
sub %r11,%rsp # align with $aptr
- lea -64(%rsp,$num,2),%rsp # alloca(frame+$num)
+ lea -320(%rsp,$num,2),%rsp # alloca(frame+2*$num*8+256)
jmp .Lmulx4xsp_done
-.align 32
.Lmulx4xsp_alt:
- lea 4096-64(,$num,2),%r10 # 4096-frame-$num
- lea -64(%rsp,$num,2),%rsp # alloca(frame+$num)
+ lea 4096-320(,$num,2),%r10
+ lea -320(%rsp,$num,2),%rsp # alloca(frame+2*$num*8+256)
sub %r10,%r11
mov \$0,%r10
cmovc %r10,%r11
@@ -2092,12 +2178,7 @@ $code.=<<___;
mov 40(%rsp),%rsi # restore %rsp
mov \$1,%rax
-___
-$code.=<<___ if ($win64);
- movaps -88(%rsi),%xmm6
- movaps -72(%rsi),%xmm7
-___
-$code.=<<___;
+
mov -48(%rsi),%r15
mov -40(%rsi),%r14
mov -32(%rsi),%r13
@@ -2112,14 +2193,16 @@ $code.=<<___;
.type mulx4x_internal,\@abi-omnipotent
.align 32
mulx4x_internal:
- .byte 0x4c,0x89,0x8c,0x24,0x08,0x00,0x00,0x00 # mov $num,8(%rsp) # save -$num
- .byte 0x67
+ mov $num,8(%rsp) # save -$num (it was in bytes)
+ mov $num,%r10
neg $num # restore $num
shl \$5,$num
- lea 256($bp,$num),%r13
+ neg %r10 # restore $num
+ lea 128($bp,$num),%r13 # end of powers table (+size optimization)
shr \$5+5,$num
- mov `($win64?56:8)`(%rax),%r10d # load 7th argument
+ movd `($win64?56:8)`(%rax),%xmm5 # load 7th argument
sub \$1,$num
+ lea .Linc(%rip),%rax
mov %r13,16+8(%rsp) # end of b[num]
mov $num,24+8(%rsp) # inner counter
mov $rp, 56+8(%rsp) # save $rp
@@ -2130,52 +2213,92 @@ my $rptr=$bptr;
my $STRIDE=2**5*8; # 5 is "window size"
my $N=$STRIDE/4; # should match cache line size
$code.=<<___;
- mov %r10,%r11
- shr \$`log($N/8)/log(2)`,%r10
- and \$`$N/8-1`,%r11
- not %r10
- lea .Lmagic_masks(%rip),%rax
- and \$`2**5/($N/8)-1`,%r10 # 5 is "window size"
- lea 96($bp,%r11,8),$bptr # pointer within 1st cache line
- movq 0(%rax,%r10,8),%xmm4 # set of masks denoting which
- movq 8(%rax,%r10,8),%xmm5 # cache line contains element
- add \$7,%r11
- movq 16(%rax,%r10,8),%xmm6 # denoted by 7th argument
- movq 24(%rax,%r10,8),%xmm7
- and \$7,%r11
-
- movq `0*$STRIDE/4-96`($bptr),%xmm0
- lea $STRIDE($bptr),$tptr # borrow $tptr
- movq `1*$STRIDE/4-96`($bptr),%xmm1
- pand %xmm4,%xmm0
- movq `2*$STRIDE/4-96`($bptr),%xmm2
- pand %xmm5,%xmm1
- movq `3*$STRIDE/4-96`($bptr),%xmm3
- pand %xmm6,%xmm2
- por %xmm1,%xmm0
- movq `0*$STRIDE/4-96`($tptr),%xmm1
- pand %xmm7,%xmm3
- por %xmm2,%xmm0
- movq `1*$STRIDE/4-96`($tptr),%xmm2
- por %xmm3,%xmm0
- .byte 0x67,0x67
- pand %xmm4,%xmm1
- movq `2*$STRIDE/4-96`($tptr),%xmm3
+ movdqa 0(%rax),%xmm0 # 00000001000000010000000000000000
+ movdqa 16(%rax),%xmm1 # 00000002000000020000000200000002
+ lea 88-112(%rsp,%r10),%r10 # place the mask after tp[num+1] (+ICache optimizaton)
+ lea 128($bp),$bptr # size optimization
+ pshufd \$0,%xmm5,%xmm5 # broadcast index
+ movdqa %xmm1,%xmm4
+ .byte 0x67
+ movdqa %xmm1,%xmm2
+___
+########################################################################
+# calculate mask by comparing 0..31 to index and save result to stack
+#
+$code.=<<___;
+ .byte 0x67
+ paddd %xmm0,%xmm1
+ pcmpeqd %xmm5,%xmm0 # compare to 1,0
+ movdqa %xmm4,%xmm3
+___
+for($i=0;$i<$STRIDE/16-4;$i+=4) {
+$code.=<<___;
+ paddd %xmm1,%xmm2
+ pcmpeqd %xmm5,%xmm1 # compare to 3,2
+ movdqa %xmm0,`16*($i+0)+112`(%r10)
+ movdqa %xmm4,%xmm0
+
+ paddd %xmm2,%xmm3
+ pcmpeqd %xmm5,%xmm2 # compare to 5,4
+ movdqa %xmm1,`16*($i+1)+112`(%r10)
+ movdqa %xmm4,%xmm1
+
+ paddd %xmm3,%xmm0
+ pcmpeqd %xmm5,%xmm3 # compare to 7,6
+ movdqa %xmm2,`16*($i+2)+112`(%r10)
+ movdqa %xmm4,%xmm2
+
+ paddd %xmm0,%xmm1
+ pcmpeqd %xmm5,%xmm0
+ movdqa %xmm3,`16*($i+3)+112`(%r10)
+ movdqa %xmm4,%xmm3
+___
+}
+$code.=<<___; # last iteration can be optimized
+ .byte 0x67
+ paddd %xmm1,%xmm2
+ pcmpeqd %xmm5,%xmm1
+ movdqa %xmm0,`16*($i+0)+112`(%r10)
+
+ paddd %xmm2,%xmm3
+ pcmpeqd %xmm5,%xmm2
+ movdqa %xmm1,`16*($i+1)+112`(%r10)
+
+ pcmpeqd %xmm5,%xmm3
+ movdqa %xmm2,`16*($i+2)+112`(%r10)
+
+ pand `16*($i+0)-128`($bptr),%xmm0 # while it's still in register
+ pand `16*($i+1)-128`($bptr),%xmm1
+ pand `16*($i+2)-128`($bptr),%xmm2
+ movdqa %xmm3,`16*($i+3)+112`(%r10)
+ pand `16*($i+3)-128`($bptr),%xmm3
+ por %xmm2,%xmm0
+ por %xmm3,%xmm1
+___
+for($i=0;$i<$STRIDE/16-4;$i+=4) {
+$code.=<<___;
+ movdqa `16*($i+0)-128`($bptr),%xmm4
+ movdqa `16*($i+1)-128`($bptr),%xmm5
+ movdqa `16*($i+2)-128`($bptr),%xmm2
+ pand `16*($i+0)+112`(%r10),%xmm4
+ movdqa `16*($i+3)-128`($bptr),%xmm3
+ pand `16*($i+1)+112`(%r10),%xmm5
+ por %xmm4,%xmm0
+ pand `16*($i+2)+112`(%r10),%xmm2
+ por %xmm5,%xmm1
+ pand `16*($i+3)+112`(%r10),%xmm3
+ por %xmm2,%xmm0
+ por %xmm3,%xmm1
+___
+}
+$code.=<<___;
+ pxor %xmm1,%xmm0
+ pshufd \$0x4e,%xmm0,%xmm1
+ por %xmm1,%xmm0
+ lea $STRIDE($bptr),$bptr
movq %xmm0,%rdx # bp[0]
- movq `3*$STRIDE/4-96`($tptr),%xmm0
- lea 2*$STRIDE($bptr),$bptr # next &b[i]
- pand %xmm5,%xmm2
- .byte 0x67,0x67
- pand %xmm6,%xmm3
- ##############################################################
- # $tptr is chosen so that writing to top-most element of the
- # vector occurs just "above" references to powers table,
- # "above" modulo cache-line size, which effectively precludes
- # possibility of memory disambiguation logic failure when
- # accessing the table.
- #
- lea 64+8*4+8(%rsp,%r11,8),$tptr
+ lea 64+8*4+8(%rsp),$tptr
mov %rdx,$bi
mulx 0*8($aptr),$mi,%rax # a[0]*b[0]
@@ -2191,37 +2314,31 @@ $code.=<<___;
xor $zero,$zero # cf=0, of=0
mov $mi,%rdx
- por %xmm2,%xmm1
- pand %xmm7,%xmm0
- por %xmm3,%xmm1
mov $bptr,8+8(%rsp) # off-load &b[i]
- por %xmm1,%xmm0
- .byte 0x48,0x8d,0xb6,0x20,0x00,0x00,0x00 # lea 4*8($aptr),$aptr
+ lea 4*8($aptr),$aptr
adcx %rax,%r13
adcx $zero,%r14 # cf=0
- mulx 0*16($nptr),%rax,%r10
+ mulx 0*8($nptr),%rax,%r10
adcx %rax,%r15 # discarded
adox %r11,%r10
- mulx 1*16($nptr),%rax,%r11
+ mulx 1*8($nptr),%rax,%r11
adcx %rax,%r10
adox %r12,%r11
- mulx 2*16($nptr),%rax,%r12
+ mulx 2*8($nptr),%rax,%r12
mov 24+8(%rsp),$bptr # counter value
- .byte 0x66
mov %r10,-8*4($tptr)
adcx %rax,%r11
adox %r13,%r12
- mulx 3*16($nptr),%rax,%r15
- .byte 0x67,0x67
+ mulx 3*8($nptr),%rax,%r15
mov $bi,%rdx
mov %r11,-8*3($tptr)
adcx %rax,%r12
adox $zero,%r15 # of=0
- .byte 0x48,0x8d,0x89,0x40,0x00,0x00,0x00 # lea 4*16($nptr),$nptr
+ lea 4*8($nptr),$nptr
mov %r12,-8*2($tptr)
- #jmp .Lmulx4x_1st
+ jmp .Lmulx4x_1st
.align 32
.Lmulx4x_1st:
@@ -2241,30 +2358,29 @@ $code.=<<___;
lea 4*8($tptr),$tptr
adox %r15,%r10
- mulx 0*16($nptr),%rax,%r15
+ mulx 0*8($nptr),%rax,%r15
adcx %rax,%r10
adox %r15,%r11
- mulx 1*16($nptr),%rax,%r15
+ mulx 1*8($nptr),%rax,%r15
adcx %rax,%r11
adox %r15,%r12
- mulx 2*16($nptr),%rax,%r15
+ mulx 2*8($nptr),%rax,%r15
mov %r10,-5*8($tptr)
adcx %rax,%r12
mov %r11,-4*8($tptr)
adox %r15,%r13
- mulx 3*16($nptr),%rax,%r15
+ mulx 3*8($nptr),%rax,%r15
mov $bi,%rdx
mov %r12,-3*8($tptr)
adcx %rax,%r13
adox $zero,%r15
- lea 4*16($nptr),$nptr
+ lea 4*8($nptr),$nptr
mov %r13,-2*8($tptr)
dec $bptr # of=0, pass cf
jnz .Lmulx4x_1st
mov 8(%rsp),$num # load -num
- movq %xmm0,%rdx # bp[1]
adc $zero,%r15 # modulo-scheduled
lea ($aptr,$num),$aptr # rewind $aptr
add %r15,%r14
@@ -2275,6 +2391,34 @@ $code.=<<___;
.align 32
.Lmulx4x_outer:
+ lea 16-256($tptr),%r10 # where 256-byte mask is (+density control)
+ pxor %xmm4,%xmm4
+ .byte 0x67,0x67
+ pxor %xmm5,%xmm5
+___
+for($i=0;$i<$STRIDE/16;$i+=4) {
+$code.=<<___;
+ movdqa `16*($i+0)-128`($bptr),%xmm0
+ movdqa `16*($i+1)-128`($bptr),%xmm1
+ movdqa `16*($i+2)-128`($bptr),%xmm2
+ pand `16*($i+0)+256`(%r10),%xmm0
+ movdqa `16*($i+3)-128`($bptr),%xmm3
+ pand `16*($i+1)+256`(%r10),%xmm1
+ por %xmm0,%xmm4
+ pand `16*($i+2)+256`(%r10),%xmm2
+ por %xmm1,%xmm5
+ pand `16*($i+3)+256`(%r10),%xmm3
+ por %xmm2,%xmm4
+ por %xmm3,%xmm5
+___
+}
+$code.=<<___;
+ por %xmm5,%xmm4
+ pshufd \$0x4e,%xmm4,%xmm0
+ por %xmm4,%xmm0
+ lea $STRIDE($bptr),$bptr
+ movq %xmm0,%rdx # m0=bp[i]
+
mov $zero,($tptr) # save top-most carry
lea 4*8($tptr,$num),$tptr # rewind $tptr
mulx 0*8($aptr),$mi,%r11 # a[0]*b[i]
@@ -2289,54 +2433,37 @@ $code.=<<___;
mulx 3*8($aptr),%rdx,%r14
adox -2*8($tptr),%r12
adcx %rdx,%r13
- lea ($nptr,$num,2),$nptr # rewind $nptr
+ lea ($nptr,$num),$nptr # rewind $nptr
lea 4*8($aptr),$aptr
adox -1*8($tptr),%r13
adcx $zero,%r14
adox $zero,%r14
- .byte 0x67
mov $mi,%r15
imulq 32+8(%rsp),$mi # "t[0]"*n0
- movq `0*$STRIDE/4-96`($bptr),%xmm0
- .byte 0x67,0x67
mov $mi,%rdx
- movq `1*$STRIDE/4-96`($bptr),%xmm1
- .byte 0x67
- pand %xmm4,%xmm0
- movq `2*$STRIDE/4-96`($bptr),%xmm2
- .byte 0x67
- pand %xmm5,%xmm1
- movq `3*$STRIDE/4-96`($bptr),%xmm3
- add \$$STRIDE,$bptr # next &b[i]
- .byte 0x67
- pand %xmm6,%xmm2
- por %xmm1,%xmm0
- pand %xmm7,%xmm3
xor $zero,$zero # cf=0, of=0
mov $bptr,8+8(%rsp) # off-load &b[i]
- mulx 0*16($nptr),%rax,%r10
+ mulx 0*8($nptr),%rax,%r10
adcx %rax,%r15 # discarded
adox %r11,%r10
- mulx 1*16($nptr),%rax,%r11
+ mulx 1*8($nptr),%rax,%r11
adcx %rax,%r10
adox %r12,%r11
- mulx 2*16($nptr),%rax,%r12
+ mulx 2*8($nptr),%rax,%r12
adcx %rax,%r11
adox %r13,%r12
- mulx 3*16($nptr),%rax,%r15
+ mulx 3*8($nptr),%rax,%r15
mov $bi,%rdx
- por %xmm2,%xmm0
mov 24+8(%rsp),$bptr # counter value
mov %r10,-8*4($tptr)
- por %xmm3,%xmm0
adcx %rax,%r12
mov %r11,-8*3($tptr)
adox $zero,%r15 # of=0
mov %r12,-8*2($tptr)
- lea 4*16($nptr),$nptr
+ lea 4*8($nptr),$nptr
jmp .Lmulx4x_inner
.align 32
@@ -2361,20 +2488,20 @@ $code.=<<___;
adcx $zero,%r14 # cf=0
adox %r15,%r10
- mulx 0*16($nptr),%rax,%r15
+ mulx 0*8($nptr),%rax,%r15
adcx %rax,%r10
adox %r15,%r11
- mulx 1*16($nptr),%rax,%r15
+ mulx 1*8($nptr),%rax,%r15
adcx %rax,%r11
adox %r15,%r12
- mulx 2*16($nptr),%rax,%r15
+ mulx 2*8($nptr),%rax,%r15
mov %r10,-5*8($tptr)
adcx %rax,%r12
adox %r15,%r13
mov %r11,-4*8($tptr)
- mulx 3*16($nptr),%rax,%r15
+ mulx 3*8($nptr),%rax,%r15
mov $bi,%rdx
- lea 4*16($nptr),$nptr
+ lea 4*8($nptr),$nptr
mov %r12,-3*8($tptr)
adcx %rax,%r13
adox $zero,%r15
@@ -2384,7 +2511,6 @@ $code.=<<___;
jnz .Lmulx4x_inner
mov 0+8(%rsp),$num # load -num
- movq %xmm0,%rdx # bp[i+1]
adc $zero,%r15 # modulo-scheduled
sub 0*8($tptr),$bptr # pull top-most carry to %cf
mov 8+8(%rsp),$bptr # re-load &b[i]
@@ -2397,20 +2523,26 @@ $code.=<<___;
cmp %r10,$bptr
jb .Lmulx4x_outer
- mov -16($nptr),%r10
+ mov -8($nptr),%r10
+ mov $zero,%r8
+ mov ($nptr,$num),%r12
+ lea ($nptr,$num),%rbp # rewind $nptr
+ mov $num,%rcx
+ lea ($tptr,$num),%rdi # rewind $tptr
+ xor %eax,%eax
xor %r15,%r15
sub %r14,%r10 # compare top-most words
adc %r15,%r15
- or %r15,$zero
- xor \$1,$zero
- lea ($tptr,$num),%rdi # rewind $tptr
- lea ($nptr,$num,2),$nptr # rewind $nptr
- .byte 0x67,0x67
- sar \$3+2,$num # cf=0
- lea ($nptr,$zero,8),%rbp
+ or %r15,%r8
+ sar \$3+2,%rcx
+ sub %r8,%rax # %rax=-%r8
mov 56+8(%rsp),%rdx # restore rp
- mov $num,%rcx
- jmp .Lsqrx4x_sub # common post-condition
+ dec %r12 # so that after 'not' we get -n[0]
+ mov 8*1(%rbp),%r13
+ xor %r8,%r8
+ mov 8*2(%rbp),%r14
+ mov 8*3(%rbp),%r15
+ jmp .Lsqrx4x_sub_entry # common post-condition
.size mulx4x_internal,.-mulx4x_internal
___
} {
@@ -2434,7 +2566,6 @@ $code.=<<___;
.align 32
bn_powerx5:
.Lpowerx5_enter:
- .byte 0x67
mov %rsp,%rax
push %rbx
push %rbp
@@ -2442,39 +2573,32 @@ bn_powerx5:
push %r13
push %r14
push %r15
-___
-$code.=<<___ if ($win64);
- lea -0x28(%rsp),%rsp
- movaps %xmm6,(%rsp)
- movaps %xmm7,0x10(%rsp)
-___
-$code.=<<___;
- .byte 0x67
- mov ${num}d,%r10d
+
shl \$3,${num}d # convert $num to bytes
- shl \$3+2,%r10d # 4*$num
+ lea ($num,$num,2),%r10 # 3*$num in bytes
neg $num
mov ($n0),$n0 # *n0
##############################################################
- # ensure that stack frame doesn't alias with $aptr+4*$num
- # modulo 4096, which covers ret[num], am[num] and n[2*num]
- # (see bn_exp.c). this is done to allow memory disambiguation
- # logic do its magic.
+ # Ensure that stack frame doesn't alias with $rptr+3*$num
+ # modulo 4096, which covers ret[num], am[num] and n[num]
+ # (see bn_exp.c). This is done to allow memory disambiguation
+ # logic do its magic. [Extra 256 bytes is for power mask
+ # calculated from 7th argument, the index.]
#
- lea -64(%rsp,$num,2),%r11
- sub $aptr,%r11
+ lea -320(%rsp,$num,2),%r11
+ sub $rptr,%r11
and \$4095,%r11
cmp %r11,%r10
jb .Lpwrx_sp_alt
sub %r11,%rsp # align with $aptr
- lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
+ lea -320(%rsp,$num,2),%rsp # alloca(frame+2*$num*8+256)
jmp .Lpwrx_sp_done
.align 32
.Lpwrx_sp_alt:
- lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num
- lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
+ lea 4096-320(,$num,2),%r10
+ lea -320(%rsp,$num,2),%rsp # alloca(frame+2*$num*8+256)
sub %r10,%r11
mov \$0,%r10
cmovc %r10,%r11
@@ -2505,10 +2629,15 @@ $code.=<<___;
.Lpowerx5_body:
call __bn_sqrx8x_internal
+ call __bn_postx4x_internal
call __bn_sqrx8x_internal
+ call __bn_postx4x_internal
call __bn_sqrx8x_internal
+ call __bn_postx4x_internal
call __bn_sqrx8x_internal
+ call __bn_postx4x_internal
call __bn_sqrx8x_internal
+ call __bn_postx4x_internal
mov %r10,$num # -num
mov $aptr,$rptr
@@ -2520,12 +2649,7 @@ $code.=<<___;
mov 40(%rsp),%rsi # restore %rsp
mov \$1,%rax
-___
-$code.=<<___ if ($win64);
- movaps -88(%rsi),%xmm6
- movaps -72(%rsi),%xmm7
-___
-$code.=<<___;
+
mov -48(%rsi),%r15
mov -40(%rsi),%r14
mov -32(%rsi),%r13
@@ -2959,11 +3083,11 @@ my ($nptr,$carry,$m0)=("%rbp","%rsi","%rdx");
$code.=<<___;
movq %xmm2,$nptr
-sqrx8x_reduction:
+__bn_sqrx8x_reduction:
xor %eax,%eax # initial top-most carry bit
mov 32+8(%rsp),%rbx # n0
mov 48+8(%rsp),%rdx # "%r8", 8*0($tptr)
- lea -128($nptr,$num,2),%rcx # end of n[]
+ lea -8*8($nptr,$num),%rcx # end of n[]
#lea 48+8(%rsp,$num,2),$tptr # end of t[] buffer
mov %rcx, 0+8(%rsp) # save end of n[]
mov $tptr,8+8(%rsp) # save end of t[]
@@ -2992,23 +3116,23 @@ sqrx8x_reduction:
.align 32
.Lsqrx8x_reduce:
mov %r8, %rbx
- mulx 16*0($nptr),%rax,%r8 # n[0]
+ mulx 8*0($nptr),%rax,%r8 # n[0]
adcx %rbx,%rax # discarded
adox %r9,%r8
- mulx 16*1($nptr),%rbx,%r9 # n[1]
+ mulx 8*1($nptr),%rbx,%r9 # n[1]
adcx %rbx,%r8
adox %r10,%r9
- mulx 16*2($nptr),%rbx,%r10
+ mulx 8*2($nptr),%rbx,%r10
adcx %rbx,%r9
adox %r11,%r10
- mulx 16*3($nptr),%rbx,%r11
+ mulx 8*3($nptr),%rbx,%r11
adcx %rbx,%r10
adox %r12,%r11
- .byte 0xc4,0x62,0xe3,0xf6,0xa5,0x40,0x00,0x00,0x00 # mulx 16*4($nptr),%rbx,%r12
+ .byte 0xc4,0x62,0xe3,0xf6,0xa5,0x20,0x00,0x00,0x00 # mulx 8*4($nptr),%rbx,%r12
mov %rdx,%rax
mov %r8,%rdx
adcx %rbx,%r11
@@ -3018,15 +3142,15 @@ sqrx8x_reduction:
mov %rax,%rdx
mov %rax,64+48+8(%rsp,%rcx,8) # put aside n0*a[i]
- mulx 16*5($nptr),%rax,%r13
+ mulx 8*5($nptr),%rax,%r13
adcx %rax,%r12
adox %r14,%r13
- mulx 16*6($nptr),%rax,%r14
+ mulx 8*6($nptr),%rax,%r14
adcx %rax,%r13
adox %r15,%r14
- mulx 16*7($nptr),%rax,%r15
+ mulx 8*7($nptr),%rax,%r15
mov %rbx,%rdx
adcx %rax,%r14
adox $carry,%r15 # $carry is 0
@@ -3042,7 +3166,7 @@ sqrx8x_reduction:
mov 48+8(%rsp),%rdx # pull n0*a[0]
add 8*0($tptr),%r8
- lea 16*8($nptr),$nptr
+ lea 8*8($nptr),$nptr
mov \$-8,%rcx
adcx 8*1($tptr),%r9
adcx 8*2($tptr),%r10
@@ -3061,35 +3185,35 @@ sqrx8x_reduction:
.align 32
.Lsqrx8x_tail:
mov %r8,%rbx
- mulx 16*0($nptr),%rax,%r8
+ mulx 8*0($nptr),%rax,%r8
adcx %rax,%rbx
adox %r9,%r8
- mulx 16*1($nptr),%rax,%r9
+ mulx 8*1($nptr),%rax,%r9
adcx %rax,%r8
adox %r10,%r9
- mulx 16*2($nptr),%rax,%r10
+ mulx 8*2($nptr),%rax,%r10
adcx %rax,%r9
adox %r11,%r10
- mulx 16*3($nptr),%rax,%r11
+ mulx 8*3($nptr),%rax,%r11
adcx %rax,%r10
adox %r12,%r11
- .byte 0xc4,0x62,0xfb,0xf6,0xa5,0x40,0x00,0x00,0x00 # mulx 16*4($nptr),%rax,%r12
+ .byte 0xc4,0x62,0xfb,0xf6,0xa5,0x20,0x00,0x00,0x00 # mulx 8*4($nptr),%rax,%r12
adcx %rax,%r11
adox %r13,%r12
- mulx 16*5($nptr),%rax,%r13
+ mulx 8*5($nptr),%rax,%r13
adcx %rax,%r12
adox %r14,%r13
- mulx 16*6($nptr),%rax,%r14
+ mulx 8*6($nptr),%rax,%r14
adcx %rax,%r13
adox %r15,%r14
- mulx 16*7($nptr),%rax,%r15
+ mulx 8*7($nptr),%rax,%r15
mov 72+48+8(%rsp,%rcx,8),%rdx # pull n0*a[i]
adcx %rax,%r14
adox $carry,%r15
@@ -3105,7 +3229,7 @@ sqrx8x_reduction:
sub 16+8(%rsp),$carry # mov 16(%rsp),%cf
mov 48+8(%rsp),%rdx # pull n0*a[0]
- lea 16*8($nptr),$nptr
+ lea 8*8($nptr),$nptr
adc 8*0($tptr),%r8
adc 8*1($tptr),%r9
adc 8*2($tptr),%r10
@@ -3141,7 +3265,7 @@ sqrx8x_reduction:
adc 8*0($tptr),%r8
movq %xmm3,%rcx
adc 8*1($tptr),%r9
- mov 16*7($nptr),$carry
+ mov 8*7($nptr),$carry
movq %xmm2,$nptr # restore $nptr
adc 8*2($tptr),%r10
adc 8*3($tptr),%r11
@@ -3167,6 +3291,8 @@ sqrx8x_reduction:
lea 8*8($tptr,%rcx),$tptr # start of current t[] window
cmp 8+8(%rsp),%r8 # end of t[]?
jb .Lsqrx8x_reduction_loop
+ ret
+.size bn_sqrx8x_internal,.-bn_sqrx8x_internal
___
}
##############################################################
@@ -3174,52 +3300,59 @@ ___
#
{
my ($rptr,$nptr)=("%rdx","%rbp");
-my @ri=map("%r$_",(10..13));
-my @ni=map("%r$_",(14..15));
$code.=<<___;
- xor %ebx,%ebx
- sub %r15,%rsi # compare top-most words
- adc %rbx,%rbx
+.align 32
+__bn_postx4x_internal:
+ mov 8*0($nptr),%r12
mov %rcx,%r10 # -$num
- or %rbx,%rax
mov %rcx,%r9 # -$num
- xor \$1,%rax
- sar \$3+2,%rcx # cf=0
+ neg %rax
+ sar \$3+2,%rcx
#lea 48+8(%rsp,%r9),$tptr
- lea ($nptr,%rax,8),$nptr
movq %xmm1,$rptr # restore $rptr
movq %xmm1,$aptr # prepare for back-to-back call
- jmp .Lsqrx4x_sub
+ dec %r12 # so that after 'not' we get -n[0]
+ mov 8*1($nptr),%r13
+ xor %r8,%r8
+ mov 8*2($nptr),%r14
+ mov 8*3($nptr),%r15
+ jmp .Lsqrx4x_sub_entry
-.align 32
+.align 16
.Lsqrx4x_sub:
- .byte 0x66
- mov 8*0($tptr),%r12
- mov 8*1($tptr),%r13
- sbb 16*0($nptr),%r12
- mov 8*2($tptr),%r14
- sbb 16*1($nptr),%r13
- mov 8*3($tptr),%r15
- lea 8*4($tptr),$tptr
- sbb 16*2($nptr),%r14
+ mov 8*0($nptr),%r12
+ mov 8*1($nptr),%r13
+ mov 8*2($nptr),%r14
+ mov 8*3($nptr),%r15
+.Lsqrx4x_sub_entry:
+ andn %rax,%r12,%r12
+ lea 8*4($nptr),$nptr
+ andn %rax,%r13,%r13
+ andn %rax,%r14,%r14
+ andn %rax,%r15,%r15
+
+ neg %r8 # mov %r8,%cf
+ adc 8*0($tptr),%r12
+ adc 8*1($tptr),%r13
+ adc 8*2($tptr),%r14
+ adc 8*3($tptr),%r15
mov %r12,8*0($rptr)
- sbb 16*3($nptr),%r15
- lea 16*4($nptr),$nptr
+ lea 8*4($tptr),$tptr
mov %r13,8*1($rptr)
+ sbb %r8,%r8 # mov %cf,%r8
mov %r14,8*2($rptr)
mov %r15,8*3($rptr)
lea 8*4($rptr),$rptr
inc %rcx
jnz .Lsqrx4x_sub
-___
-}
-$code.=<<___;
+
neg %r9 # restore $num
ret
-.size bn_sqrx8x_internal,.-bn_sqrx8x_internal
+.size __bn_postx4x_internal,.-__bn_postx4x_internal
___
+}
}}}
{
my ($inp,$num,$tbl,$idx)=$win64?("%rcx","%edx","%r8", "%r9d") : # Win64 order
@@ -3249,56 +3382,91 @@ bn_scatter5:
.globl bn_gather5
.type bn_gather5,\@abi-omnipotent
-.align 16
+.align 32
bn_gather5:
-___
-$code.=<<___ if ($win64);
-.LSEH_begin_bn_gather5:
+.LSEH_begin_bn_gather5: # Win64 thing, but harmless in other cases
# I can't trust assembler to use specific encoding:-(
- .byte 0x48,0x83,0xec,0x28 #sub \$0x28,%rsp
- .byte 0x0f,0x29,0x34,0x24 #movaps %xmm6,(%rsp)
- .byte 0x0f,0x29,0x7c,0x24,0x10 #movdqa %xmm7,0x10(%rsp)
+ .byte 0x4c,0x8d,0x14,0x24 #lea (%rsp),%r10
+ .byte 0x48,0x81,0xec,0x08,0x01,0x00,0x00 #sub $0x108,%rsp
+ lea .Linc(%rip),%rax
+ and \$-16,%rsp # shouldn't be formally required
+
+ movd $idx,%xmm5
+ movdqa 0(%rax),%xmm0 # 00000001000000010000000000000000
+ movdqa 16(%rax),%xmm1 # 00000002000000020000000200000002
+ lea 128($tbl),%r11 # size optimization
+ lea 128(%rsp),%rax # size optimization
+
+ pshufd \$0,%xmm5,%xmm5 # broadcast $idx
+ movdqa %xmm1,%xmm4
+ movdqa %xmm1,%xmm2
___
+########################################################################
+# calculate mask by comparing 0..31 to $idx and save result to stack
+#
+for($i=0;$i<$STRIDE/16;$i+=4) {
$code.=<<___;
- mov $idx,%r11d
- shr \$`log($N/8)/log(2)`,$idx
- and \$`$N/8-1`,%r11
- not $idx
- lea .Lmagic_masks(%rip),%rax
- and \$`2**5/($N/8)-1`,$idx # 5 is "window size"
- lea 128($tbl,%r11,8),$tbl # pointer within 1st cache line
- movq 0(%rax,$idx,8),%xmm4 # set of masks denoting which
- movq 8(%rax,$idx,8),%xmm5 # cache line contains element
- movq 16(%rax,$idx,8),%xmm6 # denoted by 7th argument
- movq 24(%rax,$idx,8),%xmm7
+ paddd %xmm0,%xmm1
+ pcmpeqd %xmm5,%xmm0 # compare to 1,0
+___
+$code.=<<___ if ($i);
+ movdqa %xmm3,`16*($i-1)-128`(%rax)
+___
+$code.=<<___;
+ movdqa %xmm4,%xmm3
+
+ paddd %xmm1,%xmm2
+ pcmpeqd %xmm5,%xmm1 # compare to 3,2
+ movdqa %xmm0,`16*($i+0)-128`(%rax)
+ movdqa %xmm4,%xmm0
+
+ paddd %xmm2,%xmm3
+ pcmpeqd %xmm5,%xmm2 # compare to 5,4
+ movdqa %xmm1,`16*($i+1)-128`(%rax)
+ movdqa %xmm4,%xmm1
+
+ paddd %xmm3,%xmm0
+ pcmpeqd %xmm5,%xmm3 # compare to 7,6
+ movdqa %xmm2,`16*($i+2)-128`(%rax)
+ movdqa %xmm4,%xmm2
+___
+}
+$code.=<<___;
+ movdqa %xmm3,`16*($i-1)-128`(%rax)
jmp .Lgather
-.align 16
-.Lgather:
- movq `0*$STRIDE/4-128`($tbl),%xmm0
- movq `1*$STRIDE/4-128`($tbl),%xmm1
- pand %xmm4,%xmm0
- movq `2*$STRIDE/4-128`($tbl),%xmm2
- pand %xmm5,%xmm1
- movq `3*$STRIDE/4-128`($tbl),%xmm3
- pand %xmm6,%xmm2
- por %xmm1,%xmm0
- pand %xmm7,%xmm3
- .byte 0x67,0x67
- por %xmm2,%xmm0
- lea $STRIDE($tbl),$tbl
- por %xmm3,%xmm0
+.align 32
+.Lgather:
+ pxor %xmm4,%xmm4
+ pxor %xmm5,%xmm5
+___
+for($i=0;$i<$STRIDE/16;$i+=4) {
+$code.=<<___;
+ movdqa `16*($i+0)-128`(%r11),%xmm0
+ movdqa `16*($i+1)-128`(%r11),%xmm1
+ movdqa `16*($i+2)-128`(%r11),%xmm2
+ pand `16*($i+0)-128`(%rax),%xmm0
+ movdqa `16*($i+3)-128`(%r11),%xmm3
+ pand `16*($i+1)-128`(%rax),%xmm1
+ por %xmm0,%xmm4
+ pand `16*($i+2)-128`(%rax),%xmm2
+ por %xmm1,%xmm5
+ pand `16*($i+3)-128`(%rax),%xmm3
+ por %xmm2,%xmm4
+ por %xmm3,%xmm5
+___
+}
+$code.=<<___;
+ por %xmm5,%xmm4
+ lea $STRIDE(%r11),%r11
+ pshufd \$0x4e,%xmm4,%xmm0
+ por %xmm4,%xmm0
movq %xmm0,($out) # m0=bp[0]
lea 8($out),$out
sub \$1,$num
jnz .Lgather
-___
-$code.=<<___ if ($win64);
- movaps (%rsp),%xmm6
- movaps 0x10(%rsp),%xmm7
- lea 0x28(%rsp),%rsp
-___
-$code.=<<___;
+
+ lea (%r10),%rsp
ret
.LSEH_end_bn_gather5:
.size bn_gather5,.-bn_gather5
@@ -3306,9 +3474,9 @@ ___
}
$code.=<<___;
.align 64
-.Lmagic_masks:
- .long 0,0, 0,0, 0,0, -1,-1
- .long 0,0, 0,0, 0,0, 0,0
+.Linc:
+ .long 0,0, 1,1
+ .long 2,2, 2,2
.asciz "Montgomery Multiplication with scatter/gather for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
___
@@ -3356,19 +3524,16 @@ mul_handler:
lea .Lmul_epilogue(%rip),%r10
cmp %r10,%rbx
- jb .Lbody_40
+ ja .Lbody_40
mov 192($context),%r10 # pull $num
mov 8(%rax,%r10,8),%rax # pull saved stack pointer
+
jmp .Lbody_proceed
.Lbody_40:
mov 40(%rax),%rax # pull saved stack pointer
.Lbody_proceed:
-
- movaps -88(%rax),%xmm0
- movaps -72(%rax),%xmm1
-
mov -8(%rax),%rbx
mov -16(%rax),%rbp
mov -24(%rax),%r12
@@ -3381,8 +3546,6 @@ mul_handler:
mov %r13,224($context) # restore context->R13
mov %r14,232($context) # restore context->R14
mov %r15,240($context) # restore context->R15
- movups %xmm0,512($context) # restore context->Xmm6
- movups %xmm1,528($context) # restore context->Xmm7
.Lcommon_seh_tail:
mov 8(%rax),%rdi
@@ -3493,10 +3656,9 @@ ___
$code.=<<___;
.align 8
.LSEH_info_bn_gather5:
- .byte 0x01,0x0d,0x05,0x00
- .byte 0x0d,0x78,0x01,0x00 #movaps 0x10(rsp),xmm7
- .byte 0x08,0x68,0x00,0x00 #movaps (rsp),xmm6
- .byte 0x04,0x42,0x00,0x00 #sub rsp,0x28
+ .byte 0x01,0x0b,0x03,0x0a
+ .byte 0x0b,0x01,0x21,0x00 # sub rsp,0x108
+ .byte 0x04,0xa3,0x00,0x00 # lea r10,(rsp)
.align 8
___
}
diff --git a/crypto/bn/bn.c b/crypto/bn/bn.c
index 2263701f..0ecaf825 100644
--- a/crypto/bn/bn.c
+++ b/crypto/bn/bn.c
@@ -266,6 +266,18 @@ int BN_set_word(BIGNUM *bn, BN_ULONG value) {
return 1;
}
+int bn_set_words(BIGNUM *bn, const BN_ULONG *words, size_t num) {
+ if (bn_wexpand(bn, num) == NULL) {
+ return 0;
+ }
+ memmove(bn->d, words, num * sizeof(BN_ULONG));
+ /* |bn_wexpand| verified that |num| isn't too large. */
+ bn->top = (int)num;
+ bn_correct_top(bn);
+ bn->neg = 0;
+ return 1;
+}
+
int BN_is_negative(const BIGNUM *bn) {
return bn->neg != 0;
}
diff --git a/crypto/bn/bn_test.cc b/crypto/bn/bn_test.cc
index fe8cfd05..d909ee28 100644
--- a/crypto/bn/bn_test.cc
+++ b/crypto/bn/bn_test.cc
@@ -850,11 +850,17 @@ static bool test_div_word(FILE *fp) {
return false;
}
BN_ULONG s = b->d[0];
+ BN_ULONG rmod = BN_mod_word(b.get(), s);
BN_ULONG r = BN_div_word(b.get(), s);
if (r == (BN_ULONG)-1) {
return false;
}
+ if (rmod != r) {
+ fprintf(stderr, "Mod (word) test failed!\n");
+ return false;
+ }
+
if (fp != NULL) {
BN_print_fp(fp, a.get());
puts_fp(fp, " / ");
diff --git a/crypto/bn/cmp.c b/crypto/bn/cmp.c
index fce72339..121c894c 100644
--- a/crypto/bn/cmp.c
+++ b/crypto/bn/cmp.c
@@ -56,6 +56,8 @@
#include <openssl/bn.h>
+#include <openssl/mem.h>
+
#include "internal.h"
@@ -198,3 +200,15 @@ int BN_is_word(const BIGNUM *bn, BN_ULONG w) {
int BN_is_odd(const BIGNUM *bn) {
return bn->top > 0 && (bn->d[0] & 1) == 1;
}
+
+int BN_equal_consttime(const BIGNUM *a, const BIGNUM *b) {
+ if (a->top != b->top) {
+ return 0;
+ }
+
+ int limbs_are_equal =
+ CRYPTO_memcmp(a->d, b->d, (size_t)a->top * sizeof(a->d[0])) == 0;
+
+ return constant_time_select_int(constant_time_eq_int(a->neg, b->neg),
+ limbs_are_equal, 0);
+}
diff --git a/crypto/bn/convert.c b/crypto/bn/convert.c
index 542f523f..9125bf84 100644
--- a/crypto/bn/convert.c
+++ b/crypto/bn/convert.c
@@ -577,12 +577,14 @@ BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out) {
return NULL;
}
+ int out_is_alloced = 0;
if (out == NULL) {
out = BN_new();
- }
- if (out == NULL) {
- OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
- return NULL;
+ if (out == NULL) {
+ OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ out_is_alloced = 1;
}
if (in_len == 0) {
@@ -592,6 +594,9 @@ BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out) {
in += 4;
if (BN_bin2bn(in, in_len, out) == NULL) {
+ if (out_is_alloced) {
+ BN_free(out);
+ }
return NULL;
}
out->neg = ((*in) & 0x80) != 0;
diff --git a/crypto/bn/div.c b/crypto/bn/div.c
index 5a239bce..e824458b 100644
--- a/crypto/bn/div.c
+++ b/crypto/bn/div.c
@@ -56,55 +56,126 @@
#include <openssl/bn.h>
+#include <assert.h>
#include <limits.h>
#include <openssl/err.h>
#include "internal.h"
-#define asm __asm__
-
-#if !defined(OPENSSL_NO_ASM)
-# if defined(__GNUC__) && __GNUC__>=2
-# if defined(OPENSSL_X86)
- /*
- * There were two reasons for implementing this template:
- * - GNU C generates a call to a function (__udivdi3 to be exact)
- * in reply to ((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0 (I fail to
- * understand why...);
- * - divl doesn't only calculate quotient, but also leaves
- * remainder in %edx which we can definitely use here:-)
- *
- * <appro@fy.chalmers.se>
- */
-#undef div_asm
-# define div_asm(n0,n1,d0) \
- ({ asm volatile ( \
- "divl %4" \
- : "=a"(q), "=d"(rem) \
- : "a"(n1), "d"(n0), "g"(d0) \
- : "cc"); \
- q; \
- })
-# define REMAINDER_IS_ALREADY_CALCULATED
-# elif defined(OPENSSL_X86_64)
- /*
- * Same story here, but it's 128-bit by 64-bit division. Wow!
- * <appro@fy.chalmers.se>
- */
-# undef div_asm
-# define div_asm(n0,n1,d0) \
- ({ asm volatile ( \
- "divq %4" \
- : "=a"(q), "=d"(rem) \
- : "a"(n1), "d"(n0), "g"(d0) \
- : "cc"); \
- q; \
- })
-# define REMAINDER_IS_ALREADY_CALCULATED
-# endif /* __<cpu> */
-# endif /* __GNUC__ */
-#endif /* OPENSSL_NO_ASM */
+#if !defined(BN_ULLONG)
+/* bn_div_words divides a double-width |h|,|l| by |d| and returns the result,
+ * which must fit in a |BN_ULONG|. */
+static BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) {
+ BN_ULONG dh, dl, q, ret = 0, th, tl, t;
+ int i, count = 2;
+
+ if (d == 0) {
+ return BN_MASK2;
+ }
+
+ i = BN_num_bits_word(d);
+ assert((i == BN_BITS2) || (h <= (BN_ULONG)1 << i));
+
+ i = BN_BITS2 - i;
+ if (h >= d) {
+ h -= d;
+ }
+
+ if (i) {
+ d <<= i;
+ h = (h << i) | (l >> (BN_BITS2 - i));
+ l <<= i;
+ }
+ dh = (d & BN_MASK2h) >> BN_BITS4;
+ dl = (d & BN_MASK2l);
+ for (;;) {
+ if ((h >> BN_BITS4) == dh) {
+ q = BN_MASK2l;
+ } else {
+ q = h / dh;
+ }
+
+ th = q * dh;
+ tl = dl * q;
+ for (;;) {
+ t = h - th;
+ if ((t & BN_MASK2h) ||
+ ((tl) <= ((t << BN_BITS4) | ((l & BN_MASK2h) >> BN_BITS4)))) {
+ break;
+ }
+ q--;
+ th -= dh;
+ tl -= dl;
+ }
+ t = (tl >> BN_BITS4);
+ tl = (tl << BN_BITS4) & BN_MASK2h;
+ th += t;
+
+ if (l < tl) {
+ th++;
+ }
+ l -= tl;
+ if (h < th) {
+ h += d;
+ q--;
+ }
+ h -= th;
+
+ if (--count == 0) {
+ break;
+ }
+
+ ret = q << BN_BITS4;
+ h = ((h << BN_BITS4) | (l >> BN_BITS4)) & BN_MASK2;
+ l = (l & BN_MASK2l) << BN_BITS4;
+ }
+
+ ret |= q;
+ return ret;
+}
+#endif /* !defined(BN_ULLONG) */
+
+static inline void bn_div_rem_words(BN_ULONG *quotient_out, BN_ULONG *rem_out,
+ BN_ULONG n0, BN_ULONG n1, BN_ULONG d0) {
+ /* GCC and Clang generate function calls to |__udivdi3| and |__umoddi3| when
+ * the |BN_ULLONG|-based C code is used.
+ *
+ * GCC bugs:
+ * * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14224
+ * * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721
+ * * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54183
+ * * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58897
+ * * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65668
+ *
+ * Clang bugs:
+ * * https://llvm.org/bugs/show_bug.cgi?id=6397
+ * * https://llvm.org/bugs/show_bug.cgi?id=12418
+ *
+ * These issues aren't specific to x86 and x86_64, so it might be worthwhile
+ * to add more assembly language implementations. */
+#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86) && defined(__GNUC__)
+ __asm__ volatile (
+ "divl %4"
+ : "=a"(*quotient_out), "=d"(*rem_out)
+ : "a"(n1), "d"(n0), "g"(d0)
+ : "cc" );
+#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && defined(__GNUC__)
+ __asm__ volatile (
+ "divq %4"
+ : "=a"(*quotient_out), "=d"(*rem_out)
+ : "a"(n1), "d"(n0), "g"(d0)
+ : "cc" );
+#else
+#if defined(BN_ULLONG)
+ BN_ULLONG n = (((BN_ULLONG)n0) << BN_BITS2) | n1;
+ *quotient_out = (BN_ULONG)(n / d0);
+#else
+ *quotient_out = bn_div_words(n0, n1, d0);
+#endif
+ *rem_out = n1 - (*quotient_out * d0);
+#endif
+}
/* BN_div computes dv := num / divisor, rounding towards
* zero, and sets up rm such that dv*divisor + rm = num holds.
@@ -260,23 +331,10 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
q = BN_MASK2;
} else {
/* n0 < d0 */
-#ifdef BN_ULLONG
- BN_ULLONG t2;
-
-#if defined(BN_ULLONG) && !defined(div_asm)
- q = (BN_ULONG)(((((BN_ULLONG)n0) << BN_BITS2) | n1) / d0);
-#else
- q = div_asm(n0, n1, d0);
-#endif
-
-#ifndef REMAINDER_IS_ALREADY_CALCULATED
- /* rem doesn't have to be BN_ULLONG. The least we know it's less that d0,
- * isn't it? */
- rem = (n1 - q * d0) & BN_MASK2;
-#endif
-
- t2 = (BN_ULLONG)d1 * q;
+ bn_div_rem_words(&q, &rem, n0, n1, d0);
+#ifdef BN_ULLONG
+ BN_ULLONG t2 = (BN_ULLONG)d1 * q;
for (;;) {
if (t2 <= ((((BN_ULLONG)rem) << BN_BITS2) | wnump[-2])) {
break;
@@ -290,13 +348,7 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
}
#else /* !BN_ULLONG */
BN_ULONG t2l, t2h;
-
- q = bn_div_words(n0, n1, d0);
-
- rem = (n1 - q * d0) & BN_MASK2;
-
BN_UMULT_LOHI(t2l, t2h, d1, q);
-
for (;;) {
if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) {
break;
@@ -556,7 +608,7 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
return 0;
}
- /* normalize input (so bn_div_words doesn't complain) */
+ /* normalize input for |bn_div_rem_words|. */
j = BN_BITS2 - BN_num_bits_word(w);
w <<= j;
if (!BN_lshift(a, a, j)) {
@@ -564,10 +616,10 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
}
for (i = a->top - 1; i >= 0; i--) {
- BN_ULONG l, d;
-
- l = a->d[i];
- d = bn_div_words(ret, l, w);
+ BN_ULONG l = a->d[i];
+ BN_ULONG d;
+ BN_ULONG unused_rem;
+ bn_div_rem_words(&d, &unused_rem, ret, l, w);
ret = (l - ((d * w) & BN_MASK2)) & BN_MASK2;
a->d[i] = d;
}
@@ -592,6 +644,20 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) {
return (BN_ULONG) -1;
}
+#ifndef BN_ULLONG
+ /* If |w| is too long and we don't have |BN_ULLONG| then we need to fall back
+ * to using |BN_div_word|. */
+ if (w > ((BN_ULONG)1 << BN_BITS4)) {
+ BIGNUM *tmp = BN_dup(a);
+ if (tmp == NULL) {
+ return (BN_ULONG)-1;
+ }
+ ret = BN_div_word(tmp, w);
+ BN_free(tmp);
+ return ret;
+ }
+#endif
+
w &= BN_MASK2;
for (i = a->top - 1; i >= 0; i--) {
#ifndef BN_ULLONG
diff --git a/crypto/bn/exponentiation.c b/crypto/bn/exponentiation.c
index f7100ac3..eedc88e8 100644
--- a/crypto/bn/exponentiation.c
+++ b/crypto/bn/exponentiation.c
@@ -209,6 +209,7 @@ static void BN_RECP_CTX_init(BN_RECP_CTX *recp) {
BN_init(&recp->N);
BN_init(&recp->Nr);
recp->num_bits = 0;
+ recp->shift = 0;
recp->flags = 0;
}
@@ -575,41 +576,7 @@ err:
int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
BN_CTX *ctx) {
- /* For even modulus m = 2^k*m_odd, it might make sense to compute
- * a^p mod m_odd and a^p mod 2^k separately (with Montgomery
- * exponentiation for the odd part), using appropriate exponent
- * reductions, and combine the results using the CRT.
- *
- * For now, we use Montgomery only if the modulus is odd; otherwise,
- * exponentiation using the reciprocal-based quick remaindering
- * algorithm is used.
- *
- * (Timing obtained with expspeed.c [computations a^p mod m
- * where a, p, m are of the same length: 256, 512, 1024, 2048,
- * 4096, 8192 bits], compared to the running time of the
- * standard algorithm:
- *
- * BN_mod_exp_mont 33 .. 40 % [AMD K6-2, Linux, debug configuration]
- * 55 .. 77 % [UltraSparc processor, but
- * debug-solaris-sparcv8-gcc conf.]
- *
- * BN_mod_exp_recp 50 .. 70 % [AMD K6-2, Linux, debug configuration]
- * 62 .. 118 % [UltraSparc, debug-solaris-sparcv8-gcc]
- *
- * On the Sparc, BN_mod_exp_recp was faster than BN_mod_exp_mont
- * at 2048 and more bits, but at 512 and 1024 bits, it was
- * slower even than the standard algorithm!
- *
- * "Real" timings [linux-elf, solaris-sparcv9-gcc configurations]
- * should be obtained when the new Montgomery reduction code
- * has been integrated into OpenSSL.) */
-
if (BN_is_odd(m)) {
- if (a->top == 1 && !a->neg && BN_get_flags(p, BN_FLG_CONSTTIME) == 0) {
- BN_ULONG A = a->d[0];
- return BN_mod_exp_mont_word(r, A, p, m, ctx, NULL);
- }
-
return BN_mod_exp_mont(r, a, p, m, ctx, NULL);
}
@@ -787,29 +754,65 @@ err:
* pattern as far as cache lines are concerned. The following functions are
* used to transfer a BIGNUM from/to that table. */
static int copy_to_prebuf(const BIGNUM *b, int top, unsigned char *buf, int idx,
- int width) {
- size_t i, j;
+ int window) {
+ int i, j;
+ const int width = 1 << window;
+ BN_ULONG *table = (BN_ULONG *) buf;
if (top > b->top) {
top = b->top; /* this works because 'buf' is explicitly zeroed */
}
- for (i = 0, j = idx; i < top * sizeof b->d[0]; i++, j += width) {
- buf[j] = ((unsigned char *)b->d)[i];
+
+ for (i = 0, j = idx; i < top; i++, j += width) {
+ table[j] = b->d[i];
}
return 1;
}
static int copy_from_prebuf(BIGNUM *b, int top, unsigned char *buf, int idx,
- int width) {
- size_t i, j;
+ int window) {
+ int i, j;
+ const int width = 1 << window;
+ volatile BN_ULONG *table = (volatile BN_ULONG *)buf;
if (bn_wexpand(b, top) == NULL) {
return 0;
}
- for (i = 0, j = idx; i < top * sizeof b->d[0]; i++, j += width) {
- ((unsigned char *)b->d)[i] = buf[j];
+ if (window <= 3) {
+ for (i = 0; i < top; i++, table += width) {
+ BN_ULONG acc = 0;
+
+ for (j = 0; j < width; j++) {
+ acc |= table[j] & ((BN_ULONG)0 - (constant_time_eq_int(j, idx) & 1));
+ }
+
+ b->d[i] = acc;
+ }
+ } else {
+ int xstride = 1 << (window - 2);
+ BN_ULONG y0, y1, y2, y3;
+
+ i = idx >> (window - 2); /* equivalent of idx / xstride */
+ idx &= xstride - 1; /* equivalent of idx % xstride */
+
+ y0 = (BN_ULONG)0 - (constant_time_eq_int(i, 0) & 1);
+ y1 = (BN_ULONG)0 - (constant_time_eq_int(i, 1) & 1);
+ y2 = (BN_ULONG)0 - (constant_time_eq_int(i, 2) & 1);
+ y3 = (BN_ULONG)0 - (constant_time_eq_int(i, 3) & 1);
+
+ for (i = 0; i < top; i++, table += width) {
+ BN_ULONG acc = 0;
+
+ for (j = 0; j < xstride; j++) {
+ acc |= ((table[j + 0 * xstride] & y0) | (table[j + 1 * xstride] & y1) |
+ (table[j + 2 * xstride] & y2) | (table[j + 3 * xstride] & y3)) &
+ ((BN_ULONG)0 - (constant_time_eq_int(j, idx) & 1));
+ }
+
+ b->d[i] = acc;
+ }
}
b->top = top;
@@ -891,8 +894,6 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
return BN_one(rr);
}
- BN_CTX_start(ctx);
-
/* Allocate a montgomery context if it was not supplied by the caller. */
if (mont == NULL) {
new_mont = BN_MONT_CTX_new();
@@ -935,9 +936,8 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
#if defined(OPENSSL_BN_ASM_MONT5)
if (window >= 5) {
window = 5; /* ~5% improvement for RSA2048 sign, and even for RSA4096 */
- if ((top & 7) == 0) {
- powerbufLen += 2 * top * sizeof(m->d[0]);
- }
+ /* reserve space for mont->N.d[] copy */
+ powerbufLen += top * sizeof(mont->N.d[0]);
}
#endif
@@ -1008,7 +1008,8 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
/* Dedicated window==4 case improves 512-bit RSA sign by ~15%, but as
* 512-bit RSA is hardly relevant, we omit it to spare size... */
if (window == 5 && top > 1) {
- const BN_ULONG *np = mont->N.d, *n0 = mont->n0, *np2;
+ const BN_ULONG *n0 = mont->n0;
+ BN_ULONG *np;
/* BN_to_montgomery can contaminate words above .top
* [in BN_DEBUG[_DEBUG] build]... */
@@ -1019,14 +1020,9 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
tmp.d[i] = 0;
}
- if (top & 7) {
- np2 = np;
- } else {
- BN_ULONG *np_double = am.d + top;
- for (i = 0; i < top; i++) {
- np_double[2 * i] = np[i];
- }
- np2 = np_double;
+ /* copy mont->N.d[] to improve cache locality */
+ for (np = am.d + top, i = 0; i < top; i++) {
+ np[i] = mont->N.d[i];
}
bn_scatter5(tmp.d, top, powerbuf, 0);
@@ -1041,7 +1037,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
}
for (i = 3; i < 8; i += 2) {
int j;
- bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1);
+ bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np, n0, top, i - 1);
bn_scatter5(tmp.d, top, powerbuf, i);
for (j = 2 * i; j < 32; j *= 2) {
bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
@@ -1049,13 +1045,13 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
}
}
for (; i < 16; i += 2) {
- bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1);
+ bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np, n0, top, i - 1);
bn_scatter5(tmp.d, top, powerbuf, i);
bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
bn_scatter5(tmp.d, top, powerbuf, 2 * i);
}
for (; i < 32; i += 2) {
- bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1);
+ bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np, n0, top, i - 1);
bn_scatter5(tmp.d, top, powerbuf, i);
}
@@ -1103,7 +1099,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
wvalue >>= (bits - 4) & 7;
wvalue &= 0x1f;
bits -= 5;
- bn_power5(tmp.d, tmp.d, powerbuf, np2, n0, top, wvalue);
+ bn_power5(tmp.d, tmp.d, powerbuf, np, n0, top, wvalue);
}
while (bits >= 0) {
/* Read five bits from |bits-4| through |bits|, inclusive. */
@@ -1112,11 +1108,11 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
wvalue >>= first_bit & 7;
wvalue &= 0x1f;
bits -= 5;
- bn_power5(tmp.d, tmp.d, powerbuf, np2, n0, top, wvalue);
+ bn_power5(tmp.d, tmp.d, powerbuf, np, n0, top, wvalue);
}
}
- ret = bn_from_montgomery(tmp.d, tmp.d, NULL, np2, n0, top);
+ ret = bn_from_montgomery(tmp.d, tmp.d, NULL, np, n0, top);
tmp.top = top;
bn_correct_top(&tmp);
if (ret) {
@@ -1128,8 +1124,8 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
} else
#endif
{
- if (!copy_to_prebuf(&tmp, top, powerbuf, 0, numPowers) ||
- !copy_to_prebuf(&am, top, powerbuf, 1, numPowers)) {
+ if (!copy_to_prebuf(&tmp, top, powerbuf, 0, window) ||
+ !copy_to_prebuf(&am, top, powerbuf, 1, window)) {
goto err;
}
@@ -1140,13 +1136,13 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
*/
if (window > 1) {
if (!BN_mod_mul_montgomery(&tmp, &am, &am, mont, ctx) ||
- !copy_to_prebuf(&tmp, top, powerbuf, 2, numPowers)) {
+ !copy_to_prebuf(&tmp, top, powerbuf, 2, window)) {
goto err;
}
for (i = 3; i < numPowers; i++) {
/* Calculate a^i = a^(i-1) * a */
if (!BN_mod_mul_montgomery(&tmp, &am, &tmp, mont, ctx) ||
- !copy_to_prebuf(&tmp, top, powerbuf, i, numPowers)) {
+ !copy_to_prebuf(&tmp, top, powerbuf, i, window)) {
goto err;
}
}
@@ -1156,7 +1152,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
for (wvalue = 0, i = bits % window; i >= 0; i--, bits--) {
wvalue = (wvalue << 1) + BN_is_bit_set(p, bits);
}
- if (!copy_from_prebuf(&tmp, top, powerbuf, wvalue, numPowers)) {
+ if (!copy_from_prebuf(&tmp, top, powerbuf, wvalue, window)) {
goto err;
}
@@ -1175,7 +1171,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
}
/* Fetch the appropriate pre-computed value from the pre-buf */
- if (!copy_from_prebuf(&am, top, powerbuf, wvalue, numPowers)) {
+ if (!copy_from_prebuf(&am, top, powerbuf, wvalue, window)) {
goto err;
}
@@ -1198,158 +1194,27 @@ err:
OPENSSL_cleanse(powerbuf, powerbufLen);
OPENSSL_free(powerbufFree);
}
- BN_CTX_end(ctx);
return (ret);
}
int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p,
const BIGNUM *m, BN_CTX *ctx,
const BN_MONT_CTX *mont) {
- BN_MONT_CTX *new_mont = NULL;
- int b, bits, ret = 0;
- int r_is_one;
- BN_ULONG w, next_w;
- BIGNUM *d, *r, *t;
- BIGNUM *swap_tmp;
-#define BN_MOD_MUL_WORD(r, w, m) \
- (BN_mul_word(r, (w)) && \
- (/* BN_ucmp(r, (m)) < 0 ? 1 :*/ \
- (BN_mod(t, r, m, ctx) && (swap_tmp = r, r = t, t = swap_tmp, 1))))
- /* BN_MOD_MUL_WORD is only used with 'w' large, so the BN_ucmp test is
- * probably more overhead than always using BN_mod (which uses BN_copy if a
- * similar test returns true). We can use BN_mod and do not need BN_nnmod
- * because our accumulator is never negative (the result of BN_mod does not
- * depend on the sign of the modulus). */
-#define BN_TO_MONTGOMERY_WORD(r, w, mont) \
- (BN_set_word(r, (w)) && BN_to_montgomery(r, r, (mont), ctx))
-
- if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
- /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
- OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return 0;
- }
-
- if (!BN_is_odd(m)) {
- OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
- return 0;
- }
+ BIGNUM a_bignum;
+ BN_init(&a_bignum);
- if (m->top == 1) {
- a %= m->d[0]; /* make sure that 'a' is reduced */
- }
-
- bits = BN_num_bits(p);
- if (bits == 0) {
- /* x**0 mod 1 is still zero. */
- if (BN_is_one(m)) {
- BN_zero(rr);
- return 1;
- }
- return BN_one(rr);
- }
- if (a == 0) {
- BN_zero(rr);
- return 1;
- }
+ int ret = 0;
- BN_CTX_start(ctx);
- d = BN_CTX_get(ctx);
- r = BN_CTX_get(ctx);
- t = BN_CTX_get(ctx);
- if (d == NULL || r == NULL || t == NULL) {
+ if (!BN_set_word(&a_bignum, a)) {
+ OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
goto err;
}
- /* Allocate a montgomery context if it was not supplied by the caller. */
- if (mont == NULL) {
- new_mont = BN_MONT_CTX_new();
- if (new_mont == NULL || !BN_MONT_CTX_set(new_mont, m, ctx)) {
- goto err;
- }
- mont = new_mont;
- }
-
- r_is_one = 1; /* except for Montgomery factor */
-
- /* bits-1 >= 0 */
-
- /* The result is accumulated in the product r*w. */
- w = a; /* bit 'bits-1' of 'p' is always set */
- for (b = bits - 2; b >= 0; b--) {
- /* First, square r*w. */
- next_w = w * w;
- if ((next_w / w) != w) {
- /* overflow */
- if (r_is_one) {
- if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) {
- goto err;
- }
- r_is_one = 0;
- } else {
- if (!BN_MOD_MUL_WORD(r, w, m)) {
- goto err;
- }
- }
- next_w = 1;
- }
-
- w = next_w;
- if (!r_is_one) {
- if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
- goto err;
- }
- }
-
- /* Second, multiply r*w by 'a' if exponent bit is set. */
- if (BN_is_bit_set(p, b)) {
- next_w = w * a;
- if ((next_w / a) != w) {
- /* overflow */
- if (r_is_one) {
- if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) {
- goto err;
- }
- r_is_one = 0;
- } else {
- if (!BN_MOD_MUL_WORD(r, w, m)) {
- goto err;
- }
- }
- next_w = a;
- }
- w = next_w;
- }
- }
-
- /* Finally, set r:=r*w. */
- if (w != 1) {
- if (r_is_one) {
- if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) {
- goto err;
- }
- r_is_one = 0;
- } else {
- if (!BN_MOD_MUL_WORD(r, w, m)) {
- goto err;
- }
- }
- }
-
- if (r_is_one) {
- /* can happen only if a == 1*/
- if (!BN_one(rr)) {
- goto err;
- }
- } else {
- if (!BN_from_montgomery(rr, r, mont, ctx)) {
- goto err;
- }
- }
- ret = 1;
+ ret = BN_mod_exp_mont(rr, &a_bignum, p, m, ctx, mont);
err:
- BN_MONT_CTX_free(new_mont);
- BN_CTX_end(ctx);
+ BN_free(&a_bignum);
+
return ret;
}
@@ -1358,36 +1223,11 @@ err:
int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1,
const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m,
BN_CTX *ctx, const BN_MONT_CTX *mont) {
- int i, j, bits, b, bits1, bits2, ret = 0, wpos1, wpos2, window1, window2,
- wvalue1, wvalue2;
- int r_is_one = 1;
- BIGNUM *d, *r;
- const BIGNUM *a_mod_m;
- /* Tables of variables obtained from 'ctx' */
- BIGNUM *val1[TABLE_SIZE], *val2[TABLE_SIZE];
- BN_MONT_CTX *new_mont = NULL;
-
- if (!(m->d[0] & 1)) {
- OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
- return 0;
- }
- bits1 = BN_num_bits(p1);
- bits2 = BN_num_bits(p2);
- if (bits1 == 0 && bits2 == 0) {
- ret = BN_one(rr);
- return ret;
- }
-
- bits = (bits1 > bits2) ? bits1 : bits2;
+ BIGNUM tmp;
+ BN_init(&tmp);
- BN_CTX_start(ctx);
- d = BN_CTX_get(ctx);
- r = BN_CTX_get(ctx);
- val1[0] = BN_CTX_get(ctx);
- val2[0] = BN_CTX_get(ctx);
- if (!d || !r || !val1[0] || !val2[0]) {
- goto err;
- }
+ int ret = 0;
+ BN_MONT_CTX *new_mont = NULL;
/* Allocate a montgomery context if it was not supplied by the caller. */
if (mont == NULL) {
@@ -1398,156 +1238,21 @@ int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1,
mont = new_mont;
}
- window1 = BN_window_bits_for_exponent_size(bits1);
- window2 = BN_window_bits_for_exponent_size(bits2);
-
- /* Build table for a1: val1[i] := a1^(2*i + 1) mod m for i = 0 ..
- * 2^(window1-1) */
- if (a1->neg || BN_ucmp(a1, m) >= 0) {
- if (!BN_mod(val1[0], a1, m, ctx)) {
- goto err;
- }
- a_mod_m = val1[0];
- } else {
- a_mod_m = a1;
- }
-
- if (BN_is_zero(a_mod_m)) {
- BN_zero(rr);
- ret = 1;
- goto err;
- }
-
- if (!BN_to_montgomery(val1[0], a_mod_m, mont, ctx)) {
+ /* BN_mod_mul_montgomery removes one Montgomery factor, so passing one
+ * Montgomery-encoded and one non-Montgomery-encoded value gives a
+ * non-Montgomery-encoded result. */
+ if (!BN_mod_exp_mont(rr, a1, p1, m, ctx, mont) ||
+ !BN_mod_exp_mont(&tmp, a2, p2, m, ctx, mont) ||
+ !BN_to_montgomery(rr, rr, mont, ctx) ||
+ !BN_mod_mul_montgomery(rr, rr, &tmp, mont, ctx)) {
goto err;
}
- if (window1 > 1) {
- if (!BN_mod_mul_montgomery(d, val1[0], val1[0], mont, ctx)) {
- goto err;
- }
-
- j = 1 << (window1 - 1);
- for (i = 1; i < j; i++) {
- if (((val1[i] = BN_CTX_get(ctx)) == NULL) ||
- !BN_mod_mul_montgomery(val1[i], val1[i - 1], d, mont, ctx)) {
- goto err;
- }
- }
- }
-
- /* Build table for a2: val2[i] := a2^(2*i + 1) mod m for i = 0 ..
- * 2^(window2-1) */
- if (a2->neg || BN_ucmp(a2, m) >= 0) {
- if (!BN_mod(val2[0], a2, m, ctx)) {
- goto err;
- }
- a_mod_m = val2[0];
- } else {
- a_mod_m = a2;
- }
-
- if (BN_is_zero(a_mod_m)) {
- BN_zero(rr);
- ret = 1;
- goto err;
- }
-
- if (!BN_to_montgomery(val2[0], a_mod_m, mont, ctx)) {
- goto err;
- }
-
- if (window2 > 1) {
- if (!BN_mod_mul_montgomery(d, val2[0], val2[0], mont, ctx)) {
- goto err;
- }
-
- j = 1 << (window2 - 1);
- for (i = 1; i < j; i++) {
- if (((val2[i] = BN_CTX_get(ctx)) == NULL) ||
- !BN_mod_mul_montgomery(val2[i], val2[i - 1], d, mont, ctx)) {
- goto err;
- }
- }
- }
-
- /* Now compute the power product, using independent windows. */
- r_is_one = 1;
- wvalue1 = 0; /* The 'value' of the first window */
- wvalue2 = 0; /* The 'value' of the second window */
- wpos1 = 0; /* If wvalue1 > 0, the bottom bit of the first window */
- wpos2 = 0; /* If wvalue2 > 0, the bottom bit of the second window */
-
- if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) {
- goto err;
- }
-
- for (b = bits - 1; b >= 0; b--) {
- if (!r_is_one) {
- if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
- goto err;
- }
- }
-
- if (!wvalue1 && BN_is_bit_set(p1, b)) {
- /* consider bits b-window1+1 .. b for this window */
- i = b - window1 + 1;
- /* works for i<0 */
- while (!BN_is_bit_set(p1, i)) {
- i++;
- }
- wpos1 = i;
- wvalue1 = 1;
- for (i = b - 1; i >= wpos1; i--) {
- wvalue1 <<= 1;
- if (BN_is_bit_set(p1, i)) {
- wvalue1++;
- }
- }
- }
-
- if (!wvalue2 && BN_is_bit_set(p2, b)) {
- /* consider bits b-window2+1 .. b for this window */
- i = b - window2 + 1;
- while (!BN_is_bit_set(p2, i)) {
- i++;
- }
- wpos2 = i;
- wvalue2 = 1;
- for (i = b - 1; i >= wpos2; i--) {
- wvalue2 <<= 1;
- if (BN_is_bit_set(p2, i)) {
- wvalue2++;
- }
- }
- }
-
- if (wvalue1 && b == wpos1) {
- /* wvalue1 is odd and < 2^window1 */
- if (!BN_mod_mul_montgomery(r, r, val1[wvalue1 >> 1], mont, ctx)) {
- goto err;
- }
- wvalue1 = 0;
- r_is_one = 0;
- }
-
- if (wvalue2 && b == wpos2) {
- /* wvalue2 is odd and < 2^window2 */
- if (!BN_mod_mul_montgomery(r, r, val2[wvalue2 >> 1], mont, ctx)) {
- goto err;
- }
- wvalue2 = 0;
- r_is_one = 0;
- }
- }
-
- if (!BN_from_montgomery(rr, r, mont, ctx)) {
- goto err;
- }
ret = 1;
err:
BN_MONT_CTX_free(new_mont);
- BN_CTX_end(ctx);
+ BN_free(&tmp);
+
return ret;
}
diff --git a/crypto/bn/gcd.c b/crypto/bn/gcd.c
index 41ca6d21..c9a7123f 100644
--- a/crypto/bn/gcd.c
+++ b/crypto/bn/gcd.c
@@ -668,6 +668,12 @@ static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse,
sign = -sign;
}
+ if (!BN_is_one(A)) {
+ *out_no_inverse = 1;
+ OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE);
+ goto err;
+ }
+
/*
* The while loop (Euclid's algorithm) ends when
* A == gcd(a,n);
@@ -683,22 +689,17 @@ static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse,
}
/* Now Y*a == A (mod |n|). */
- if (BN_is_one(A)) {
- /* Y*a == 1 (mod |n|) */
- if (!Y->neg && BN_ucmp(Y, n) < 0) {
- if (!BN_copy(R, Y)) {
- goto err;
- }
- } else {
- if (!BN_nnmod(R, Y, n, ctx)) {
- goto err;
- }
+ /* Y*a == 1 (mod |n|) */
+ if (!Y->neg && BN_ucmp(Y, n) < 0) {
+ if (!BN_copy(R, Y)) {
+ goto err;
}
} else {
- *out_no_inverse = 1;
- OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE);
- goto err;
+ if (!BN_nnmod(R, Y, n, ctx)) {
+ goto err;
+ }
}
+
ret = R;
err:
diff --git a/crypto/bn/generic.c b/crypto/bn/generic.c
index cf2db8b8..f552d99f 100644
--- a/crypto/bn/generic.c
+++ b/crypto/bn/generic.c
@@ -202,86 +202,6 @@ void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) {
}
}
-#if defined(BN_ULLONG)
-
-BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) {
- return (BN_ULONG)(((((BN_ULLONG)h) << BN_BITS2) | l) / (BN_ULLONG)d);
-}
-
-#else
-
-/* Divide h,l by d and return the result. */
-BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) {
- BN_ULONG dh, dl, q, ret = 0, th, tl, t;
- int i, count = 2;
-
- if (d == 0) {
- return BN_MASK2;
- }
-
- i = BN_num_bits_word(d);
- assert((i == BN_BITS2) || (h <= (BN_ULONG)1 << i));
-
- i = BN_BITS2 - i;
- if (h >= d) {
- h -= d;
- }
-
- if (i) {
- d <<= i;
- h = (h << i) | (l >> (BN_BITS2 - i));
- l <<= i;
- }
- dh = (d & BN_MASK2h) >> BN_BITS4;
- dl = (d & BN_MASK2l);
- for (;;) {
- if ((h >> BN_BITS4) == dh) {
- q = BN_MASK2l;
- } else {
- q = h / dh;
- }
-
- th = q * dh;
- tl = dl * q;
- for (;;) {
- t = h - th;
- if ((t & BN_MASK2h) ||
- ((tl) <= ((t << BN_BITS4) | ((l & BN_MASK2h) >> BN_BITS4)))) {
- break;
- }
- q--;
- th -= dh;
- tl -= dl;
- }
- t = (tl >> BN_BITS4);
- tl = (tl << BN_BITS4) & BN_MASK2h;
- th += t;
-
- if (l < tl) {
- th++;
- }
- l -= tl;
- if (h < th) {
- h += d;
- q--;
- }
- h -= th;
-
- if (--count == 0) {
- break;
- }
-
- ret = q << BN_BITS4;
- h = ((h << BN_BITS4) | (l >> BN_BITS4)) & BN_MASK2;
- l = (l & BN_MASK2l) << BN_BITS4;
- }
-
- ret |= q;
- return ret;
-}
-
-#endif /* !defined(BN_ULLONG) */
-
#ifdef BN_ULLONG
BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
int n) {
diff --git a/crypto/bn/internal.h b/crypto/bn/internal.h
index 5c9baa4f..8b1c8660 100644
--- a/crypto/bn/internal.h
+++ b/crypto/bn/internal.h
@@ -126,9 +126,9 @@
#include <openssl/base.h>
#if defined(OPENSSL_X86_64) && defined(_MSC_VER)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <intrin.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma intrinsic(__umulh, _umul128)
#endif
@@ -192,10 +192,14 @@ BIGNUM *bn_expand(BIGNUM *bn, size_t bits);
#define Hw(t) (((BN_ULONG)((t)>>BN_BITS2))&BN_MASK2)
#endif
+
+/* bn_set_words sets |bn| to the value encoded in the |num| words in |words|,
+ * least significant word first. */
+int bn_set_words(BIGNUM *bn, const BN_ULONG *words, size_t num);
+
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num);
-BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d);
BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num);
BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num);
diff --git a/crypto/bn/montgomery.c b/crypto/bn/montgomery.c
index d956d62b..7c3b420c 100644
--- a/crypto/bn/montgomery.c
+++ b/crypto/bn/montgomery.c
@@ -289,14 +289,14 @@ err:
return ret;
}
-BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock,
- const BIGNUM *mod, BN_CTX *bn_ctx) {
+int BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock,
+ const BIGNUM *mod, BN_CTX *bn_ctx) {
CRYPTO_MUTEX_lock_read(lock);
BN_MONT_CTX *ctx = *pmont;
- CRYPTO_MUTEX_unlock(lock);
+ CRYPTO_MUTEX_unlock_read(lock);
if (ctx) {
- return ctx;
+ return 1;
}
CRYPTO_MUTEX_lock_write(lock);
@@ -317,8 +317,8 @@ BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock,
*pmont = ctx;
out:
- CRYPTO_MUTEX_unlock(lock);
- return ctx;
+ CRYPTO_MUTEX_unlock_write(lock);
+ return ctx != NULL;
}
int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
@@ -326,14 +326,12 @@ int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
return BN_mod_mul_montgomery(ret, a, &mont->RR, mont, ctx);
}
-#if 0
static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r,
const BN_MONT_CTX *mont) {
- const BIGNUM *n;
BN_ULONG *ap, *np, *rp, n0, v, carry;
int nl, max, i;
- n = &mont->N;
+ const BIGNUM *n = &mont->N;
nl = n->top;
if (nl == 0) {
ret->top = 0;
@@ -376,13 +374,13 @@ static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r,
{
BN_ULONG *nrp;
- size_t m;
+ uintptr_t m;
v = bn_sub_words(rp, ap, np, nl) - carry;
/* if subtraction result is real, then trick unconditional memcpy below to
* perform in-place "refresh" instead of actual copy. */
- m = (0 - (size_t)v);
- nrp = (BN_ULONG *)(((intptr_t)rp & ~m) | ((intptr_t)ap & m));
+ m = (0u - (uintptr_t)v);
+ nrp = (BN_ULONG *)(((uintptr_t)rp & ~m) | ((uintptr_t)ap & m));
for (i = 0, nl -= 4; i < nl; i += 4) {
BN_ULONG t1, t2, t3, t4;
@@ -411,103 +409,25 @@ static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r,
return 1;
}
-#endif
-
-#define PTR_SIZE_INT size_t
-
-static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, const BN_MONT_CTX *mont)
- {
- BN_ULONG *ap,*np,*rp,n0,v,carry;
- int nl,max,i;
-
- const BIGNUM *n = &mont->N;
- nl=n->top;
- if (nl == 0) { ret->top=0; return(1); }
- max=(2*nl); /* carry is stored separately */
- if (bn_wexpand(r,max) == NULL) return(0);
-
- r->neg^=n->neg;
- np=n->d;
- rp=r->d;
-
- /* clear the top words of T */
-#if 1
- for (i=r->top; i<max; i++) /* memset? XXX */
- rp[i]=0;
-#else
- memset(&(rp[r->top]),0,(max-r->top)*sizeof(BN_ULONG));
-#endif
-
- r->top=max;
- n0=mont->n0[0];
-
- for (carry=0, i=0; i<nl; i++, rp++)
- {
- v=bn_mul_add_words(rp,np,nl,(rp[0]*n0)&BN_MASK2);
- v = (v+carry+rp[nl])&BN_MASK2;
- carry |= (v != rp[nl]);
- carry &= (v <= rp[nl]);
- rp[nl]=v;
- }
-
- if (bn_wexpand(ret,nl) == NULL) return(0);
- ret->top=nl;
- ret->neg=r->neg;
-
- rp=ret->d;
- ap=&(r->d[nl]);
-
- {
- BN_ULONG *nrp;
- size_t m;
-
- v=bn_sub_words(rp,ap,np,nl)-carry;
- /* if subtraction result is real, then
- * trick unconditional memcpy below to perform in-place
- * "refresh" instead of actual copy. */
- m=(0-(size_t)v);
- nrp=(BN_ULONG *)(((PTR_SIZE_INT)rp&~m)|((PTR_SIZE_INT)ap&m));
-
- for (i=0,nl-=4; i<nl; i+=4)
- {
- BN_ULONG t1,t2,t3,t4;
-
- t1=nrp[i+0];
- t2=nrp[i+1];
- t3=nrp[i+2]; ap[i+0]=0;
- t4=nrp[i+3]; ap[i+1]=0;
- rp[i+0]=t1; ap[i+2]=0;
- rp[i+1]=t2; ap[i+3]=0;
- rp[i+2]=t3;
- rp[i+3]=t4;
- }
- for (nl+=4; i<nl; i++)
- rp[i]=nrp[i], ap[i]=0;
- }
- bn_correct_top(r);
- bn_correct_top(ret);
-
- return(1);
- }
-
-int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
+int BN_from_montgomery(BIGNUM *r, const BIGNUM *a, const BN_MONT_CTX *mont,
BN_CTX *ctx) {
- int retn = 0;
+ int ret = 0;
BIGNUM *t;
BN_CTX_start(ctx);
t = BN_CTX_get(ctx);
- if (t == NULL) {
- return 0;
+ if (t == NULL ||
+ !BN_copy(t, a)) {
+ goto err;
}
- if (BN_copy(t, a)) {
- retn = BN_from_montgomery_word(ret, t, mont);
- }
+ ret = BN_from_montgomery_word(r, t, mont);
+
+err:
BN_CTX_end(ctx);
- return retn;
+ return ret;
}
int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
diff --git a/crypto/bn/mul.c b/crypto/bn/mul.c
index d2d8fd8c..06e53ee0 100644
--- a/crypto/bn/mul.c
+++ b/crypto/bn/mul.c
@@ -66,7 +66,8 @@
#define BN_SQR_RECURSIVE_SIZE_NORMAL BN_MUL_RECURSIVE_SIZE_NORMAL
-void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb) {
+static void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b,
+ int nb) {
BN_ULONG *rr;
if (na < nb) {
diff --git a/crypto/buf/buf.c b/crypto/buf/buf.c
index b918f01f..efe9952a 100644
--- a/crypto/buf/buf.c
+++ b/crypto/buf/buf.c
@@ -88,34 +88,26 @@ void BUF_MEM_free(BUF_MEM *buf) {
OPENSSL_free(buf);
}
-static size_t buf_mem_grow(BUF_MEM *buf, size_t len, char clean) {
- char *new_buf;
- size_t n, alloc_size;
-
- if (buf->length >= len) {
- buf->length = len;
- return len;
- }
- if (buf->max >= len) {
- memset(&buf->data[buf->length], 0, len - buf->length);
- buf->length = len;
- return len;
+static int buf_mem_reserve(BUF_MEM *buf, size_t cap, int clean) {
+ if (buf->max >= cap) {
+ return 1;
}
- n = len + 3;
- if (n < len) {
+ size_t n = cap + 3;
+ if (n < cap) {
/* overflow */
OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
return 0;
}
n = n / 3;
- alloc_size = n * 4;
+ size_t alloc_size = n * 4;
if (alloc_size / 4 != n) {
/* overflow */
OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
return 0;
}
+ char *new_buf;
if (buf->data == NULL) {
new_buf = OPENSSL_malloc(alloc_size);
} else {
@@ -128,14 +120,26 @@ static size_t buf_mem_grow(BUF_MEM *buf, size_t len, char clean) {
if (new_buf == NULL) {
OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
- len = 0;
- } else {
- buf->data = new_buf;
- buf->max = alloc_size;
- memset(&buf->data[buf->length], 0, len - buf->length);
- buf->length = len;
+ return 0;
}
+ buf->data = new_buf;
+ buf->max = alloc_size;
+ return 1;
+}
+
+int BUF_MEM_reserve(BUF_MEM *buf, size_t cap) {
+ return buf_mem_reserve(buf, cap, 0 /* don't clear old buffer contents. */);
+}
+
+static size_t buf_mem_grow(BUF_MEM *buf, size_t len, int clean) {
+ if (!buf_mem_reserve(buf, len, clean)) {
+ return 0;
+ }
+ if (buf->length < len) {
+ memset(&buf->data[buf->length], 0, len - buf->length);
+ }
+ buf->length = len;
return len;
}
diff --git a/crypto/bytestring/ber.c b/crypto/bytestring/ber.c
index 2a968e16..04fcac6a 100644
--- a/crypto/bytestring/ber.c
+++ b/crypto/bytestring/ber.c
@@ -34,6 +34,7 @@ static int is_string_type(unsigned tag) {
switch (tag & 0x1f) {
case CBS_ASN1_BITSTRING:
case CBS_ASN1_OCTETSTRING:
+ case CBS_ASN1_UTF8STRING:
case CBS_ASN1_NUMERICSTRING:
case CBS_ASN1_PRINTABLESTRING:
case CBS_ASN1_T16STRING:
diff --git a/crypto/bytestring/bytestring_test.cc b/crypto/bytestring/bytestring_test.cc
index 84ecffcd..e1d16f49 100644
--- a/crypto/bytestring/bytestring_test.cc
+++ b/crypto/bytestring/bytestring_test.cc
@@ -43,7 +43,7 @@ static bool TestSkip() {
}
static bool TestGetUint() {
- static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
uint8_t u8;
uint16_t u16;
uint32_t u32;
@@ -58,7 +58,10 @@ static bool TestGetUint() {
u32 == 0x40506 &&
CBS_get_u32(&data, &u32) &&
u32 == 0x708090a &&
- !CBS_get_u8(&data, &u8);
+ CBS_get_last_u8(&data, &u8) &&
+ u8 == 0xb &&
+ !CBS_get_u8(&data, &u8) &&
+ !CBS_get_last_u8(&data, &u8);
}
static bool TestGetPrefixed() {
diff --git a/crypto/bytestring/cbs.c b/crypto/bytestring/cbs.c
index 5e0c538a..c86afbda 100644
--- a/crypto/bytestring/cbs.c
+++ b/crypto/bytestring/cbs.c
@@ -128,6 +128,15 @@ int CBS_get_u32(CBS *cbs, uint32_t *out) {
return cbs_get_u(cbs, out, 4);
}
+int CBS_get_last_u8(CBS *cbs, uint8_t *out) {
+ if (cbs->len == 0) {
+ return 0;
+ }
+ *out = cbs->data[cbs->len - 1];
+ cbs->len--;
+ return 1;
+}
+
int CBS_get_bytes(CBS *cbs, CBS *out, size_t len) {
const uint8_t *v;
if (!cbs_get(cbs, &v, len)) {
@@ -181,8 +190,14 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
return 0;
}
+ /* ITU-T X.690 section 8.1.2.3 specifies the format for identifiers with a tag
+ * number no greater than 30.
+ *
+ * If the number portion is 31 (0x1f, the largest value that fits in the
+ * allotted bits), then the tag is more than one byte long and the
+ * continuation bytes contain the tag number. This parser only supports tag
+ * numbers less than 31 (and thus single-byte tags). */
if ((tag & 0x1f) == 0x1f) {
- /* Long form tags are not supported. */
return 0;
}
@@ -191,6 +206,8 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
}
size_t len;
+ /* The format for the length encoding is specified in ITU-T X.690 section
+ * 8.1.3. */
if ((length_byte & 0x80) == 0) {
/* Short form length. */
len = ((size_t) length_byte) + 2;
@@ -198,7 +215,9 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
*out_header_len = 2;
}
} else {
- /* Long form length. */
+ /* The high bit indicate that this is the long form, while the next 7 bits
+ * encode the number of subsequent octets used to encode the length (ITU-T
+ * X.690 clause 8.1.3.5.b). */
const size_t num_bytes = length_byte & 0x7f;
uint32_t len32;
@@ -210,12 +229,18 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
return CBS_get_bytes(cbs, out, 2);
}
+ /* ITU-T X.690 clause 8.1.3.5.c specifies that the value 0xff shall not be
+ * used as the first byte of the length. If this parser encounters that
+ * value, num_bytes will be parsed as 127, which will fail the check below.
+ */
if (num_bytes == 0 || num_bytes > 4) {
return 0;
}
if (!cbs_get_u(&header, &len32, num_bytes)) {
return 0;
}
+ /* ITU-T X.690 section 10.1 (DER length forms) requires encoding the length
+ * with the minimum number of octets. */
if (len32 < 128) {
/* Length should have used short-form encoding. */
return 0;
diff --git a/crypto/chacha/CMakeLists.txt b/crypto/chacha/CMakeLists.txt
index 266e8699..73cfc31e 100644
--- a/crypto/chacha/CMakeLists.txt
+++ b/crypto/chacha/CMakeLists.txt
@@ -4,7 +4,31 @@ if (${ARCH} STREQUAL "arm")
set(
CHACHA_ARCH_SOURCES
- chacha_vec_arm.S
+ chacha-armv4.${ASM_EXT}
+ )
+endif()
+
+if (${ARCH} STREQUAL "aarch64")
+ set(
+ CHACHA_ARCH_SOURCES
+
+ chacha-armv8.${ASM_EXT}
+ )
+endif()
+
+if (${ARCH} STREQUAL "x86")
+ set(
+ CHACHA_ARCH_SOURCES
+
+ chacha-x86.${ASM_EXT}
+ )
+endif()
+
+if (${ARCH} STREQUAL "x86_64")
+ set(
+ CHACHA_ARCH_SOURCES
+
+ chacha-x86_64.${ASM_EXT}
)
endif()
@@ -13,8 +37,24 @@ add_library(
OBJECT
- chacha_generic.c
- chacha_vec.c
+ chacha.c
${CHACHA_ARCH_SOURCES}
)
+
+if(ENABLE_TESTS)
+add_executable(
+ chacha_test
+
+ chacha_test.cc
+ $<TARGET_OBJECTS:test_support>
+)
+
+target_link_libraries(chacha_test crypto)
+add_dependencies(all_tests chacha_test)
+endif()
+
+perlasm(chacha-armv4.${ASM_EXT} asm/chacha-armv4.pl)
+perlasm(chacha-armv8.${ASM_EXT} asm/chacha-armv8.pl)
+perlasm(chacha-x86.${ASM_EXT} asm/chacha-x86.pl)
+perlasm(chacha-x86_64.${ASM_EXT} asm/chacha-x86_64.pl)
diff --git a/crypto/chacha/asm/chacha-armv4.pl b/crypto/chacha/asm/chacha-armv4.pl
new file mode 100755
index 00000000..b190445d
--- /dev/null
+++ b/crypto/chacha/asm/chacha-armv4.pl
@@ -0,0 +1,1151 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# December 2014
+#
+# ChaCha20 for ARMv4.
+#
+# Performance in cycles per byte out of large buffer.
+#
+# IALU/gcc-4.4 1xNEON 3xNEON+1xIALU
+#
+# Cortex-A5 19.3(*)/+95% 21.8 14.1
+# Cortex-A8 10.5(*)/+160% 13.9 6.35
+# Cortex-A9 12.9(**)/+110% 14.3 6.50
+# Cortex-A15 11.0/+40% 16.0 5.00
+# Snapdragon S4 11.5/+125% 13.6 4.90
+#
+# (*) most "favourable" result for aligned data on little-endian
+# processor, result for misaligned data is 10-15% lower;
+# (**) this result is a trade-off: it can be improved by 20%,
+# but then Snapdragon S4 and Cortex-A8 results get
+# 20-25% worse;
+
+$flavour = shift;
+if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
+else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} }
+
+if ($flavour && $flavour ne "void") {
+ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+ ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
+ ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
+ die "can't locate arm-xlate.pl";
+
+ open STDOUT,"| \"$^X\" $xlate $flavour $output";
+} else {
+ open STDOUT,">$output";
+}
+
+sub AUTOLOAD() # thunk [simplified] x86-style perlasm
+{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
+ my $arg = pop;
+ $arg = "#$arg" if ($arg*1 eq $arg);
+ $code .= "\t$opcode\t".join(',',@_,$arg)."\n";
+}
+
+my @x=map("r$_",(0..7,"x","x","x","x",12,"x",14,"x"));
+my @t=map("r$_",(8..11));
+
+sub ROUND {
+my ($a0,$b0,$c0,$d0)=@_;
+my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
+my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
+my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
+my $odd = $d0&1;
+my ($xc,$xc_) = (@t[0..1]);
+my ($xd,$xd_) = $odd ? (@t[2],@x[$d1]) : (@x[$d0],@t[2]);
+my @ret;
+
+ # Consider order in which variables are addressed by their
+ # index:
+ #
+ # a b c d
+ #
+ # 0 4 8 12 < even round
+ # 1 5 9 13
+ # 2 6 10 14
+ # 3 7 11 15
+ # 0 5 10 15 < odd round
+ # 1 6 11 12
+ # 2 7 8 13
+ # 3 4 9 14
+ #
+ # 'a', 'b' are permanently allocated in registers, @x[0..7],
+ # while 'c's and pair of 'd's are maintained in memory. If
+ # you observe 'c' column, you'll notice that pair of 'c's is
+ # invariant between rounds. This means that we have to reload
+ # them once per round, in the middle. This is why you'll see
+ # bunch of 'c' stores and loads in the middle, but none in
+ # the beginning or end. If you observe 'd' column, you'll
+ # notice that 15 and 13 are reused in next pair of rounds.
+ # This is why these two are chosen for offloading to memory,
+ # to make loads count more.
+ push @ret,(
+ "&add (@x[$a0],@x[$a0],@x[$b0])",
+ "&mov ($xd,$xd,'ror#16')",
+ "&add (@x[$a1],@x[$a1],@x[$b1])",
+ "&mov ($xd_,$xd_,'ror#16')",
+ "&eor ($xd,$xd,@x[$a0],'ror#16')",
+ "&eor ($xd_,$xd_,@x[$a1],'ror#16')",
+
+ "&add ($xc,$xc,$xd)",
+ "&mov (@x[$b0],@x[$b0],'ror#20')",
+ "&add ($xc_,$xc_,$xd_)",
+ "&mov (@x[$b1],@x[$b1],'ror#20')",
+ "&eor (@x[$b0],@x[$b0],$xc,'ror#20')",
+ "&eor (@x[$b1],@x[$b1],$xc_,'ror#20')",
+
+ "&add (@x[$a0],@x[$a0],@x[$b0])",
+ "&mov ($xd,$xd,'ror#24')",
+ "&add (@x[$a1],@x[$a1],@x[$b1])",
+ "&mov ($xd_,$xd_,'ror#24')",
+ "&eor ($xd,$xd,@x[$a0],'ror#24')",
+ "&eor ($xd_,$xd_,@x[$a1],'ror#24')",
+
+ "&add ($xc,$xc,$xd)",
+ "&mov (@x[$b0],@x[$b0],'ror#25')" );
+ push @ret,(
+ "&str ($xd,'[sp,#4*(16+$d0)]')",
+ "&ldr ($xd,'[sp,#4*(16+$d2)]')" ) if ($odd);
+ push @ret,(
+ "&add ($xc_,$xc_,$xd_)",
+ "&mov (@x[$b1],@x[$b1],'ror#25')" );
+ push @ret,(
+ "&str ($xd_,'[sp,#4*(16+$d1)]')",
+ "&ldr ($xd_,'[sp,#4*(16+$d3)]')" ) if (!$odd);
+ push @ret,(
+ "&eor (@x[$b0],@x[$b0],$xc,'ror#25')",
+ "&eor (@x[$b1],@x[$b1],$xc_,'ror#25')" );
+
+ $xd=@x[$d2] if (!$odd);
+ $xd_=@x[$d3] if ($odd);
+ push @ret,(
+ "&str ($xc,'[sp,#4*(16+$c0)]')",
+ "&ldr ($xc,'[sp,#4*(16+$c2)]')",
+ "&add (@x[$a2],@x[$a2],@x[$b2])",
+ "&mov ($xd,$xd,'ror#16')",
+ "&str ($xc_,'[sp,#4*(16+$c1)]')",
+ "&ldr ($xc_,'[sp,#4*(16+$c3)]')",
+ "&add (@x[$a3],@x[$a3],@x[$b3])",
+ "&mov ($xd_,$xd_,'ror#16')",
+ "&eor ($xd,$xd,@x[$a2],'ror#16')",
+ "&eor ($xd_,$xd_,@x[$a3],'ror#16')",
+
+ "&add ($xc,$xc,$xd)",
+ "&mov (@x[$b2],@x[$b2],'ror#20')",
+ "&add ($xc_,$xc_,$xd_)",
+ "&mov (@x[$b3],@x[$b3],'ror#20')",
+ "&eor (@x[$b2],@x[$b2],$xc,'ror#20')",
+ "&eor (@x[$b3],@x[$b3],$xc_,'ror#20')",
+
+ "&add (@x[$a2],@x[$a2],@x[$b2])",
+ "&mov ($xd,$xd,'ror#24')",
+ "&add (@x[$a3],@x[$a3],@x[$b3])",
+ "&mov ($xd_,$xd_,'ror#24')",
+ "&eor ($xd,$xd,@x[$a2],'ror#24')",
+ "&eor ($xd_,$xd_,@x[$a3],'ror#24')",
+
+ "&add ($xc,$xc,$xd)",
+ "&mov (@x[$b2],@x[$b2],'ror#25')",
+ "&add ($xc_,$xc_,$xd_)",
+ "&mov (@x[$b3],@x[$b3],'ror#25')",
+ "&eor (@x[$b2],@x[$b2],$xc,'ror#25')",
+ "&eor (@x[$b3],@x[$b3],$xc_,'ror#25')" );
+
+ @ret;
+}
+
+$code.=<<___;
+#include <openssl/arm_arch.h>
+
+.text
+#if defined(__thumb2__)
+.syntax unified
+.thumb
+#else
+.code 32
+#endif
+
+#if defined(__thumb2__) || defined(__clang__)
+#define ldrhsb ldrbhs
+#endif
+
+.align 5
+.Lsigma:
+.long 0x61707865,0x3320646e,0x79622d32,0x6b206574 @ endian-neutral
+.Lone:
+.long 1,0,0,0
+#if __ARM_MAX_ARCH__>=7
+.LOPENSSL_armcap:
+.word OPENSSL_armcap_P-.LChaCha20_ctr32
+#else
+.word -1
+#endif
+
+.globl ChaCha20_ctr32
+.type ChaCha20_ctr32,%function
+.align 5
+ChaCha20_ctr32:
+.LChaCha20_ctr32:
+ ldr r12,[sp,#0] @ pull pointer to counter and nonce
+ stmdb sp!,{r0-r2,r4-r11,lr}
+#if __ARM_ARCH__<7 && !defined(__thumb2__)
+ sub r14,pc,#16 @ ChaCha20_ctr32
+#else
+ adr r14,.LChaCha20_ctr32
+#endif
+ cmp r2,#0 @ len==0?
+#ifdef __thumb2__
+ itt eq
+#endif
+ addeq sp,sp,#4*3
+ beq .Lno_data
+#if __ARM_MAX_ARCH__>=7
+ cmp r2,#192 @ test len
+ bls .Lshort
+ ldr r4,[r14,#-32]
+ ldr r4,[r14,r4]
+# ifdef __APPLE__
+ ldr r4,[r4]
+# endif
+ tst r4,#ARMV7_NEON
+ bne .LChaCha20_neon
+.Lshort:
+#endif
+ ldmia r12,{r4-r7} @ load counter and nonce
+ sub sp,sp,#4*(16) @ off-load area
+ sub r14,r14,#64 @ .Lsigma
+ stmdb sp!,{r4-r7} @ copy counter and nonce
+ ldmia r3,{r4-r11} @ load key
+ ldmia r14,{r0-r3} @ load sigma
+ stmdb sp!,{r4-r11} @ copy key
+ stmdb sp!,{r0-r3} @ copy sigma
+ str r10,[sp,#4*(16+10)] @ off-load "@x[10]"
+ str r11,[sp,#4*(16+11)] @ off-load "@x[11]"
+ b .Loop_outer_enter
+
+.align 4
+.Loop_outer:
+ ldmia sp,{r0-r9} @ load key material
+ str @t[3],[sp,#4*(32+2)] @ save len
+ str r12, [sp,#4*(32+1)] @ save inp
+ str r14, [sp,#4*(32+0)] @ save out
+.Loop_outer_enter:
+ ldr @t[3], [sp,#4*(15)]
+ ldr @x[12],[sp,#4*(12)] @ modulo-scheduled load
+ ldr @t[2], [sp,#4*(13)]
+ ldr @x[14],[sp,#4*(14)]
+ str @t[3], [sp,#4*(16+15)]
+ mov @t[3],#10
+ b .Loop
+
+.align 4
+.Loop:
+ subs @t[3],@t[3],#1
+___
+ foreach (&ROUND(0, 4, 8,12)) { eval; }
+ foreach (&ROUND(0, 5,10,15)) { eval; }
+$code.=<<___;
+ bne .Loop
+
+ ldr @t[3],[sp,#4*(32+2)] @ load len
+
+ str @t[0], [sp,#4*(16+8)] @ modulo-scheduled store
+ str @t[1], [sp,#4*(16+9)]
+ str @x[12],[sp,#4*(16+12)]
+ str @t[2], [sp,#4*(16+13)]
+ str @x[14],[sp,#4*(16+14)]
+
+ @ at this point we have first half of 512-bit result in
+ @ @x[0-7] and second half at sp+4*(16+8)
+
+ cmp @t[3],#64 @ done yet?
+#ifdef __thumb2__
+ itete lo
+#endif
+ addlo r12,sp,#4*(0) @ shortcut or ...
+ ldrhs r12,[sp,#4*(32+1)] @ ... load inp
+ addlo r14,sp,#4*(0) @ shortcut or ...
+ ldrhs r14,[sp,#4*(32+0)] @ ... load out
+
+ ldr @t[0],[sp,#4*(0)] @ load key material
+ ldr @t[1],[sp,#4*(1)]
+
+#if __ARM_ARCH__>=6 || !defined(__ARMEB__)
+# if __ARM_ARCH__<7
+ orr @t[2],r12,r14
+ tst @t[2],#3 @ are input and output aligned?
+ ldr @t[2],[sp,#4*(2)]
+ bne .Lunaligned
+ cmp @t[3],#64 @ restore flags
+# else
+ ldr @t[2],[sp,#4*(2)]
+# endif
+ ldr @t[3],[sp,#4*(3)]
+
+ add @x[0],@x[0],@t[0] @ accumulate key material
+ add @x[1],@x[1],@t[1]
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhs @t[0],[r12],#16 @ load input
+ ldrhs @t[1],[r12,#-12]
+
+ add @x[2],@x[2],@t[2]
+ add @x[3],@x[3],@t[3]
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhs @t[2],[r12,#-8]
+ ldrhs @t[3],[r12,#-4]
+# if __ARM_ARCH__>=6 && defined(__ARMEB__)
+ rev @x[0],@x[0]
+ rev @x[1],@x[1]
+ rev @x[2],@x[2]
+ rev @x[3],@x[3]
+# endif
+# ifdef __thumb2__
+ itt hs
+# endif
+ eorhs @x[0],@x[0],@t[0] @ xor with input
+ eorhs @x[1],@x[1],@t[1]
+ add @t[0],sp,#4*(4)
+ str @x[0],[r14],#16 @ store output
+# ifdef __thumb2__
+ itt hs
+# endif
+ eorhs @x[2],@x[2],@t[2]
+ eorhs @x[3],@x[3],@t[3]
+ ldmia @t[0],{@t[0]-@t[3]} @ load key material
+ str @x[1],[r14,#-12]
+ str @x[2],[r14,#-8]
+ str @x[3],[r14,#-4]
+
+ add @x[4],@x[4],@t[0] @ accumulate key material
+ add @x[5],@x[5],@t[1]
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhs @t[0],[r12],#16 @ load input
+ ldrhs @t[1],[r12,#-12]
+ add @x[6],@x[6],@t[2]
+ add @x[7],@x[7],@t[3]
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhs @t[2],[r12,#-8]
+ ldrhs @t[3],[r12,#-4]
+# if __ARM_ARCH__>=6 && defined(__ARMEB__)
+ rev @x[4],@x[4]
+ rev @x[5],@x[5]
+ rev @x[6],@x[6]
+ rev @x[7],@x[7]
+# endif
+# ifdef __thumb2__
+ itt hs
+# endif
+ eorhs @x[4],@x[4],@t[0]
+ eorhs @x[5],@x[5],@t[1]
+ add @t[0],sp,#4*(8)
+ str @x[4],[r14],#16 @ store output
+# ifdef __thumb2__
+ itt hs
+# endif
+ eorhs @x[6],@x[6],@t[2]
+ eorhs @x[7],@x[7],@t[3]
+ str @x[5],[r14,#-12]
+ ldmia @t[0],{@t[0]-@t[3]} @ load key material
+ str @x[6],[r14,#-8]
+ add @x[0],sp,#4*(16+8)
+ str @x[7],[r14,#-4]
+
+ ldmia @x[0],{@x[0]-@x[7]} @ load second half
+
+ add @x[0],@x[0],@t[0] @ accumulate key material
+ add @x[1],@x[1],@t[1]
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhs @t[0],[r12],#16 @ load input
+ ldrhs @t[1],[r12,#-12]
+# ifdef __thumb2__
+ itt hi
+# endif
+ strhi @t[2],[sp,#4*(16+10)] @ copy "@x[10]" while at it
+ strhi @t[3],[sp,#4*(16+11)] @ copy "@x[11]" while at it
+ add @x[2],@x[2],@t[2]
+ add @x[3],@x[3],@t[3]
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhs @t[2],[r12,#-8]
+ ldrhs @t[3],[r12,#-4]
+# if __ARM_ARCH__>=6 && defined(__ARMEB__)
+ rev @x[0],@x[0]
+ rev @x[1],@x[1]
+ rev @x[2],@x[2]
+ rev @x[3],@x[3]
+# endif
+# ifdef __thumb2__
+ itt hs
+# endif
+ eorhs @x[0],@x[0],@t[0]
+ eorhs @x[1],@x[1],@t[1]
+ add @t[0],sp,#4*(12)
+ str @x[0],[r14],#16 @ store output
+# ifdef __thumb2__
+ itt hs
+# endif
+ eorhs @x[2],@x[2],@t[2]
+ eorhs @x[3],@x[3],@t[3]
+ str @x[1],[r14,#-12]
+ ldmia @t[0],{@t[0]-@t[3]} @ load key material
+ str @x[2],[r14,#-8]
+ str @x[3],[r14,#-4]
+
+ add @x[4],@x[4],@t[0] @ accumulate key material
+ add @x[5],@x[5],@t[1]
+# ifdef __thumb2__
+ itt hi
+# endif
+ addhi @t[0],@t[0],#1 @ next counter value
+ strhi @t[0],[sp,#4*(12)] @ save next counter value
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhs @t[0],[r12],#16 @ load input
+ ldrhs @t[1],[r12,#-12]
+ add @x[6],@x[6],@t[2]
+ add @x[7],@x[7],@t[3]
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhs @t[2],[r12,#-8]
+ ldrhs @t[3],[r12,#-4]
+# if __ARM_ARCH__>=6 && defined(__ARMEB__)
+ rev @x[4],@x[4]
+ rev @x[5],@x[5]
+ rev @x[6],@x[6]
+ rev @x[7],@x[7]
+# endif
+# ifdef __thumb2__
+ itt hs
+# endif
+ eorhs @x[4],@x[4],@t[0]
+ eorhs @x[5],@x[5],@t[1]
+# ifdef __thumb2__
+ it ne
+# endif
+ ldrne @t[0],[sp,#4*(32+2)] @ re-load len
+# ifdef __thumb2__
+ itt hs
+# endif
+ eorhs @x[6],@x[6],@t[2]
+ eorhs @x[7],@x[7],@t[3]
+ str @x[4],[r14],#16 @ store output
+ str @x[5],[r14,#-12]
+# ifdef __thumb2__
+ it hs
+# endif
+ subhs @t[3],@t[0],#64 @ len-=64
+ str @x[6],[r14,#-8]
+ str @x[7],[r14,#-4]
+ bhi .Loop_outer
+
+ beq .Ldone
+# if __ARM_ARCH__<7
+ b .Ltail
+
+.align 4
+.Lunaligned: @ unaligned endian-neutral path
+ cmp @t[3],#64 @ restore flags
+# endif
+#endif
+#if __ARM_ARCH__<7
+ ldr @t[3],[sp,#4*(3)]
+___
+for ($i=0;$i<16;$i+=4) {
+my $j=$i&0x7;
+
+$code.=<<___ if ($i==4);
+ add @x[0],sp,#4*(16+8)
+___
+$code.=<<___ if ($i==8);
+ ldmia @x[0],{@x[0]-@x[7]} @ load second half
+# ifdef __thumb2__
+ itt hi
+# endif
+ strhi @t[2],[sp,#4*(16+10)] @ copy "@x[10]"
+ strhi @t[3],[sp,#4*(16+11)] @ copy "@x[11]"
+___
+$code.=<<___;
+ add @x[$j+0],@x[$j+0],@t[0] @ accumulate key material
+___
+$code.=<<___ if ($i==12);
+# ifdef __thumb2__
+ itt hi
+# endif
+ addhi @t[0],@t[0],#1 @ next counter value
+ strhi @t[0],[sp,#4*(12)] @ save next counter value
+___
+$code.=<<___;
+ add @x[$j+1],@x[$j+1],@t[1]
+ add @x[$j+2],@x[$j+2],@t[2]
+# ifdef __thumb2__
+ itete lo
+# endif
+ eorlo @t[0],@t[0],@t[0] @ zero or ...
+ ldrhsb @t[0],[r12],#16 @ ... load input
+ eorlo @t[1],@t[1],@t[1]
+ ldrhsb @t[1],[r12,#-12]
+
+ add @x[$j+3],@x[$j+3],@t[3]
+# ifdef __thumb2__
+ itete lo
+# endif
+ eorlo @t[2],@t[2],@t[2]
+ ldrhsb @t[2],[r12,#-8]
+ eorlo @t[3],@t[3],@t[3]
+ ldrhsb @t[3],[r12,#-4]
+
+ eor @x[$j+0],@t[0],@x[$j+0] @ xor with input (or zero)
+ eor @x[$j+1],@t[1],@x[$j+1]
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhsb @t[0],[r12,#-15] @ load more input
+ ldrhsb @t[1],[r12,#-11]
+ eor @x[$j+2],@t[2],@x[$j+2]
+ strb @x[$j+0],[r14],#16 @ store output
+ eor @x[$j+3],@t[3],@x[$j+3]
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhsb @t[2],[r12,#-7]
+ ldrhsb @t[3],[r12,#-3]
+ strb @x[$j+1],[r14,#-12]
+ eor @x[$j+0],@t[0],@x[$j+0],lsr#8
+ strb @x[$j+2],[r14,#-8]
+ eor @x[$j+1],@t[1],@x[$j+1],lsr#8
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhsb @t[0],[r12,#-14] @ load more input
+ ldrhsb @t[1],[r12,#-10]
+ strb @x[$j+3],[r14,#-4]
+ eor @x[$j+2],@t[2],@x[$j+2],lsr#8
+ strb @x[$j+0],[r14,#-15]
+ eor @x[$j+3],@t[3],@x[$j+3],lsr#8
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhsb @t[2],[r12,#-6]
+ ldrhsb @t[3],[r12,#-2]
+ strb @x[$j+1],[r14,#-11]
+ eor @x[$j+0],@t[0],@x[$j+0],lsr#8
+ strb @x[$j+2],[r14,#-7]
+ eor @x[$j+1],@t[1],@x[$j+1],lsr#8
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhsb @t[0],[r12,#-13] @ load more input
+ ldrhsb @t[1],[r12,#-9]
+ strb @x[$j+3],[r14,#-3]
+ eor @x[$j+2],@t[2],@x[$j+2],lsr#8
+ strb @x[$j+0],[r14,#-14]
+ eor @x[$j+3],@t[3],@x[$j+3],lsr#8
+# ifdef __thumb2__
+ itt hs
+# endif
+ ldrhsb @t[2],[r12,#-5]
+ ldrhsb @t[3],[r12,#-1]
+ strb @x[$j+1],[r14,#-10]
+ strb @x[$j+2],[r14,#-6]
+ eor @x[$j+0],@t[0],@x[$j+0],lsr#8
+ strb @x[$j+3],[r14,#-2]
+ eor @x[$j+1],@t[1],@x[$j+1],lsr#8
+ strb @x[$j+0],[r14,#-13]
+ eor @x[$j+2],@t[2],@x[$j+2],lsr#8
+ strb @x[$j+1],[r14,#-9]
+ eor @x[$j+3],@t[3],@x[$j+3],lsr#8
+ strb @x[$j+2],[r14,#-5]
+ strb @x[$j+3],[r14,#-1]
+___
+$code.=<<___ if ($i<12);
+ add @t[0],sp,#4*(4+$i)
+ ldmia @t[0],{@t[0]-@t[3]} @ load key material
+___
+}
+$code.=<<___;
+# ifdef __thumb2__
+ it ne
+# endif
+ ldrne @t[0],[sp,#4*(32+2)] @ re-load len
+# ifdef __thumb2__
+ it hs
+# endif
+ subhs @t[3],@t[0],#64 @ len-=64
+ bhi .Loop_outer
+
+ beq .Ldone
+#endif
+
+.Ltail:
+ ldr r12,[sp,#4*(32+1)] @ load inp
+ add @t[1],sp,#4*(0)
+ ldr r14,[sp,#4*(32+0)] @ load out
+
+.Loop_tail:
+ ldrb @t[2],[@t[1]],#1 @ read buffer on stack
+ ldrb @t[3],[r12],#1 @ read input
+ subs @t[0],@t[0],#1
+ eor @t[3],@t[3],@t[2]
+ strb @t[3],[r14],#1 @ store output
+ bne .Loop_tail
+
+.Ldone:
+ add sp,sp,#4*(32+3)
+.Lno_data:
+ ldmia sp!,{r4-r11,pc}
+.size ChaCha20_ctr32,.-ChaCha20_ctr32
+___
+
+{{{
+my ($a0,$b0,$c0,$d0,$a1,$b1,$c1,$d1,$a2,$b2,$c2,$d2,$t0,$t1,$t2,$t3) =
+ map("q$_",(0..15));
+
+sub NEONROUND {
+my $odd = pop;
+my ($a,$b,$c,$d,$t)=@_;
+
+ (
+ "&vadd_i32 ($a,$a,$b)",
+ "&veor ($d,$d,$a)",
+ "&vrev32_16 ($d,$d)", # vrot ($d,16)
+
+ "&vadd_i32 ($c,$c,$d)",
+ "&veor ($t,$b,$c)",
+ "&vshr_u32 ($b,$t,20)",
+ "&vsli_32 ($b,$t,12)",
+
+ "&vadd_i32 ($a,$a,$b)",
+ "&veor ($t,$d,$a)",
+ "&vshr_u32 ($d,$t,24)",
+ "&vsli_32 ($d,$t,8)",
+
+ "&vadd_i32 ($c,$c,$d)",
+ "&veor ($t,$b,$c)",
+ "&vshr_u32 ($b,$t,25)",
+ "&vsli_32 ($b,$t,7)",
+
+ "&vext_8 ($c,$c,$c,8)",
+ "&vext_8 ($b,$b,$b,$odd?12:4)",
+ "&vext_8 ($d,$d,$d,$odd?4:12)"
+ );
+}
+
+$code.=<<___;
+#if __ARM_MAX_ARCH__>=7
+.arch armv7-a
+.fpu neon
+
+.type ChaCha20_neon,%function
+.align 5
+ChaCha20_neon:
+ ldr r12,[sp,#0] @ pull pointer to counter and nonce
+ stmdb sp!,{r0-r2,r4-r11,lr}
+.LChaCha20_neon:
+ adr r14,.Lsigma
+ vstmdb sp!,{d8-d15} @ ABI spec says so
+ stmdb sp!,{r0-r3}
+
+ vld1.32 {$b0-$c0},[r3] @ load key
+ ldmia r3,{r4-r11} @ load key
+
+ sub sp,sp,#4*(16+16)
+ vld1.32 {$d0},[r12] @ load counter and nonce
+ add r12,sp,#4*8
+ ldmia r14,{r0-r3} @ load sigma
+ vld1.32 {$a0},[r14]! @ load sigma
+ vld1.32 {$t0},[r14] @ one
+ vst1.32 {$c0-$d0},[r12] @ copy 1/2key|counter|nonce
+ vst1.32 {$a0-$b0},[sp] @ copy sigma|1/2key
+
+ str r10,[sp,#4*(16+10)] @ off-load "@x[10]"
+ str r11,[sp,#4*(16+11)] @ off-load "@x[11]"
+ vshl.i32 $t1#lo,$t0#lo,#1 @ two
+ vstr $t0#lo,[sp,#4*(16+0)]
+ vshl.i32 $t2#lo,$t0#lo,#2 @ four
+ vstr $t1#lo,[sp,#4*(16+2)]
+ vmov $a1,$a0
+ vstr $t2#lo,[sp,#4*(16+4)]
+ vmov $a2,$a0
+ vmov $b1,$b0
+ vmov $b2,$b0
+ b .Loop_neon_enter
+
+.align 4
+.Loop_neon_outer:
+ ldmia sp,{r0-r9} @ load key material
+ cmp @t[3],#64*2 @ if len<=64*2
+ bls .Lbreak_neon @ switch to integer-only
+ vmov $a1,$a0
+ str @t[3],[sp,#4*(32+2)] @ save len
+ vmov $a2,$a0
+ str r12, [sp,#4*(32+1)] @ save inp
+ vmov $b1,$b0
+ str r14, [sp,#4*(32+0)] @ save out
+ vmov $b2,$b0
+.Loop_neon_enter:
+ ldr @t[3], [sp,#4*(15)]
+ vadd.i32 $d1,$d0,$t0 @ counter+1
+ ldr @x[12],[sp,#4*(12)] @ modulo-scheduled load
+ vmov $c1,$c0
+ ldr @t[2], [sp,#4*(13)]
+ vmov $c2,$c0
+ ldr @x[14],[sp,#4*(14)]
+ vadd.i32 $d2,$d1,$t0 @ counter+2
+ str @t[3], [sp,#4*(16+15)]
+ mov @t[3],#10
+ add @x[12],@x[12],#3 @ counter+3
+ b .Loop_neon
+
+.align 4
+.Loop_neon:
+ subs @t[3],@t[3],#1
+___
+ my @thread0=&NEONROUND($a0,$b0,$c0,$d0,$t0,0);
+ my @thread1=&NEONROUND($a1,$b1,$c1,$d1,$t1,0);
+ my @thread2=&NEONROUND($a2,$b2,$c2,$d2,$t2,0);
+ my @thread3=&ROUND(0,4,8,12);
+
+ foreach (@thread0) {
+ eval; eval(shift(@thread3));
+ eval(shift(@thread1)); eval(shift(@thread3));
+ eval(shift(@thread2)); eval(shift(@thread3));
+ }
+
+ @thread0=&NEONROUND($a0,$b0,$c0,$d0,$t0,1);
+ @thread1=&NEONROUND($a1,$b1,$c1,$d1,$t1,1);
+ @thread2=&NEONROUND($a2,$b2,$c2,$d2,$t2,1);
+ @thread3=&ROUND(0,5,10,15);
+
+ foreach (@thread0) {
+ eval; eval(shift(@thread3));
+ eval(shift(@thread1)); eval(shift(@thread3));
+ eval(shift(@thread2)); eval(shift(@thread3));
+ }
+$code.=<<___;
+ bne .Loop_neon
+
+ add @t[3],sp,#32
+ vld1.32 {$t0-$t1},[sp] @ load key material
+ vld1.32 {$t2-$t3},[@t[3]]
+
+ ldr @t[3],[sp,#4*(32+2)] @ load len
+
+ str @t[0], [sp,#4*(16+8)] @ modulo-scheduled store
+ str @t[1], [sp,#4*(16+9)]
+ str @x[12],[sp,#4*(16+12)]
+ str @t[2], [sp,#4*(16+13)]
+ str @x[14],[sp,#4*(16+14)]
+
+ @ at this point we have first half of 512-bit result in
+ @ @x[0-7] and second half at sp+4*(16+8)
+
+ ldr r12,[sp,#4*(32+1)] @ load inp
+ ldr r14,[sp,#4*(32+0)] @ load out
+
+ vadd.i32 $a0,$a0,$t0 @ accumulate key material
+ vadd.i32 $a1,$a1,$t0
+ vadd.i32 $a2,$a2,$t0
+ vldr $t0#lo,[sp,#4*(16+0)] @ one
+
+ vadd.i32 $b0,$b0,$t1
+ vadd.i32 $b1,$b1,$t1
+ vadd.i32 $b2,$b2,$t1
+ vldr $t1#lo,[sp,#4*(16+2)] @ two
+
+ vadd.i32 $c0,$c0,$t2
+ vadd.i32 $c1,$c1,$t2
+ vadd.i32 $c2,$c2,$t2
+ vadd.i32 $d1#lo,$d1#lo,$t0#lo @ counter+1
+ vadd.i32 $d2#lo,$d2#lo,$t1#lo @ counter+2
+
+ vadd.i32 $d0,$d0,$t3
+ vadd.i32 $d1,$d1,$t3
+ vadd.i32 $d2,$d2,$t3
+
+ cmp @t[3],#64*4
+ blo .Ltail_neon
+
+ vld1.8 {$t0-$t1},[r12]! @ load input
+ mov @t[3],sp
+ vld1.8 {$t2-$t3},[r12]!
+ veor $a0,$a0,$t0 @ xor with input
+ veor $b0,$b0,$t1
+ vld1.8 {$t0-$t1},[r12]!
+ veor $c0,$c0,$t2
+ veor $d0,$d0,$t3
+ vld1.8 {$t2-$t3},[r12]!
+
+ veor $a1,$a1,$t0
+ vst1.8 {$a0-$b0},[r14]! @ store output
+ veor $b1,$b1,$t1
+ vld1.8 {$t0-$t1},[r12]!
+ veor $c1,$c1,$t2
+ vst1.8 {$c0-$d0},[r14]!
+ veor $d1,$d1,$t3
+ vld1.8 {$t2-$t3},[r12]!
+
+ veor $a2,$a2,$t0
+ vld1.32 {$a0-$b0},[@t[3]]! @ load for next iteration
+ veor $t0#hi,$t0#hi,$t0#hi
+ vldr $t0#lo,[sp,#4*(16+4)] @ four
+ veor $b2,$b2,$t1
+ vld1.32 {$c0-$d0},[@t[3]]
+ veor $c2,$c2,$t2
+ vst1.8 {$a1-$b1},[r14]!
+ veor $d2,$d2,$t3
+ vst1.8 {$c1-$d1},[r14]!
+
+ vadd.i32 $d0#lo,$d0#lo,$t0#lo @ next counter value
+ vldr $t0#lo,[sp,#4*(16+0)] @ one
+
+ ldmia sp,{@t[0]-@t[3]} @ load key material
+ add @x[0],@x[0],@t[0] @ accumulate key material
+ ldr @t[0],[r12],#16 @ load input
+ vst1.8 {$a2-$b2},[r14]!
+ add @x[1],@x[1],@t[1]
+ ldr @t[1],[r12,#-12]
+ vst1.8 {$c2-$d2},[r14]!
+ add @x[2],@x[2],@t[2]
+ ldr @t[2],[r12,#-8]
+ add @x[3],@x[3],@t[3]
+ ldr @t[3],[r12,#-4]
+# ifdef __ARMEB__
+ rev @x[0],@x[0]
+ rev @x[1],@x[1]
+ rev @x[2],@x[2]
+ rev @x[3],@x[3]
+# endif
+ eor @x[0],@x[0],@t[0] @ xor with input
+ add @t[0],sp,#4*(4)
+ eor @x[1],@x[1],@t[1]
+ str @x[0],[r14],#16 @ store output
+ eor @x[2],@x[2],@t[2]
+ str @x[1],[r14,#-12]
+ eor @x[3],@x[3],@t[3]
+ ldmia @t[0],{@t[0]-@t[3]} @ load key material
+ str @x[2],[r14,#-8]
+ str @x[3],[r14,#-4]
+
+ add @x[4],@x[4],@t[0] @ accumulate key material
+ ldr @t[0],[r12],#16 @ load input
+ add @x[5],@x[5],@t[1]
+ ldr @t[1],[r12,#-12]
+ add @x[6],@x[6],@t[2]
+ ldr @t[2],[r12,#-8]
+ add @x[7],@x[7],@t[3]
+ ldr @t[3],[r12,#-4]
+# ifdef __ARMEB__
+ rev @x[4],@x[4]
+ rev @x[5],@x[5]
+ rev @x[6],@x[6]
+ rev @x[7],@x[7]
+# endif
+ eor @x[4],@x[4],@t[0]
+ add @t[0],sp,#4*(8)
+ eor @x[5],@x[5],@t[1]
+ str @x[4],[r14],#16 @ store output
+ eor @x[6],@x[6],@t[2]
+ str @x[5],[r14,#-12]
+ eor @x[7],@x[7],@t[3]
+ ldmia @t[0],{@t[0]-@t[3]} @ load key material
+ str @x[6],[r14,#-8]
+ add @x[0],sp,#4*(16+8)
+ str @x[7],[r14,#-4]
+
+ ldmia @x[0],{@x[0]-@x[7]} @ load second half
+
+ add @x[0],@x[0],@t[0] @ accumulate key material
+ ldr @t[0],[r12],#16 @ load input
+ add @x[1],@x[1],@t[1]
+ ldr @t[1],[r12,#-12]
+# ifdef __thumb2__
+ it hi
+# endif
+ strhi @t[2],[sp,#4*(16+10)] @ copy "@x[10]" while at it
+ add @x[2],@x[2],@t[2]
+ ldr @t[2],[r12,#-8]
+# ifdef __thumb2__
+ it hi
+# endif
+ strhi @t[3],[sp,#4*(16+11)] @ copy "@x[11]" while at it
+ add @x[3],@x[3],@t[3]
+ ldr @t[3],[r12,#-4]
+# ifdef __ARMEB__
+ rev @x[0],@x[0]
+ rev @x[1],@x[1]
+ rev @x[2],@x[2]
+ rev @x[3],@x[3]
+# endif
+ eor @x[0],@x[0],@t[0]
+ add @t[0],sp,#4*(12)
+ eor @x[1],@x[1],@t[1]
+ str @x[0],[r14],#16 @ store output
+ eor @x[2],@x[2],@t[2]
+ str @x[1],[r14,#-12]
+ eor @x[3],@x[3],@t[3]
+ ldmia @t[0],{@t[0]-@t[3]} @ load key material
+ str @x[2],[r14,#-8]
+ str @x[3],[r14,#-4]
+
+ add @x[4],@x[4],@t[0] @ accumulate key material
+ add @t[0],@t[0],#4 @ next counter value
+ add @x[5],@x[5],@t[1]
+ str @t[0],[sp,#4*(12)] @ save next counter value
+ ldr @t[0],[r12],#16 @ load input
+ add @x[6],@x[6],@t[2]
+ add @x[4],@x[4],#3 @ counter+3
+ ldr @t[1],[r12,#-12]
+ add @x[7],@x[7],@t[3]
+ ldr @t[2],[r12,#-8]
+ ldr @t[3],[r12,#-4]
+# ifdef __ARMEB__
+ rev @x[4],@x[4]
+ rev @x[5],@x[5]
+ rev @x[6],@x[6]
+ rev @x[7],@x[7]
+# endif
+ eor @x[4],@x[4],@t[0]
+# ifdef __thumb2__
+ it hi
+# endif
+ ldrhi @t[0],[sp,#4*(32+2)] @ re-load len
+ eor @x[5],@x[5],@t[1]
+ eor @x[6],@x[6],@t[2]
+ str @x[4],[r14],#16 @ store output
+ eor @x[7],@x[7],@t[3]
+ str @x[5],[r14,#-12]
+ sub @t[3],@t[0],#64*4 @ len-=64*4
+ str @x[6],[r14,#-8]
+ str @x[7],[r14,#-4]
+ bhi .Loop_neon_outer
+
+ b .Ldone_neon
+
+.align 4
+.Lbreak_neon:
+ @ harmonize NEON and integer-only stack frames: load data
+ @ from NEON frame, but save to integer-only one; distance
+ @ between the two is 4*(32+4+16-32)=4*(20).
+
+ str @t[3], [sp,#4*(20+32+2)] @ save len
+ add @t[3],sp,#4*(32+4)
+ str r12, [sp,#4*(20+32+1)] @ save inp
+ str r14, [sp,#4*(20+32+0)] @ save out
+
+ ldr @x[12],[sp,#4*(16+10)]
+ ldr @x[14],[sp,#4*(16+11)]
+ vldmia @t[3],{d8-d15} @ fulfill ABI requirement
+ str @x[12],[sp,#4*(20+16+10)] @ copy "@x[10]"
+ str @x[14],[sp,#4*(20+16+11)] @ copy "@x[11]"
+
+ ldr @t[3], [sp,#4*(15)]
+ ldr @x[12],[sp,#4*(12)] @ modulo-scheduled load
+ ldr @t[2], [sp,#4*(13)]
+ ldr @x[14],[sp,#4*(14)]
+ str @t[3], [sp,#4*(20+16+15)]
+ add @t[3],sp,#4*(20)
+ vst1.32 {$a0-$b0},[@t[3]]! @ copy key
+ add sp,sp,#4*(20) @ switch frame
+ vst1.32 {$c0-$d0},[@t[3]]
+ mov @t[3],#10
+ b .Loop @ go integer-only
+
+.align 4
+.Ltail_neon:
+ cmp @t[3],#64*3
+ bhs .L192_or_more_neon
+ cmp @t[3],#64*2
+ bhs .L128_or_more_neon
+ cmp @t[3],#64*1
+ bhs .L64_or_more_neon
+
+ add @t[0],sp,#4*(8)
+ vst1.8 {$a0-$b0},[sp]
+ add @t[2],sp,#4*(0)
+ vst1.8 {$c0-$d0},[@t[0]]
+ b .Loop_tail_neon
+
+.align 4
+.L64_or_more_neon:
+ vld1.8 {$t0-$t1},[r12]!
+ vld1.8 {$t2-$t3},[r12]!
+ veor $a0,$a0,$t0
+ veor $b0,$b0,$t1
+ veor $c0,$c0,$t2
+ veor $d0,$d0,$t3
+ vst1.8 {$a0-$b0},[r14]!
+ vst1.8 {$c0-$d0},[r14]!
+
+ beq .Ldone_neon
+
+ add @t[0],sp,#4*(8)
+ vst1.8 {$a1-$b1},[sp]
+ add @t[2],sp,#4*(0)
+ vst1.8 {$c1-$d1},[@t[0]]
+ sub @t[3],@t[3],#64*1 @ len-=64*1
+ b .Loop_tail_neon
+
+.align 4
+.L128_or_more_neon:
+ vld1.8 {$t0-$t1},[r12]!
+ vld1.8 {$t2-$t3},[r12]!
+ veor $a0,$a0,$t0
+ veor $b0,$b0,$t1
+ vld1.8 {$t0-$t1},[r12]!
+ veor $c0,$c0,$t2
+ veor $d0,$d0,$t3
+ vld1.8 {$t2-$t3},[r12]!
+
+ veor $a1,$a1,$t0
+ veor $b1,$b1,$t1
+ vst1.8 {$a0-$b0},[r14]!
+ veor $c1,$c1,$t2
+ vst1.8 {$c0-$d0},[r14]!
+ veor $d1,$d1,$t3
+ vst1.8 {$a1-$b1},[r14]!
+ vst1.8 {$c1-$d1},[r14]!
+
+ beq .Ldone_neon
+
+ add @t[0],sp,#4*(8)
+ vst1.8 {$a2-$b2},[sp]
+ add @t[2],sp,#4*(0)
+ vst1.8 {$c2-$d2},[@t[0]]
+ sub @t[3],@t[3],#64*2 @ len-=64*2
+ b .Loop_tail_neon
+
+.align 4
+.L192_or_more_neon:
+ vld1.8 {$t0-$t1},[r12]!
+ vld1.8 {$t2-$t3},[r12]!
+ veor $a0,$a0,$t0
+ veor $b0,$b0,$t1
+ vld1.8 {$t0-$t1},[r12]!
+ veor $c0,$c0,$t2
+ veor $d0,$d0,$t3
+ vld1.8 {$t2-$t3},[r12]!
+
+ veor $a1,$a1,$t0
+ veor $b1,$b1,$t1
+ vld1.8 {$t0-$t1},[r12]!
+ veor $c1,$c1,$t2
+ vst1.8 {$a0-$b0},[r14]!
+ veor $d1,$d1,$t3
+ vld1.8 {$t2-$t3},[r12]!
+
+ veor $a2,$a2,$t0
+ vst1.8 {$c0-$d0},[r14]!
+ veor $b2,$b2,$t1
+ vst1.8 {$a1-$b1},[r14]!
+ veor $c2,$c2,$t2
+ vst1.8 {$c1-$d1},[r14]!
+ veor $d2,$d2,$t3
+ vst1.8 {$a2-$b2},[r14]!
+ vst1.8 {$c2-$d2},[r14]!
+
+ beq .Ldone_neon
+
+ ldmia sp,{@t[0]-@t[3]} @ load key material
+ add @x[0],@x[0],@t[0] @ accumulate key material
+ add @t[0],sp,#4*(4)
+ add @x[1],@x[1],@t[1]
+ add @x[2],@x[2],@t[2]
+ add @x[3],@x[3],@t[3]
+ ldmia @t[0],{@t[0]-@t[3]} @ load key material
+
+ add @x[4],@x[4],@t[0] @ accumulate key material
+ add @t[0],sp,#4*(8)
+ add @x[5],@x[5],@t[1]
+ add @x[6],@x[6],@t[2]
+ add @x[7],@x[7],@t[3]
+ ldmia @t[0],{@t[0]-@t[3]} @ load key material
+# ifdef __ARMEB__
+ rev @x[0],@x[0]
+ rev @x[1],@x[1]
+ rev @x[2],@x[2]
+ rev @x[3],@x[3]
+ rev @x[4],@x[4]
+ rev @x[5],@x[5]
+ rev @x[6],@x[6]
+ rev @x[7],@x[7]
+# endif
+ stmia sp,{@x[0]-@x[7]}
+ add @x[0],sp,#4*(16+8)
+
+ ldmia @x[0],{@x[0]-@x[7]} @ load second half
+
+ add @x[0],@x[0],@t[0] @ accumulate key material
+ add @t[0],sp,#4*(12)
+ add @x[1],@x[1],@t[1]
+ add @x[2],@x[2],@t[2]
+ add @x[3],@x[3],@t[3]
+ ldmia @t[0],{@t[0]-@t[3]} @ load key material
+
+ add @x[4],@x[4],@t[0] @ accumulate key material
+ add @t[0],sp,#4*(8)
+ add @x[5],@x[5],@t[1]
+ add @x[4],@x[4],#3 @ counter+3
+ add @x[6],@x[6],@t[2]
+ add @x[7],@x[7],@t[3]
+ ldr @t[3],[sp,#4*(32+2)] @ re-load len
+# ifdef __ARMEB__
+ rev @x[0],@x[0]
+ rev @x[1],@x[1]
+ rev @x[2],@x[2]
+ rev @x[3],@x[3]
+ rev @x[4],@x[4]
+ rev @x[5],@x[5]
+ rev @x[6],@x[6]
+ rev @x[7],@x[7]
+# endif
+ stmia @t[0],{@x[0]-@x[7]}
+ add @t[2],sp,#4*(0)
+ sub @t[3],@t[3],#64*3 @ len-=64*3
+
+.Loop_tail_neon:
+ ldrb @t[0],[@t[2]],#1 @ read buffer on stack
+ ldrb @t[1],[r12],#1 @ read input
+ subs @t[3],@t[3],#1
+ eor @t[0],@t[0],@t[1]
+ strb @t[0],[r14],#1 @ store ouput
+ bne .Loop_tail_neon
+
+.Ldone_neon:
+ add sp,sp,#4*(32+4)
+ vldmia sp,{d8-d15}
+ add sp,sp,#4*(16+3)
+ ldmia sp!,{r4-r11,pc}
+.size ChaCha20_neon,.-ChaCha20_neon
+.comm OPENSSL_armcap_P,4,4
+#endif
+___
+}}}
+
+foreach (split("\n",$code)) {
+ s/\`([^\`]*)\`/eval $1/geo;
+
+ s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo;
+
+ print $_,"\n";
+}
+close STDOUT;
diff --git a/crypto/chacha/asm/chacha-armv8.pl b/crypto/chacha/asm/chacha-armv8.pl
new file mode 100755
index 00000000..215d9657
--- /dev/null
+++ b/crypto/chacha/asm/chacha-armv8.pl
@@ -0,0 +1,1127 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# June 2015
+#
+# ChaCha20 for ARMv8.
+#
+# Performance in cycles per byte out of large buffer.
+#
+# IALU/gcc-4.9 3xNEON+1xIALU 6xNEON+2xIALU
+#
+# Apple A7 5.50/+49% 3.33 1.70
+# Cortex-A53 8.40/+80% 4.72 4.72(*)
+# Cortex-A57 8.06/+43% 4.90 4.43(**)
+# Denver 4.50/+82% 2.63 2.67(*)
+# X-Gene 9.50/+46% 8.82 8.89(*)
+#
+# (*) it's expected that doubling interleave factor doesn't help
+# all processors, only those with higher NEON latency and
+# higher instruction issue rate;
+# (**) expected improvement was actually higher;
+
+$flavour=shift;
+$output=shift;
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
+( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
+die "can't locate arm-xlate.pl";
+
+open OUT,"| \"$^X\" $xlate $flavour $output";
+*STDOUT=*OUT;
+
+sub AUTOLOAD() # thunk [simplified] x86-style perlasm
+{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
+ my $arg = pop;
+ $arg = "#$arg" if ($arg*1 eq $arg);
+ $code .= "\t$opcode\t".join(',',@_,$arg)."\n";
+}
+
+my ($out,$inp,$len,$key,$ctr) = map("x$_",(0..4));
+
+my @x=map("x$_",(5..17,19..21));
+my @d=map("x$_",(22..28,30));
+
+sub ROUND {
+my ($a0,$b0,$c0,$d0)=@_;
+my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
+my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
+my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
+
+ (
+ "&add_32 (@x[$a0],@x[$a0],@x[$b0])",
+ "&add_32 (@x[$a1],@x[$a1],@x[$b1])",
+ "&add_32 (@x[$a2],@x[$a2],@x[$b2])",
+ "&add_32 (@x[$a3],@x[$a3],@x[$b3])",
+ "&eor_32 (@x[$d0],@x[$d0],@x[$a0])",
+ "&eor_32 (@x[$d1],@x[$d1],@x[$a1])",
+ "&eor_32 (@x[$d2],@x[$d2],@x[$a2])",
+ "&eor_32 (@x[$d3],@x[$d3],@x[$a3])",
+ "&ror_32 (@x[$d0],@x[$d0],16)",
+ "&ror_32 (@x[$d1],@x[$d1],16)",
+ "&ror_32 (@x[$d2],@x[$d2],16)",
+ "&ror_32 (@x[$d3],@x[$d3],16)",
+
+ "&add_32 (@x[$c0],@x[$c0],@x[$d0])",
+ "&add_32 (@x[$c1],@x[$c1],@x[$d1])",
+ "&add_32 (@x[$c2],@x[$c2],@x[$d2])",
+ "&add_32 (@x[$c3],@x[$c3],@x[$d3])",
+ "&eor_32 (@x[$b0],@x[$b0],@x[$c0])",
+ "&eor_32 (@x[$b1],@x[$b1],@x[$c1])",
+ "&eor_32 (@x[$b2],@x[$b2],@x[$c2])",
+ "&eor_32 (@x[$b3],@x[$b3],@x[$c3])",
+ "&ror_32 (@x[$b0],@x[$b0],20)",
+ "&ror_32 (@x[$b1],@x[$b1],20)",
+ "&ror_32 (@x[$b2],@x[$b2],20)",
+ "&ror_32 (@x[$b3],@x[$b3],20)",
+
+ "&add_32 (@x[$a0],@x[$a0],@x[$b0])",
+ "&add_32 (@x[$a1],@x[$a1],@x[$b1])",
+ "&add_32 (@x[$a2],@x[$a2],@x[$b2])",
+ "&add_32 (@x[$a3],@x[$a3],@x[$b3])",
+ "&eor_32 (@x[$d0],@x[$d0],@x[$a0])",
+ "&eor_32 (@x[$d1],@x[$d1],@x[$a1])",
+ "&eor_32 (@x[$d2],@x[$d2],@x[$a2])",
+ "&eor_32 (@x[$d3],@x[$d3],@x[$a3])",
+ "&ror_32 (@x[$d0],@x[$d0],24)",
+ "&ror_32 (@x[$d1],@x[$d1],24)",
+ "&ror_32 (@x[$d2],@x[$d2],24)",
+ "&ror_32 (@x[$d3],@x[$d3],24)",
+
+ "&add_32 (@x[$c0],@x[$c0],@x[$d0])",
+ "&add_32 (@x[$c1],@x[$c1],@x[$d1])",
+ "&add_32 (@x[$c2],@x[$c2],@x[$d2])",
+ "&add_32 (@x[$c3],@x[$c3],@x[$d3])",
+ "&eor_32 (@x[$b0],@x[$b0],@x[$c0])",
+ "&eor_32 (@x[$b1],@x[$b1],@x[$c1])",
+ "&eor_32 (@x[$b2],@x[$b2],@x[$c2])",
+ "&eor_32 (@x[$b3],@x[$b3],@x[$c3])",
+ "&ror_32 (@x[$b0],@x[$b0],25)",
+ "&ror_32 (@x[$b1],@x[$b1],25)",
+ "&ror_32 (@x[$b2],@x[$b2],25)",
+ "&ror_32 (@x[$b3],@x[$b3],25)"
+ );
+}
+
+$code.=<<___;
+#include <openssl/arm_arch.h>
+
+.text
+
+.extern OPENSSL_armcap_P
+
+.align 5
+.Lsigma:
+.quad 0x3320646e61707865,0x6b20657479622d32 // endian-neutral
+.Lone:
+.long 1,0,0,0
+.LOPENSSL_armcap_P:
+#ifdef __ILP32__
+.long OPENSSL_armcap_P-.
+#else
+.quad OPENSSL_armcap_P-.
+#endif
+.asciz "ChaCha20 for ARMv8, CRYPTOGAMS by <appro\@openssl.org>"
+
+.globl ChaCha20_ctr32
+.type ChaCha20_ctr32,%function
+.align 5
+ChaCha20_ctr32:
+ cbz $len,.Labort
+ adr @x[0],.LOPENSSL_armcap_P
+ cmp $len,#192
+ b.lo .Lshort
+#ifdef __ILP32__
+ ldrsw @x[1],[@x[0]]
+#else
+ ldr @x[1],[@x[0]]
+#endif
+ ldr w17,[@x[1],@x[0]]
+ tst w17,#ARMV7_NEON
+ b.ne ChaCha20_neon
+
+.Lshort:
+ stp x29,x30,[sp,#-96]!
+ add x29,sp,#0
+
+ adr @x[0],.Lsigma
+ stp x19,x20,[sp,#16]
+ stp x21,x22,[sp,#32]
+ stp x23,x24,[sp,#48]
+ stp x25,x26,[sp,#64]
+ stp x27,x28,[sp,#80]
+ sub sp,sp,#64
+
+ ldp @d[0],@d[1],[@x[0]] // load sigma
+ ldp @d[2],@d[3],[$key] // load key
+ ldp @d[4],@d[5],[$key,#16]
+ ldp @d[6],@d[7],[$ctr] // load counter
+#ifdef __ARMEB__
+ ror @d[2],@d[2],#32
+ ror @d[3],@d[3],#32
+ ror @d[4],@d[4],#32
+ ror @d[5],@d[5],#32
+ ror @d[6],@d[6],#32
+ ror @d[7],@d[7],#32
+#endif
+
+.Loop_outer:
+ mov.32 @x[0],@d[0] // unpack key block
+ lsr @x[1],@d[0],#32
+ mov.32 @x[2],@d[1]
+ lsr @x[3],@d[1],#32
+ mov.32 @x[4],@d[2]
+ lsr @x[5],@d[2],#32
+ mov.32 @x[6],@d[3]
+ lsr @x[7],@d[3],#32
+ mov.32 @x[8],@d[4]
+ lsr @x[9],@d[4],#32
+ mov.32 @x[10],@d[5]
+ lsr @x[11],@d[5],#32
+ mov.32 @x[12],@d[6]
+ lsr @x[13],@d[6],#32
+ mov.32 @x[14],@d[7]
+ lsr @x[15],@d[7],#32
+
+ mov $ctr,#10
+ subs $len,$len,#64
+.Loop:
+ sub $ctr,$ctr,#1
+___
+ foreach (&ROUND(0, 4, 8,12)) { eval; }
+ foreach (&ROUND(0, 5,10,15)) { eval; }
+$code.=<<___;
+ cbnz $ctr,.Loop
+
+ add.32 @x[0],@x[0],@d[0] // accumulate key block
+ add @x[1],@x[1],@d[0],lsr#32
+ add.32 @x[2],@x[2],@d[1]
+ add @x[3],@x[3],@d[1],lsr#32
+ add.32 @x[4],@x[4],@d[2]
+ add @x[5],@x[5],@d[2],lsr#32
+ add.32 @x[6],@x[6],@d[3]
+ add @x[7],@x[7],@d[3],lsr#32
+ add.32 @x[8],@x[8],@d[4]
+ add @x[9],@x[9],@d[4],lsr#32
+ add.32 @x[10],@x[10],@d[5]
+ add @x[11],@x[11],@d[5],lsr#32
+ add.32 @x[12],@x[12],@d[6]
+ add @x[13],@x[13],@d[6],lsr#32
+ add.32 @x[14],@x[14],@d[7]
+ add @x[15],@x[15],@d[7],lsr#32
+
+ b.lo .Ltail
+
+ add @x[0],@x[0],@x[1],lsl#32 // pack
+ add @x[2],@x[2],@x[3],lsl#32
+ ldp @x[1],@x[3],[$inp,#0] // load input
+ add @x[4],@x[4],@x[5],lsl#32
+ add @x[6],@x[6],@x[7],lsl#32
+ ldp @x[5],@x[7],[$inp,#16]
+ add @x[8],@x[8],@x[9],lsl#32
+ add @x[10],@x[10],@x[11],lsl#32
+ ldp @x[9],@x[11],[$inp,#32]
+ add @x[12],@x[12],@x[13],lsl#32
+ add @x[14],@x[14],@x[15],lsl#32
+ ldp @x[13],@x[15],[$inp,#48]
+ add $inp,$inp,#64
+#ifdef __ARMEB__
+ rev @x[0],@x[0]
+ rev @x[2],@x[2]
+ rev @x[4],@x[4]
+ rev @x[6],@x[6]
+ rev @x[8],@x[8]
+ rev @x[10],@x[10]
+ rev @x[12],@x[12]
+ rev @x[14],@x[14]
+#endif
+ eor @x[0],@x[0],@x[1]
+ eor @x[2],@x[2],@x[3]
+ eor @x[4],@x[4],@x[5]
+ eor @x[6],@x[6],@x[7]
+ eor @x[8],@x[8],@x[9]
+ eor @x[10],@x[10],@x[11]
+ eor @x[12],@x[12],@x[13]
+ eor @x[14],@x[14],@x[15]
+
+ stp @x[0],@x[2],[$out,#0] // store output
+ add @d[6],@d[6],#1 // increment counter
+ stp @x[4],@x[6],[$out,#16]
+ stp @x[8],@x[10],[$out,#32]
+ stp @x[12],@x[14],[$out,#48]
+ add $out,$out,#64
+
+ b.hi .Loop_outer
+
+ ldp x19,x20,[x29,#16]
+ add sp,sp,#64
+ ldp x21,x22,[x29,#32]
+ ldp x23,x24,[x29,#48]
+ ldp x25,x26,[x29,#64]
+ ldp x27,x28,[x29,#80]
+ ldp x29,x30,[sp],#96
+.Labort:
+ ret
+
+.align 4
+.Ltail:
+ add $len,$len,#64
+.Less_than_64:
+ sub $out,$out,#1
+ add $inp,$inp,$len
+ add $out,$out,$len
+ add $ctr,sp,$len
+ neg $len,$len
+
+ add @x[0],@x[0],@x[1],lsl#32 // pack
+ add @x[2],@x[2],@x[3],lsl#32
+ add @x[4],@x[4],@x[5],lsl#32
+ add @x[6],@x[6],@x[7],lsl#32
+ add @x[8],@x[8],@x[9],lsl#32
+ add @x[10],@x[10],@x[11],lsl#32
+ add @x[12],@x[12],@x[13],lsl#32
+ add @x[14],@x[14],@x[15],lsl#32
+#ifdef __ARMEB__
+ rev @x[0],@x[0]
+ rev @x[2],@x[2]
+ rev @x[4],@x[4]
+ rev @x[6],@x[6]
+ rev @x[8],@x[8]
+ rev @x[10],@x[10]
+ rev @x[12],@x[12]
+ rev @x[14],@x[14]
+#endif
+ stp @x[0],@x[2],[sp,#0]
+ stp @x[4],@x[6],[sp,#16]
+ stp @x[8],@x[10],[sp,#32]
+ stp @x[12],@x[14],[sp,#48]
+
+.Loop_tail:
+ ldrb w10,[$inp,$len]
+ ldrb w11,[$ctr,$len]
+ add $len,$len,#1
+ eor w10,w10,w11
+ strb w10,[$out,$len]
+ cbnz $len,.Loop_tail
+
+ stp xzr,xzr,[sp,#0]
+ stp xzr,xzr,[sp,#16]
+ stp xzr,xzr,[sp,#32]
+ stp xzr,xzr,[sp,#48]
+
+ ldp x19,x20,[x29,#16]
+ add sp,sp,#64
+ ldp x21,x22,[x29,#32]
+ ldp x23,x24,[x29,#48]
+ ldp x25,x26,[x29,#64]
+ ldp x27,x28,[x29,#80]
+ ldp x29,x30,[sp],#96
+ ret
+.size ChaCha20_ctr32,.-ChaCha20_ctr32
+___
+
+{{{
+my ($A0,$B0,$C0,$D0,$A1,$B1,$C1,$D1,$A2,$B2,$C2,$D2,$T0,$T1,$T2,$T3) =
+ map("v$_.4s",(0..7,16..23));
+my (@K)=map("v$_.4s",(24..30));
+my $ONE="v31.4s";
+
+sub NEONROUND {
+my $odd = pop;
+my ($a,$b,$c,$d,$t)=@_;
+
+ (
+ "&add ('$a','$a','$b')",
+ "&eor ('$d','$d','$a')",
+ "&rev32_16 ('$d','$d')", # vrot ($d,16)
+
+ "&add ('$c','$c','$d')",
+ "&eor ('$t','$b','$c')",
+ "&ushr ('$b','$t',20)",
+ "&sli ('$b','$t',12)",
+
+ "&add ('$a','$a','$b')",
+ "&eor ('$t','$d','$a')",
+ "&ushr ('$d','$t',24)",
+ "&sli ('$d','$t',8)",
+
+ "&add ('$c','$c','$d')",
+ "&eor ('$t','$b','$c')",
+ "&ushr ('$b','$t',25)",
+ "&sli ('$b','$t',7)",
+
+ "&ext ('$c','$c','$c',8)",
+ "&ext ('$d','$d','$d',$odd?4:12)",
+ "&ext ('$b','$b','$b',$odd?12:4)"
+ );
+}
+
+$code.=<<___;
+
+.type ChaCha20_neon,%function
+.align 5
+ChaCha20_neon:
+ stp x29,x30,[sp,#-96]!
+ add x29,sp,#0
+
+ adr @x[0],.Lsigma
+ stp x19,x20,[sp,#16]
+ stp x21,x22,[sp,#32]
+ stp x23,x24,[sp,#48]
+ stp x25,x26,[sp,#64]
+ stp x27,x28,[sp,#80]
+ cmp $len,#512
+ b.hs .L512_or_more_neon
+
+ sub sp,sp,#64
+
+ ldp @d[0],@d[1],[@x[0]] // load sigma
+ ld1 {@K[0]},[@x[0]],#16
+ ldp @d[2],@d[3],[$key] // load key
+ ldp @d[4],@d[5],[$key,#16]
+ ld1 {@K[1],@K[2]},[$key]
+ ldp @d[6],@d[7],[$ctr] // load counter
+ ld1 {@K[3]},[$ctr]
+ ld1 {$ONE},[@x[0]]
+#ifdef __ARMEB__
+ rev64 @K[0],@K[0]
+ ror @d[2],@d[2],#32
+ ror @d[3],@d[3],#32
+ ror @d[4],@d[4],#32
+ ror @d[5],@d[5],#32
+ ror @d[6],@d[6],#32
+ ror @d[7],@d[7],#32
+#endif
+ add @K[3],@K[3],$ONE // += 1
+ add @K[4],@K[3],$ONE
+ add @K[5],@K[4],$ONE
+ shl $ONE,$ONE,#2 // 1 -> 4
+
+.Loop_outer_neon:
+ mov.32 @x[0],@d[0] // unpack key block
+ lsr @x[1],@d[0],#32
+ mov $A0,@K[0]
+ mov.32 @x[2],@d[1]
+ lsr @x[3],@d[1],#32
+ mov $A1,@K[0]
+ mov.32 @x[4],@d[2]
+ lsr @x[5],@d[2],#32
+ mov $A2,@K[0]
+ mov.32 @x[6],@d[3]
+ mov $B0,@K[1]
+ lsr @x[7],@d[3],#32
+ mov $B1,@K[1]
+ mov.32 @x[8],@d[4]
+ mov $B2,@K[1]
+ lsr @x[9],@d[4],#32
+ mov $D0,@K[3]
+ mov.32 @x[10],@d[5]
+ mov $D1,@K[4]
+ lsr @x[11],@d[5],#32
+ mov $D2,@K[5]
+ mov.32 @x[12],@d[6]
+ mov $C0,@K[2]
+ lsr @x[13],@d[6],#32
+ mov $C1,@K[2]
+ mov.32 @x[14],@d[7]
+ mov $C2,@K[2]
+ lsr @x[15],@d[7],#32
+
+ mov $ctr,#10
+ subs $len,$len,#256
+.Loop_neon:
+ sub $ctr,$ctr,#1
+___
+ my @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0);
+ my @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0);
+ my @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0);
+ my @thread3=&ROUND(0,4,8,12);
+
+ foreach (@thread0) {
+ eval; eval(shift(@thread3));
+ eval(shift(@thread1)); eval(shift(@thread3));
+ eval(shift(@thread2)); eval(shift(@thread3));
+ }
+
+ @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1);
+ @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1);
+ @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1);
+ @thread3=&ROUND(0,5,10,15);
+
+ foreach (@thread0) {
+ eval; eval(shift(@thread3));
+ eval(shift(@thread1)); eval(shift(@thread3));
+ eval(shift(@thread2)); eval(shift(@thread3));
+ }
+$code.=<<___;
+ cbnz $ctr,.Loop_neon
+
+ add.32 @x[0],@x[0],@d[0] // accumulate key block
+ add $A0,$A0,@K[0]
+ add @x[1],@x[1],@d[0],lsr#32
+ add $A1,$A1,@K[0]
+ add.32 @x[2],@x[2],@d[1]
+ add $A2,$A2,@K[0]
+ add @x[3],@x[3],@d[1],lsr#32
+ add $C0,$C0,@K[2]
+ add.32 @x[4],@x[4],@d[2]
+ add $C1,$C1,@K[2]
+ add @x[5],@x[5],@d[2],lsr#32
+ add $C2,$C2,@K[2]
+ add.32 @x[6],@x[6],@d[3]
+ add $D0,$D0,@K[3]
+ add @x[7],@x[7],@d[3],lsr#32
+ add.32 @x[8],@x[8],@d[4]
+ add $D1,$D1,@K[4]
+ add @x[9],@x[9],@d[4],lsr#32
+ add.32 @x[10],@x[10],@d[5]
+ add $D2,$D2,@K[5]
+ add @x[11],@x[11],@d[5],lsr#32
+ add.32 @x[12],@x[12],@d[6]
+ add $B0,$B0,@K[1]
+ add @x[13],@x[13],@d[6],lsr#32
+ add.32 @x[14],@x[14],@d[7]
+ add $B1,$B1,@K[1]
+ add @x[15],@x[15],@d[7],lsr#32
+ add $B2,$B2,@K[1]
+
+ b.lo .Ltail_neon
+
+ add @x[0],@x[0],@x[1],lsl#32 // pack
+ add @x[2],@x[2],@x[3],lsl#32
+ ldp @x[1],@x[3],[$inp,#0] // load input
+ add @x[4],@x[4],@x[5],lsl#32
+ add @x[6],@x[6],@x[7],lsl#32
+ ldp @x[5],@x[7],[$inp,#16]
+ add @x[8],@x[8],@x[9],lsl#32
+ add @x[10],@x[10],@x[11],lsl#32
+ ldp @x[9],@x[11],[$inp,#32]
+ add @x[12],@x[12],@x[13],lsl#32
+ add @x[14],@x[14],@x[15],lsl#32
+ ldp @x[13],@x[15],[$inp,#48]
+ add $inp,$inp,#64
+#ifdef __ARMEB__
+ rev @x[0],@x[0]
+ rev @x[2],@x[2]
+ rev @x[4],@x[4]
+ rev @x[6],@x[6]
+ rev @x[8],@x[8]
+ rev @x[10],@x[10]
+ rev @x[12],@x[12]
+ rev @x[14],@x[14]
+#endif
+ ld1.8 {$T0-$T3},[$inp],#64
+ eor @x[0],@x[0],@x[1]
+ eor @x[2],@x[2],@x[3]
+ eor @x[4],@x[4],@x[5]
+ eor @x[6],@x[6],@x[7]
+ eor @x[8],@x[8],@x[9]
+ eor $A0,$A0,$T0
+ eor @x[10],@x[10],@x[11]
+ eor $B0,$B0,$T1
+ eor @x[12],@x[12],@x[13]
+ eor $C0,$C0,$T2
+ eor @x[14],@x[14],@x[15]
+ eor $D0,$D0,$T3
+ ld1.8 {$T0-$T3},[$inp],#64
+
+ stp @x[0],@x[2],[$out,#0] // store output
+ add @d[6],@d[6],#4 // increment counter
+ stp @x[4],@x[6],[$out,#16]
+ add @K[3],@K[3],$ONE // += 4
+ stp @x[8],@x[10],[$out,#32]
+ add @K[4],@K[4],$ONE
+ stp @x[12],@x[14],[$out,#48]
+ add @K[5],@K[5],$ONE
+ add $out,$out,#64
+
+ st1.8 {$A0-$D0},[$out],#64
+ ld1.8 {$A0-$D0},[$inp],#64
+
+ eor $A1,$A1,$T0
+ eor $B1,$B1,$T1
+ eor $C1,$C1,$T2
+ eor $D1,$D1,$T3
+ st1.8 {$A1-$D1},[$out],#64
+
+ eor $A2,$A2,$A0
+ eor $B2,$B2,$B0
+ eor $C2,$C2,$C0
+ eor $D2,$D2,$D0
+ st1.8 {$A2-$D2},[$out],#64
+
+ b.hi .Loop_outer_neon
+
+ ldp x19,x20,[x29,#16]
+ add sp,sp,#64
+ ldp x21,x22,[x29,#32]
+ ldp x23,x24,[x29,#48]
+ ldp x25,x26,[x29,#64]
+ ldp x27,x28,[x29,#80]
+ ldp x29,x30,[sp],#96
+ ret
+
+.Ltail_neon:
+ add $len,$len,#256
+ cmp $len,#64
+ b.lo .Less_than_64
+
+ add @x[0],@x[0],@x[1],lsl#32 // pack
+ add @x[2],@x[2],@x[3],lsl#32
+ ldp @x[1],@x[3],[$inp,#0] // load input
+ add @x[4],@x[4],@x[5],lsl#32
+ add @x[6],@x[6],@x[7],lsl#32
+ ldp @x[5],@x[7],[$inp,#16]
+ add @x[8],@x[8],@x[9],lsl#32
+ add @x[10],@x[10],@x[11],lsl#32
+ ldp @x[9],@x[11],[$inp,#32]
+ add @x[12],@x[12],@x[13],lsl#32
+ add @x[14],@x[14],@x[15],lsl#32
+ ldp @x[13],@x[15],[$inp,#48]
+ add $inp,$inp,#64
+#ifdef __ARMEB__
+ rev @x[0],@x[0]
+ rev @x[2],@x[2]
+ rev @x[4],@x[4]
+ rev @x[6],@x[6]
+ rev @x[8],@x[8]
+ rev @x[10],@x[10]
+ rev @x[12],@x[12]
+ rev @x[14],@x[14]
+#endif
+ eor @x[0],@x[0],@x[1]
+ eor @x[2],@x[2],@x[3]
+ eor @x[4],@x[4],@x[5]
+ eor @x[6],@x[6],@x[7]
+ eor @x[8],@x[8],@x[9]
+ eor @x[10],@x[10],@x[11]
+ eor @x[12],@x[12],@x[13]
+ eor @x[14],@x[14],@x[15]
+
+ stp @x[0],@x[2],[$out,#0] // store output
+ add @d[6],@d[6],#4 // increment counter
+ stp @x[4],@x[6],[$out,#16]
+ stp @x[8],@x[10],[$out,#32]
+ stp @x[12],@x[14],[$out,#48]
+ add $out,$out,#64
+ b.eq .Ldone_neon
+ sub $len,$len,#64
+ cmp $len,#64
+ b.lo .Less_than_128
+
+ ld1.8 {$T0-$T3},[$inp],#64
+ eor $A0,$A0,$T0
+ eor $B0,$B0,$T1
+ eor $C0,$C0,$T2
+ eor $D0,$D0,$T3
+ st1.8 {$A0-$D0},[$out],#64
+ b.eq .Ldone_neon
+ sub $len,$len,#64
+ cmp $len,#64
+ b.lo .Less_than_192
+
+ ld1.8 {$T0-$T3},[$inp],#64
+ eor $A1,$A1,$T0
+ eor $B1,$B1,$T1
+ eor $C1,$C1,$T2
+ eor $D1,$D1,$T3
+ st1.8 {$A1-$D1},[$out],#64
+ b.eq .Ldone_neon
+ sub $len,$len,#64
+
+ st1.8 {$A2-$D2},[sp]
+ b .Last_neon
+
+.Less_than_128:
+ st1.8 {$A0-$D0},[sp]
+ b .Last_neon
+.Less_than_192:
+ st1.8 {$A1-$D1},[sp]
+ b .Last_neon
+
+.align 4
+.Last_neon:
+ sub $out,$out,#1
+ add $inp,$inp,$len
+ add $out,$out,$len
+ add $ctr,sp,$len
+ neg $len,$len
+
+.Loop_tail_neon:
+ ldrb w10,[$inp,$len]
+ ldrb w11,[$ctr,$len]
+ add $len,$len,#1
+ eor w10,w10,w11
+ strb w10,[$out,$len]
+ cbnz $len,.Loop_tail_neon
+
+ stp xzr,xzr,[sp,#0]
+ stp xzr,xzr,[sp,#16]
+ stp xzr,xzr,[sp,#32]
+ stp xzr,xzr,[sp,#48]
+
+.Ldone_neon:
+ ldp x19,x20,[x29,#16]
+ add sp,sp,#64
+ ldp x21,x22,[x29,#32]
+ ldp x23,x24,[x29,#48]
+ ldp x25,x26,[x29,#64]
+ ldp x27,x28,[x29,#80]
+ ldp x29,x30,[sp],#96
+ ret
+.size ChaCha20_neon,.-ChaCha20_neon
+___
+{
+my ($T0,$T1,$T2,$T3,$T4,$T5)=@K;
+my ($A0,$B0,$C0,$D0,$A1,$B1,$C1,$D1,$A2,$B2,$C2,$D2,
+ $A3,$B3,$C3,$D3,$A4,$B4,$C4,$D4,$A5,$B5,$C5,$D5) = map("v$_.4s",(0..23));
+
+$code.=<<___;
+.type ChaCha20_512_neon,%function
+.align 5
+ChaCha20_512_neon:
+ stp x29,x30,[sp,#-96]!
+ add x29,sp,#0
+
+ adr @x[0],.Lsigma
+ stp x19,x20,[sp,#16]
+ stp x21,x22,[sp,#32]
+ stp x23,x24,[sp,#48]
+ stp x25,x26,[sp,#64]
+ stp x27,x28,[sp,#80]
+
+.L512_or_more_neon:
+ sub sp,sp,#128+64
+
+ ldp @d[0],@d[1],[@x[0]] // load sigma
+ ld1 {@K[0]},[@x[0]],#16
+ ldp @d[2],@d[3],[$key] // load key
+ ldp @d[4],@d[5],[$key,#16]
+ ld1 {@K[1],@K[2]},[$key]
+ ldp @d[6],@d[7],[$ctr] // load counter
+ ld1 {@K[3]},[$ctr]
+ ld1 {$ONE},[@x[0]]
+#ifdef __ARMEB__
+ rev64 @K[0],@K[0]
+ ror @d[2],@d[2],#32
+ ror @d[3],@d[3],#32
+ ror @d[4],@d[4],#32
+ ror @d[5],@d[5],#32
+ ror @d[6],@d[6],#32
+ ror @d[7],@d[7],#32
+#endif
+ add @K[3],@K[3],$ONE // += 1
+ stp @K[0],@K[1],[sp,#0] // off-load key block, invariant part
+ add @K[3],@K[3],$ONE // not typo
+ str @K[2],[sp,#32]
+ add @K[4],@K[3],$ONE
+ add @K[5],@K[4],$ONE
+ add @K[6],@K[5],$ONE
+ shl $ONE,$ONE,#2 // 1 -> 4
+
+ stp d8,d9,[sp,#128+0] // meet ABI requirements
+ stp d10,d11,[sp,#128+16]
+ stp d12,d13,[sp,#128+32]
+ stp d14,d15,[sp,#128+48]
+
+ sub $len,$len,#512 // not typo
+
+.Loop_outer_512_neon:
+ mov $A0,@K[0]
+ mov $A1,@K[0]
+ mov $A2,@K[0]
+ mov $A3,@K[0]
+ mov $A4,@K[0]
+ mov $A5,@K[0]
+ mov $B0,@K[1]
+ mov.32 @x[0],@d[0] // unpack key block
+ mov $B1,@K[1]
+ lsr @x[1],@d[0],#32
+ mov $B2,@K[1]
+ mov.32 @x[2],@d[1]
+ mov $B3,@K[1]
+ lsr @x[3],@d[1],#32
+ mov $B4,@K[1]
+ mov.32 @x[4],@d[2]
+ mov $B5,@K[1]
+ lsr @x[5],@d[2],#32
+ mov $D0,@K[3]
+ mov.32 @x[6],@d[3]
+ mov $D1,@K[4]
+ lsr @x[7],@d[3],#32
+ mov $D2,@K[5]
+ mov.32 @x[8],@d[4]
+ mov $D3,@K[6]
+ lsr @x[9],@d[4],#32
+ mov $C0,@K[2]
+ mov.32 @x[10],@d[5]
+ mov $C1,@K[2]
+ lsr @x[11],@d[5],#32
+ add $D4,$D0,$ONE // +4
+ mov.32 @x[12],@d[6]
+ add $D5,$D1,$ONE // +4
+ lsr @x[13],@d[6],#32
+ mov $C2,@K[2]
+ mov.32 @x[14],@d[7]
+ mov $C3,@K[2]
+ lsr @x[15],@d[7],#32
+ mov $C4,@K[2]
+ stp @K[3],@K[4],[sp,#48] // off-load key block, variable part
+ mov $C5,@K[2]
+ str @K[5],[sp,#80]
+
+ mov $ctr,#5
+ subs $len,$len,#512
+.Loop_upper_neon:
+ sub $ctr,$ctr,#1
+___
+ my @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0);
+ my @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0);
+ my @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0);
+ my @thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,0);
+ my @thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,0);
+ my @thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,0);
+ my @thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
+ my $diff = ($#thread0+1)*6 - $#thread67 - 1;
+ my $i = 0;
+
+ foreach (@thread0) {
+ eval; eval(shift(@thread67));
+ eval(shift(@thread1)); eval(shift(@thread67));
+ eval(shift(@thread2)); eval(shift(@thread67));
+ eval(shift(@thread3)); eval(shift(@thread67));
+ eval(shift(@thread4)); eval(shift(@thread67));
+ eval(shift(@thread5)); eval(shift(@thread67));
+ }
+
+ @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1);
+ @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1);
+ @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1);
+ @thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,1);
+ @thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,1);
+ @thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,1);
+ @thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
+
+ foreach (@thread0) {
+ eval; eval(shift(@thread67));
+ eval(shift(@thread1)); eval(shift(@thread67));
+ eval(shift(@thread2)); eval(shift(@thread67));
+ eval(shift(@thread3)); eval(shift(@thread67));
+ eval(shift(@thread4)); eval(shift(@thread67));
+ eval(shift(@thread5)); eval(shift(@thread67));
+ }
+$code.=<<___;
+ cbnz $ctr,.Loop_upper_neon
+
+ add.32 @x[0],@x[0],@d[0] // accumulate key block
+ add @x[1],@x[1],@d[0],lsr#32
+ add.32 @x[2],@x[2],@d[1]
+ add @x[3],@x[3],@d[1],lsr#32
+ add.32 @x[4],@x[4],@d[2]
+ add @x[5],@x[5],@d[2],lsr#32
+ add.32 @x[6],@x[6],@d[3]
+ add @x[7],@x[7],@d[3],lsr#32
+ add.32 @x[8],@x[8],@d[4]
+ add @x[9],@x[9],@d[4],lsr#32
+ add.32 @x[10],@x[10],@d[5]
+ add @x[11],@x[11],@d[5],lsr#32
+ add.32 @x[12],@x[12],@d[6]
+ add @x[13],@x[13],@d[6],lsr#32
+ add.32 @x[14],@x[14],@d[7]
+ add @x[15],@x[15],@d[7],lsr#32
+
+ add @x[0],@x[0],@x[1],lsl#32 // pack
+ add @x[2],@x[2],@x[3],lsl#32
+ ldp @x[1],@x[3],[$inp,#0] // load input
+ add @x[4],@x[4],@x[5],lsl#32
+ add @x[6],@x[6],@x[7],lsl#32
+ ldp @x[5],@x[7],[$inp,#16]
+ add @x[8],@x[8],@x[9],lsl#32
+ add @x[10],@x[10],@x[11],lsl#32
+ ldp @x[9],@x[11],[$inp,#32]
+ add @x[12],@x[12],@x[13],lsl#32
+ add @x[14],@x[14],@x[15],lsl#32
+ ldp @x[13],@x[15],[$inp,#48]
+ add $inp,$inp,#64
+#ifdef __ARMEB__
+ rev @x[0],@x[0]
+ rev @x[2],@x[2]
+ rev @x[4],@x[4]
+ rev @x[6],@x[6]
+ rev @x[8],@x[8]
+ rev @x[10],@x[10]
+ rev @x[12],@x[12]
+ rev @x[14],@x[14]
+#endif
+ eor @x[0],@x[0],@x[1]
+ eor @x[2],@x[2],@x[3]
+ eor @x[4],@x[4],@x[5]
+ eor @x[6],@x[6],@x[7]
+ eor @x[8],@x[8],@x[9]
+ eor @x[10],@x[10],@x[11]
+ eor @x[12],@x[12],@x[13]
+ eor @x[14],@x[14],@x[15]
+
+ stp @x[0],@x[2],[$out,#0] // store output
+ add @d[6],@d[6],#1 // increment counter
+ mov.32 @x[0],@d[0] // unpack key block
+ lsr @x[1],@d[0],#32
+ stp @x[4],@x[6],[$out,#16]
+ mov.32 @x[2],@d[1]
+ lsr @x[3],@d[1],#32
+ stp @x[8],@x[10],[$out,#32]
+ mov.32 @x[4],@d[2]
+ lsr @x[5],@d[2],#32
+ stp @x[12],@x[14],[$out,#48]
+ add $out,$out,#64
+ mov.32 @x[6],@d[3]
+ lsr @x[7],@d[3],#32
+ mov.32 @x[8],@d[4]
+ lsr @x[9],@d[4],#32
+ mov.32 @x[10],@d[5]
+ lsr @x[11],@d[5],#32
+ mov.32 @x[12],@d[6]
+ lsr @x[13],@d[6],#32
+ mov.32 @x[14],@d[7]
+ lsr @x[15],@d[7],#32
+
+ mov $ctr,#5
+.Loop_lower_neon:
+ sub $ctr,$ctr,#1
+___
+ @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,0);
+ @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,0);
+ @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,0);
+ @thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,0);
+ @thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,0);
+ @thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,0);
+ @thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
+
+ foreach (@thread0) {
+ eval; eval(shift(@thread67));
+ eval(shift(@thread1)); eval(shift(@thread67));
+ eval(shift(@thread2)); eval(shift(@thread67));
+ eval(shift(@thread3)); eval(shift(@thread67));
+ eval(shift(@thread4)); eval(shift(@thread67));
+ eval(shift(@thread5)); eval(shift(@thread67));
+ }
+
+ @thread0=&NEONROUND($A0,$B0,$C0,$D0,$T0,1);
+ @thread1=&NEONROUND($A1,$B1,$C1,$D1,$T1,1);
+ @thread2=&NEONROUND($A2,$B2,$C2,$D2,$T2,1);
+ @thread3=&NEONROUND($A3,$B3,$C3,$D3,$T3,1);
+ @thread4=&NEONROUND($A4,$B4,$C4,$D4,$T4,1);
+ @thread5=&NEONROUND($A5,$B5,$C5,$D5,$T5,1);
+ @thread67=(&ROUND(0,4,8,12),&ROUND(0,5,10,15));
+
+ foreach (@thread0) {
+ eval; eval(shift(@thread67));
+ eval(shift(@thread1)); eval(shift(@thread67));
+ eval(shift(@thread2)); eval(shift(@thread67));
+ eval(shift(@thread3)); eval(shift(@thread67));
+ eval(shift(@thread4)); eval(shift(@thread67));
+ eval(shift(@thread5)); eval(shift(@thread67));
+ }
+$code.=<<___;
+ cbnz $ctr,.Loop_lower_neon
+
+ add.32 @x[0],@x[0],@d[0] // accumulate key block
+ ldp @K[0],@K[1],[sp,#0]
+ add @x[1],@x[1],@d[0],lsr#32
+ ldp @K[2],@K[3],[sp,#32]
+ add.32 @x[2],@x[2],@d[1]
+ ldp @K[4],@K[5],[sp,#64]
+ add @x[3],@x[3],@d[1],lsr#32
+ add $A0,$A0,@K[0]
+ add.32 @x[4],@x[4],@d[2]
+ add $A1,$A1,@K[0]
+ add @x[5],@x[5],@d[2],lsr#32
+ add $A2,$A2,@K[0]
+ add.32 @x[6],@x[6],@d[3]
+ add $A3,$A3,@K[0]
+ add @x[7],@x[7],@d[3],lsr#32
+ add $A4,$A4,@K[0]
+ add.32 @x[8],@x[8],@d[4]
+ add $A5,$A5,@K[0]
+ add @x[9],@x[9],@d[4],lsr#32
+ add $C0,$C0,@K[2]
+ add.32 @x[10],@x[10],@d[5]
+ add $C1,$C1,@K[2]
+ add @x[11],@x[11],@d[5],lsr#32
+ add $C2,$C2,@K[2]
+ add.32 @x[12],@x[12],@d[6]
+ add $C3,$C3,@K[2]
+ add @x[13],@x[13],@d[6],lsr#32
+ add $C4,$C4,@K[2]
+ add.32 @x[14],@x[14],@d[7]
+ add $C5,$C5,@K[2]
+ add @x[15],@x[15],@d[7],lsr#32
+ add $D4,$D4,$ONE // +4
+ add @x[0],@x[0],@x[1],lsl#32 // pack
+ add $D5,$D5,$ONE // +4
+ add @x[2],@x[2],@x[3],lsl#32
+ add $D0,$D0,@K[3]
+ ldp @x[1],@x[3],[$inp,#0] // load input
+ add $D1,$D1,@K[4]
+ add @x[4],@x[4],@x[5],lsl#32
+ add $D2,$D2,@K[5]
+ add @x[6],@x[6],@x[7],lsl#32
+ add $D3,$D3,@K[6]
+ ldp @x[5],@x[7],[$inp,#16]
+ add $D4,$D4,@K[3]
+ add @x[8],@x[8],@x[9],lsl#32
+ add $D5,$D5,@K[4]
+ add @x[10],@x[10],@x[11],lsl#32
+ add $B0,$B0,@K[1]
+ ldp @x[9],@x[11],[$inp,#32]
+ add $B1,$B1,@K[1]
+ add @x[12],@x[12],@x[13],lsl#32
+ add $B2,$B2,@K[1]
+ add @x[14],@x[14],@x[15],lsl#32
+ add $B3,$B3,@K[1]
+ ldp @x[13],@x[15],[$inp,#48]
+ add $B4,$B4,@K[1]
+ add $inp,$inp,#64
+ add $B5,$B5,@K[1]
+
+#ifdef __ARMEB__
+ rev @x[0],@x[0]
+ rev @x[2],@x[2]
+ rev @x[4],@x[4]
+ rev @x[6],@x[6]
+ rev @x[8],@x[8]
+ rev @x[10],@x[10]
+ rev @x[12],@x[12]
+ rev @x[14],@x[14]
+#endif
+ ld1.8 {$T0-$T3},[$inp],#64
+ eor @x[0],@x[0],@x[1]
+ eor @x[2],@x[2],@x[3]
+ eor @x[4],@x[4],@x[5]
+ eor @x[6],@x[6],@x[7]
+ eor @x[8],@x[8],@x[9]
+ eor $A0,$A0,$T0
+ eor @x[10],@x[10],@x[11]
+ eor $B0,$B0,$T1
+ eor @x[12],@x[12],@x[13]
+ eor $C0,$C0,$T2
+ eor @x[14],@x[14],@x[15]
+ eor $D0,$D0,$T3
+ ld1.8 {$T0-$T3},[$inp],#64
+
+ stp @x[0],@x[2],[$out,#0] // store output
+ add @d[6],@d[6],#7 // increment counter
+ stp @x[4],@x[6],[$out,#16]
+ stp @x[8],@x[10],[$out,#32]
+ stp @x[12],@x[14],[$out,#48]
+ add $out,$out,#64
+ st1.8 {$A0-$D0},[$out],#64
+
+ ld1.8 {$A0-$D0},[$inp],#64
+ eor $A1,$A1,$T0
+ eor $B1,$B1,$T1
+ eor $C1,$C1,$T2
+ eor $D1,$D1,$T3
+ st1.8 {$A1-$D1},[$out],#64
+
+ ld1.8 {$A1-$D1},[$inp],#64
+ eor $A2,$A2,$A0
+ ldp @K[0],@K[1],[sp,#0]
+ eor $B2,$B2,$B0
+ ldp @K[2],@K[3],[sp,#32]
+ eor $C2,$C2,$C0
+ eor $D2,$D2,$D0
+ st1.8 {$A2-$D2},[$out],#64
+
+ ld1.8 {$A2-$D2},[$inp],#64
+ eor $A3,$A3,$A1
+ eor $B3,$B3,$B1
+ eor $C3,$C3,$C1
+ eor $D3,$D3,$D1
+ st1.8 {$A3-$D3},[$out],#64
+
+ ld1.8 {$A3-$D3},[$inp],#64
+ eor $A4,$A4,$A2
+ eor $B4,$B4,$B2
+ eor $C4,$C4,$C2
+ eor $D4,$D4,$D2
+ st1.8 {$A4-$D4},[$out],#64
+
+ shl $A0,$ONE,#1 // 4 -> 8
+ eor $A5,$A5,$A3
+ eor $B5,$B5,$B3
+ eor $C5,$C5,$C3
+ eor $D5,$D5,$D3
+ st1.8 {$A5-$D5},[$out],#64
+
+ add @K[3],@K[3],$A0 // += 8
+ add @K[4],@K[4],$A0
+ add @K[5],@K[5],$A0
+ add @K[6],@K[6],$A0
+
+ b.hs .Loop_outer_512_neon
+
+ adds $len,$len,#512
+ ushr $A0,$ONE,#2 // 4 -> 1
+
+ ldp d8,d9,[sp,#128+0] // meet ABI requirements
+ ldp d10,d11,[sp,#128+16]
+ ldp d12,d13,[sp,#128+32]
+ ldp d14,d15,[sp,#128+48]
+
+ stp @K[0],$ONE,[sp,#0] // wipe off-load area
+ stp @K[0],$ONE,[sp,#32]
+ stp @K[0],$ONE,[sp,#64]
+
+ b.eq .Ldone_512_neon
+
+ cmp $len,#192
+ sub @K[3],@K[3],$A0 // -= 1
+ sub @K[4],@K[4],$A0
+ sub @K[5],@K[5],$A0
+ add sp,sp,#128
+ b.hs .Loop_outer_neon
+
+ eor @K[1],@K[1],@K[1]
+ eor @K[2],@K[2],@K[2]
+ eor @K[3],@K[3],@K[3]
+ eor @K[4],@K[4],@K[4]
+ eor @K[5],@K[5],@K[5]
+ eor @K[6],@K[6],@K[6]
+ b .Loop_outer
+
+.Ldone_512_neon:
+ ldp x19,x20,[x29,#16]
+ add sp,sp,#128+64
+ ldp x21,x22,[x29,#32]
+ ldp x23,x24,[x29,#48]
+ ldp x25,x26,[x29,#64]
+ ldp x27,x28,[x29,#80]
+ ldp x29,x30,[sp],#96
+ ret
+.size ChaCha20_512_neon,.-ChaCha20_512_neon
+___
+}
+}}}
+
+foreach (split("\n",$code)) {
+ s/\`([^\`]*)\`/eval $1/geo;
+
+ (s/\b([a-z]+)\.32\b/$1/ and (s/x([0-9]+)/w$1/g or 1)) or
+ (m/\b(eor|ext|mov)\b/ and (s/\.4s/\.16b/g or 1)) or
+ (s/\b((?:ld|st)1)\.8\b/$1/ and (s/\.4s/\.16b/g or 1)) or
+ (m/\b(ld|st)[rp]\b/ and (s/v([0-9]+)\.4s/q$1/g or 1)) or
+ (s/\brev32\.16\b/rev32/ and (s/\.4s/\.8h/g or 1));
+
+ #s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo;
+
+ print $_,"\n";
+}
+close STDOUT; # flush
diff --git a/crypto/chacha/asm/chacha-x86.pl b/crypto/chacha/asm/chacha-x86.pl
new file mode 100755
index 00000000..edce43dc
--- /dev/null
+++ b/crypto/chacha/asm/chacha-x86.pl
@@ -0,0 +1,753 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# January 2015
+#
+# ChaCha20 for x86.
+#
+# Performance in cycles per byte out of large buffer.
+#
+# 1xIALU/gcc 4xSSSE3
+# Pentium 17.5/+80%
+# PIII 14.2/+60%
+# P4 18.6/+84%
+# Core2 9.56/+89% 4.83
+# Westmere 9.50/+45% 3.35
+# Sandy Bridge 10.5/+47% 3.20
+# Haswell 8.15/+50% 2.83
+# Silvermont 17.4/+36% 8.35
+# Sledgehammer 10.2/+54%
+# Bulldozer 13.4/+50% 4.38(*)
+#
+# (*) Bulldozer actually executes 4xXOP code path that delivers 3.55;
+#
+# Modified from upstream OpenSSL to remove the XOP code.
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],"chacha-x86.pl",$ARGV[$#ARGV] eq "386");
+
+$xmm=$ymm=0;
+for (@ARGV) { $xmm=1 if (/-DOPENSSL_IA32_SSE2/); }
+
+$ymm=$xmm;
+
+$a="eax";
+($b,$b_)=("ebx","ebp");
+($c,$c_)=("ecx","esi");
+($d,$d_)=("edx","edi");
+
+sub QUARTERROUND {
+my ($ai,$bi,$ci,$di,$i)=@_;
+my ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+1)&3),($ai,$bi,$ci,$di)); # next
+my ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-1)&3),($ai,$bi,$ci,$di)); # previous
+
+ # a b c d
+ #
+ # 0 4 8 12 < even round
+ # 1 5 9 13
+ # 2 6 10 14
+ # 3 7 11 15
+ # 0 5 10 15 < odd round
+ # 1 6 11 12
+ # 2 7 8 13
+ # 3 4 9 14
+
+ if ($i==0) {
+ my $j=4;
+ ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-$j--)&3),($ap,$bp,$cp,$dp));
+ } elsif ($i==3) {
+ my $j=0;
+ ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+$j++)&3),($an,$bn,$cn,$dn));
+ } elsif ($i==4) {
+ my $j=4;
+ ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_+$j--)&3),($ap,$bp,$cp,$dp));
+ } elsif ($i==7) {
+ my $j=0;
+ ($an,$bn,$cn,$dn)=map(($_&~3)+(($_-$j++)&3),($an,$bn,$cn,$dn));
+ }
+
+ #&add ($a,$b); # see elsewhere
+ &xor ($d,$a);
+ &mov (&DWP(4*$cp,"esp"),$c_) if ($ai>0 && $ai<3);
+ &rol ($d,16);
+ &mov (&DWP(4*$bp,"esp"),$b_) if ($i!=0);
+ &add ($c,$d);
+ &mov ($c_,&DWP(4*$cn,"esp")) if ($ai>0 && $ai<3);
+ &xor ($b,$c);
+ &mov ($d_,&DWP(4*$dn,"esp")) if ($di!=$dn);
+ &rol ($b,12);
+ &mov ($b_,&DWP(4*$bn,"esp")) if ($i<7);
+ &mov ($b_,&DWP(128,"esp")) if ($i==7); # loop counter
+ &add ($a,$b);
+ &xor ($d,$a);
+ &mov (&DWP(4*$ai,"esp"),$a);
+ &rol ($d,8);
+ &mov ($a,&DWP(4*$an,"esp"));
+ &add ($c,$d);
+ &mov (&DWP(4*$di,"esp"),$d) if ($di!=$dn);
+ &mov ($d_,$d) if ($di==$dn);
+ &xor ($b,$c);
+ &add ($a,$b_) if ($i<7); # elsewhere
+ &rol ($b,7);
+
+ ($b,$b_)=($b_,$b);
+ ($c,$c_)=($c_,$c);
+ ($d,$d_)=($d_,$d);
+}
+
+&static_label("ssse3_shortcut");
+&static_label("ssse3_data");
+&static_label("pic_point");
+
+&function_begin("ChaCha20_ctr32");
+ &xor ("eax","eax");
+ &cmp ("eax",&wparam(2)); # len==0?
+ &je (&label("no_data"));
+if ($xmm) {
+ &call (&label("pic_point"));
+&set_label("pic_point");
+ &blindpop("eax");
+ &picmeup("ebp","OPENSSL_ia32cap_P","eax",&label("pic_point"));
+ &test (&DWP(0,"ebp"),1<<24); # test FXSR bit
+ &jz (&label("x86"));
+ &test (&DWP(4,"ebp"),1<<9); # test SSSE3 bit
+ &jz (&label("x86"));
+ &jmp (&label("ssse3_shortcut"));
+&set_label("x86");
+}
+ &mov ("esi",&wparam(3)); # key
+ &mov ("edi",&wparam(4)); # counter and nonce
+
+ &stack_push(33);
+
+ &mov ("eax",&DWP(4*0,"esi")); # copy key
+ &mov ("ebx",&DWP(4*1,"esi"));
+ &mov ("ecx",&DWP(4*2,"esi"));
+ &mov ("edx",&DWP(4*3,"esi"));
+ &mov (&DWP(64+4*4,"esp"),"eax");
+ &mov (&DWP(64+4*5,"esp"),"ebx");
+ &mov (&DWP(64+4*6,"esp"),"ecx");
+ &mov (&DWP(64+4*7,"esp"),"edx");
+ &mov ("eax",&DWP(4*4,"esi"));
+ &mov ("ebx",&DWP(4*5,"esi"));
+ &mov ("ecx",&DWP(4*6,"esi"));
+ &mov ("edx",&DWP(4*7,"esi"));
+ &mov (&DWP(64+4*8,"esp"),"eax");
+ &mov (&DWP(64+4*9,"esp"),"ebx");
+ &mov (&DWP(64+4*10,"esp"),"ecx");
+ &mov (&DWP(64+4*11,"esp"),"edx");
+ &mov ("eax",&DWP(4*0,"edi")); # copy counter and nonce
+ &mov ("ebx",&DWP(4*1,"edi"));
+ &mov ("ecx",&DWP(4*2,"edi"));
+ &mov ("edx",&DWP(4*3,"edi"));
+ &sub ("eax",1);
+ &mov (&DWP(64+4*12,"esp"),"eax");
+ &mov (&DWP(64+4*13,"esp"),"ebx");
+ &mov (&DWP(64+4*14,"esp"),"ecx");
+ &mov (&DWP(64+4*15,"esp"),"edx");
+ &jmp (&label("entry"));
+
+&set_label("outer_loop",16);
+ &mov (&wparam(1),$b); # save input
+ &mov (&wparam(0),$a); # save output
+ &mov (&wparam(2),$c); # save len
+&set_label("entry");
+ &mov ($a,0x61707865);
+ &mov (&DWP(4*1,"esp"),0x3320646e);
+ &mov (&DWP(4*2,"esp"),0x79622d32);
+ &mov (&DWP(4*3,"esp"),0x6b206574);
+
+ &mov ($b, &DWP(64+4*5,"esp")); # copy key material
+ &mov ($b_,&DWP(64+4*6,"esp"));
+ &mov ($c, &DWP(64+4*10,"esp"));
+ &mov ($c_,&DWP(64+4*11,"esp"));
+ &mov ($d, &DWP(64+4*13,"esp"));
+ &mov ($d_,&DWP(64+4*14,"esp"));
+ &mov (&DWP(4*5,"esp"),$b);
+ &mov (&DWP(4*6,"esp"),$b_);
+ &mov (&DWP(4*10,"esp"),$c);
+ &mov (&DWP(4*11,"esp"),$c_);
+ &mov (&DWP(4*13,"esp"),$d);
+ &mov (&DWP(4*14,"esp"),$d_);
+
+ &mov ($b, &DWP(64+4*7,"esp"));
+ &mov ($d_,&DWP(64+4*15,"esp"));
+ &mov ($d, &DWP(64+4*12,"esp"));
+ &mov ($b_,&DWP(64+4*4,"esp"));
+ &mov ($c, &DWP(64+4*8,"esp"));
+ &mov ($c_,&DWP(64+4*9,"esp"));
+ &add ($d,1); # counter value
+ &mov (&DWP(4*7,"esp"),$b);
+ &mov (&DWP(4*15,"esp"),$d_);
+ &mov (&DWP(64+4*12,"esp"),$d); # save counter value
+
+ &mov ($b,10); # loop counter
+ &jmp (&label("loop"));
+
+&set_label("loop",16);
+ &add ($a,$b_); # elsewhere
+ &mov (&DWP(128,"esp"),$b); # save loop counter
+ &mov ($b,$b_);
+ &QUARTERROUND(0, 4, 8, 12, 0);
+ &QUARTERROUND(1, 5, 9, 13, 1);
+ &QUARTERROUND(2, 6,10, 14, 2);
+ &QUARTERROUND(3, 7,11, 15, 3);
+ &QUARTERROUND(0, 5,10, 15, 4);
+ &QUARTERROUND(1, 6,11, 12, 5);
+ &QUARTERROUND(2, 7, 8, 13, 6);
+ &QUARTERROUND(3, 4, 9, 14, 7);
+ &dec ($b);
+ &jnz (&label("loop"));
+
+ &mov ($b,&wparam(2)); # load len
+
+ &add ($a,0x61707865); # accumulate key material
+ &add ($b_,&DWP(64+4*4,"esp"));
+ &add ($c, &DWP(64+4*8,"esp"));
+ &add ($c_,&DWP(64+4*9,"esp"));
+
+ &cmp ($b,64);
+ &jb (&label("tail"));
+
+ &mov ($b,&wparam(1)); # load input pointer
+ &add ($d, &DWP(64+4*12,"esp"));
+ &add ($d_,&DWP(64+4*14,"esp"));
+
+ &xor ($a, &DWP(4*0,$b)); # xor with input
+ &xor ($b_,&DWP(4*4,$b));
+ &mov (&DWP(4*0,"esp"),$a);
+ &mov ($a,&wparam(0)); # load output pointer
+ &xor ($c, &DWP(4*8,$b));
+ &xor ($c_,&DWP(4*9,$b));
+ &xor ($d, &DWP(4*12,$b));
+ &xor ($d_,&DWP(4*14,$b));
+ &mov (&DWP(4*4,$a),$b_); # write output
+ &mov (&DWP(4*8,$a),$c);
+ &mov (&DWP(4*9,$a),$c_);
+ &mov (&DWP(4*12,$a),$d);
+ &mov (&DWP(4*14,$a),$d_);
+
+ &mov ($b_,&DWP(4*1,"esp"));
+ &mov ($c, &DWP(4*2,"esp"));
+ &mov ($c_,&DWP(4*3,"esp"));
+ &mov ($d, &DWP(4*5,"esp"));
+ &mov ($d_,&DWP(4*6,"esp"));
+ &add ($b_,0x3320646e); # accumulate key material
+ &add ($c, 0x79622d32);
+ &add ($c_,0x6b206574);
+ &add ($d, &DWP(64+4*5,"esp"));
+ &add ($d_,&DWP(64+4*6,"esp"));
+ &xor ($b_,&DWP(4*1,$b));
+ &xor ($c, &DWP(4*2,$b));
+ &xor ($c_,&DWP(4*3,$b));
+ &xor ($d, &DWP(4*5,$b));
+ &xor ($d_,&DWP(4*6,$b));
+ &mov (&DWP(4*1,$a),$b_);
+ &mov (&DWP(4*2,$a),$c);
+ &mov (&DWP(4*3,$a),$c_);
+ &mov (&DWP(4*5,$a),$d);
+ &mov (&DWP(4*6,$a),$d_);
+
+ &mov ($b_,&DWP(4*7,"esp"));
+ &mov ($c, &DWP(4*10,"esp"));
+ &mov ($c_,&DWP(4*11,"esp"));
+ &mov ($d, &DWP(4*13,"esp"));
+ &mov ($d_,&DWP(4*15,"esp"));
+ &add ($b_,&DWP(64+4*7,"esp"));
+ &add ($c, &DWP(64+4*10,"esp"));
+ &add ($c_,&DWP(64+4*11,"esp"));
+ &add ($d, &DWP(64+4*13,"esp"));
+ &add ($d_,&DWP(64+4*15,"esp"));
+ &xor ($b_,&DWP(4*7,$b));
+ &xor ($c, &DWP(4*10,$b));
+ &xor ($c_,&DWP(4*11,$b));
+ &xor ($d, &DWP(4*13,$b));
+ &xor ($d_,&DWP(4*15,$b));
+ &lea ($b,&DWP(4*16,$b));
+ &mov (&DWP(4*7,$a),$b_);
+ &mov ($b_,&DWP(4*0,"esp"));
+ &mov (&DWP(4*10,$a),$c);
+ &mov ($c,&wparam(2)); # len
+ &mov (&DWP(4*11,$a),$c_);
+ &mov (&DWP(4*13,$a),$d);
+ &mov (&DWP(4*15,$a),$d_);
+ &mov (&DWP(4*0,$a),$b_);
+ &lea ($a,&DWP(4*16,$a));
+ &sub ($c,64);
+ &jnz (&label("outer_loop"));
+
+ &jmp (&label("done"));
+
+&set_label("tail");
+ &add ($d, &DWP(64+4*12,"esp"));
+ &add ($d_,&DWP(64+4*14,"esp"));
+ &mov (&DWP(4*0,"esp"),$a);
+ &mov (&DWP(4*4,"esp"),$b_);
+ &mov (&DWP(4*8,"esp"),$c);
+ &mov (&DWP(4*9,"esp"),$c_);
+ &mov (&DWP(4*12,"esp"),$d);
+ &mov (&DWP(4*14,"esp"),$d_);
+
+ &mov ($b_,&DWP(4*1,"esp"));
+ &mov ($c, &DWP(4*2,"esp"));
+ &mov ($c_,&DWP(4*3,"esp"));
+ &mov ($d, &DWP(4*5,"esp"));
+ &mov ($d_,&DWP(4*6,"esp"));
+ &add ($b_,0x3320646e); # accumulate key material
+ &add ($c, 0x79622d32);
+ &add ($c_,0x6b206574);
+ &add ($d, &DWP(64+4*5,"esp"));
+ &add ($d_,&DWP(64+4*6,"esp"));
+ &mov (&DWP(4*1,"esp"),$b_);
+ &mov (&DWP(4*2,"esp"),$c);
+ &mov (&DWP(4*3,"esp"),$c_);
+ &mov (&DWP(4*5,"esp"),$d);
+ &mov (&DWP(4*6,"esp"),$d_);
+
+ &mov ($b_,&DWP(4*7,"esp"));
+ &mov ($c, &DWP(4*10,"esp"));
+ &mov ($c_,&DWP(4*11,"esp"));
+ &mov ($d, &DWP(4*13,"esp"));
+ &mov ($d_,&DWP(4*15,"esp"));
+ &add ($b_,&DWP(64+4*7,"esp"));
+ &add ($c, &DWP(64+4*10,"esp"));
+ &add ($c_,&DWP(64+4*11,"esp"));
+ &add ($d, &DWP(64+4*13,"esp"));
+ &add ($d_,&DWP(64+4*15,"esp"));
+ &mov (&DWP(4*7,"esp"),$b_);
+ &mov ($b_,&wparam(1)); # load input
+ &mov (&DWP(4*10,"esp"),$c);
+ &mov ($c,&wparam(0)); # load output
+ &mov (&DWP(4*11,"esp"),$c_);
+ &xor ($c_,$c_);
+ &mov (&DWP(4*13,"esp"),$d);
+ &mov (&DWP(4*15,"esp"),$d_);
+
+ &xor ("eax","eax");
+ &xor ("edx","edx");
+&set_label("tail_loop");
+ &movb ("al",&BP(0,$c_,$b_));
+ &movb ("dl",&BP(0,"esp",$c_));
+ &lea ($c_,&DWP(1,$c_));
+ &xor ("al","dl");
+ &mov (&BP(-1,$c,$c_),"al");
+ &dec ($b);
+ &jnz (&label("tail_loop"));
+
+&set_label("done");
+ &stack_pop(33);
+&set_label("no_data");
+&function_end("ChaCha20_ctr32");
+
+if ($xmm) {
+my ($xa,$xa_,$xb,$xb_,$xc,$xc_,$xd,$xd_)=map("xmm$_",(0..7));
+my ($out,$inp,$len)=("edi","esi","ecx");
+
+sub QUARTERROUND_SSSE3 {
+my ($ai,$bi,$ci,$di,$i)=@_;
+my ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+1)&3),($ai,$bi,$ci,$di)); # next
+my ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-1)&3),($ai,$bi,$ci,$di)); # previous
+
+ # a b c d
+ #
+ # 0 4 8 12 < even round
+ # 1 5 9 13
+ # 2 6 10 14
+ # 3 7 11 15
+ # 0 5 10 15 < odd round
+ # 1 6 11 12
+ # 2 7 8 13
+ # 3 4 9 14
+
+ if ($i==0) {
+ my $j=4;
+ ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-$j--)&3),($ap,$bp,$cp,$dp));
+ } elsif ($i==3) {
+ my $j=0;
+ ($an,$bn,$cn,$dn)=map(($_&~3)+(($_+$j++)&3),($an,$bn,$cn,$dn));
+ } elsif ($i==4) {
+ my $j=4;
+ ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_+$j--)&3),($ap,$bp,$cp,$dp));
+ } elsif ($i==7) {
+ my $j=0;
+ ($an,$bn,$cn,$dn)=map(($_&~3)+(($_-$j++)&3),($an,$bn,$cn,$dn));
+ }
+
+ #&paddd ($xa,$xb); # see elsewhere
+ #&pxor ($xd,$xa); # see elsewhere
+ &movdqa(&QWP(16*$cp-128,"ebx"),$xc_) if ($ai>0 && $ai<3);
+ &pshufb ($xd,&QWP(0,"eax")); # rot16
+ &movdqa(&QWP(16*$bp-128,"ebx"),$xb_) if ($i!=0);
+ &paddd ($xc,$xd);
+ &movdqa($xc_,&QWP(16*$cn-128,"ebx")) if ($ai>0 && $ai<3);
+ &pxor ($xb,$xc);
+ &movdqa($xb_,&QWP(16*$bn-128,"ebx")) if ($i<7);
+ &movdqa ($xa_,$xb); # borrow as temporary
+ &pslld ($xb,12);
+ &psrld ($xa_,20);
+ &por ($xb,$xa_);
+ &movdqa($xa_,&QWP(16*$an-128,"ebx"));
+ &paddd ($xa,$xb);
+ &movdqa($xd_,&QWP(16*$dn-128,"ebx")) if ($di!=$dn);
+ &pxor ($xd,$xa);
+ &movdqa (&QWP(16*$ai-128,"ebx"),$xa);
+ &pshufb ($xd,&QWP(16,"eax")); # rot8
+ &paddd ($xc,$xd);
+ &movdqa (&QWP(16*$di-128,"ebx"),$xd) if ($di!=$dn);
+ &movdqa ($xd_,$xd) if ($di==$dn);
+ &pxor ($xb,$xc);
+ &paddd ($xa_,$xb_) if ($i<7); # elsewhere
+ &movdqa ($xa,$xb); # borrow as temporary
+ &pslld ($xb,7);
+ &psrld ($xa,25);
+ &pxor ($xd_,$xa_) if ($i<7); # elsewhere
+ &por ($xb,$xa);
+
+ ($xa,$xa_)=($xa_,$xa);
+ ($xb,$xb_)=($xb_,$xb);
+ ($xc,$xc_)=($xc_,$xc);
+ ($xd,$xd_)=($xd_,$xd);
+}
+
+&function_begin("ChaCha20_ssse3");
+&set_label("ssse3_shortcut");
+ &mov ($out,&wparam(0));
+ &mov ($inp,&wparam(1));
+ &mov ($len,&wparam(2));
+ &mov ("edx",&wparam(3)); # key
+ &mov ("ebx",&wparam(4)); # counter and nonce
+
+ &mov ("ebp","esp");
+ &stack_push (131);
+ &and ("esp",-64);
+ &mov (&DWP(512,"esp"),"ebp");
+
+ &lea ("eax",&DWP(&label("ssse3_data")."-".
+ &label("pic_point"),"eax"));
+ &movdqu ("xmm3",&QWP(0,"ebx")); # counter and nonce
+
+ &cmp ($len,64*4);
+ &jb (&label("1x"));
+
+ &mov (&DWP(512+4,"esp"),"edx"); # offload pointers
+ &mov (&DWP(512+8,"esp"),"ebx");
+ &sub ($len,64*4); # bias len
+ &lea ("ebp",&DWP(256+128,"esp")); # size optimization
+
+ &movdqu ("xmm7",&QWP(0,"edx")); # key
+ &pshufd ("xmm0","xmm3",0x00);
+ &pshufd ("xmm1","xmm3",0x55);
+ &pshufd ("xmm2","xmm3",0xaa);
+ &pshufd ("xmm3","xmm3",0xff);
+ &paddd ("xmm0",&QWP(16*3,"eax")); # fix counters
+ &pshufd ("xmm4","xmm7",0x00);
+ &pshufd ("xmm5","xmm7",0x55);
+ &psubd ("xmm0",&QWP(16*4,"eax"));
+ &pshufd ("xmm6","xmm7",0xaa);
+ &pshufd ("xmm7","xmm7",0xff);
+ &movdqa (&QWP(16*12-128,"ebp"),"xmm0");
+ &movdqa (&QWP(16*13-128,"ebp"),"xmm1");
+ &movdqa (&QWP(16*14-128,"ebp"),"xmm2");
+ &movdqa (&QWP(16*15-128,"ebp"),"xmm3");
+ &movdqu ("xmm3",&QWP(16,"edx")); # key
+ &movdqa (&QWP(16*4-128,"ebp"),"xmm4");
+ &movdqa (&QWP(16*5-128,"ebp"),"xmm5");
+ &movdqa (&QWP(16*6-128,"ebp"),"xmm6");
+ &movdqa (&QWP(16*7-128,"ebp"),"xmm7");
+ &movdqa ("xmm7",&QWP(16*2,"eax")); # sigma
+ &lea ("ebx",&DWP(128,"esp")); # size optimization
+
+ &pshufd ("xmm0","xmm3",0x00);
+ &pshufd ("xmm1","xmm3",0x55);
+ &pshufd ("xmm2","xmm3",0xaa);
+ &pshufd ("xmm3","xmm3",0xff);
+ &pshufd ("xmm4","xmm7",0x00);
+ &pshufd ("xmm5","xmm7",0x55);
+ &pshufd ("xmm6","xmm7",0xaa);
+ &pshufd ("xmm7","xmm7",0xff);
+ &movdqa (&QWP(16*8-128,"ebp"),"xmm0");
+ &movdqa (&QWP(16*9-128,"ebp"),"xmm1");
+ &movdqa (&QWP(16*10-128,"ebp"),"xmm2");
+ &movdqa (&QWP(16*11-128,"ebp"),"xmm3");
+ &movdqa (&QWP(16*0-128,"ebp"),"xmm4");
+ &movdqa (&QWP(16*1-128,"ebp"),"xmm5");
+ &movdqa (&QWP(16*2-128,"ebp"),"xmm6");
+ &movdqa (&QWP(16*3-128,"ebp"),"xmm7");
+
+ &lea ($inp,&DWP(128,$inp)); # size optimization
+ &lea ($out,&DWP(128,$out)); # size optimization
+ &jmp (&label("outer_loop"));
+
+&set_label("outer_loop",16);
+ #&movdqa ("xmm0",&QWP(16*0-128,"ebp")); # copy key material
+ &movdqa ("xmm1",&QWP(16*1-128,"ebp"));
+ &movdqa ("xmm2",&QWP(16*2-128,"ebp"));
+ &movdqa ("xmm3",&QWP(16*3-128,"ebp"));
+ #&movdqa ("xmm4",&QWP(16*4-128,"ebp"));
+ &movdqa ("xmm5",&QWP(16*5-128,"ebp"));
+ &movdqa ("xmm6",&QWP(16*6-128,"ebp"));
+ &movdqa ("xmm7",&QWP(16*7-128,"ebp"));
+ #&movdqa (&QWP(16*0-128,"ebx"),"xmm0");
+ &movdqa (&QWP(16*1-128,"ebx"),"xmm1");
+ &movdqa (&QWP(16*2-128,"ebx"),"xmm2");
+ &movdqa (&QWP(16*3-128,"ebx"),"xmm3");
+ #&movdqa (&QWP(16*4-128,"ebx"),"xmm4");
+ &movdqa (&QWP(16*5-128,"ebx"),"xmm5");
+ &movdqa (&QWP(16*6-128,"ebx"),"xmm6");
+ &movdqa (&QWP(16*7-128,"ebx"),"xmm7");
+ #&movdqa ("xmm0",&QWP(16*8-128,"ebp"));
+ #&movdqa ("xmm1",&QWP(16*9-128,"ebp"));
+ &movdqa ("xmm2",&QWP(16*10-128,"ebp"));
+ &movdqa ("xmm3",&QWP(16*11-128,"ebp"));
+ &movdqa ("xmm4",&QWP(16*12-128,"ebp"));
+ &movdqa ("xmm5",&QWP(16*13-128,"ebp"));
+ &movdqa ("xmm6",&QWP(16*14-128,"ebp"));
+ &movdqa ("xmm7",&QWP(16*15-128,"ebp"));
+ &paddd ("xmm4",&QWP(16*4,"eax")); # counter value
+ #&movdqa (&QWP(16*8-128,"ebx"),"xmm0");
+ #&movdqa (&QWP(16*9-128,"ebx"),"xmm1");
+ &movdqa (&QWP(16*10-128,"ebx"),"xmm2");
+ &movdqa (&QWP(16*11-128,"ebx"),"xmm3");
+ &movdqa (&QWP(16*12-128,"ebx"),"xmm4");
+ &movdqa (&QWP(16*13-128,"ebx"),"xmm5");
+ &movdqa (&QWP(16*14-128,"ebx"),"xmm6");
+ &movdqa (&QWP(16*15-128,"ebx"),"xmm7");
+ &movdqa (&QWP(16*12-128,"ebp"),"xmm4"); # save counter value
+
+ &movdqa ($xa, &QWP(16*0-128,"ebp"));
+ &movdqa ($xd, "xmm4");
+ &movdqa ($xb_,&QWP(16*4-128,"ebp"));
+ &movdqa ($xc, &QWP(16*8-128,"ebp"));
+ &movdqa ($xc_,&QWP(16*9-128,"ebp"));
+
+ &mov ("edx",10); # loop counter
+ &nop ();
+
+&set_label("loop",16);
+ &paddd ($xa,$xb_); # elsewhere
+ &movdqa ($xb,$xb_);
+ &pxor ($xd,$xa); # elsewhere
+ &QUARTERROUND_SSSE3(0, 4, 8, 12, 0);
+ &QUARTERROUND_SSSE3(1, 5, 9, 13, 1);
+ &QUARTERROUND_SSSE3(2, 6,10, 14, 2);
+ &QUARTERROUND_SSSE3(3, 7,11, 15, 3);
+ &QUARTERROUND_SSSE3(0, 5,10, 15, 4);
+ &QUARTERROUND_SSSE3(1, 6,11, 12, 5);
+ &QUARTERROUND_SSSE3(2, 7, 8, 13, 6);
+ &QUARTERROUND_SSSE3(3, 4, 9, 14, 7);
+ &dec ("edx");
+ &jnz (&label("loop"));
+
+ &movdqa (&QWP(16*4-128,"ebx"),$xb_);
+ &movdqa (&QWP(16*8-128,"ebx"),$xc);
+ &movdqa (&QWP(16*9-128,"ebx"),$xc_);
+ &movdqa (&QWP(16*12-128,"ebx"),$xd);
+ &movdqa (&QWP(16*14-128,"ebx"),$xd_);
+
+ my ($xa0,$xa1,$xa2,$xa3,$xt0,$xt1,$xt2,$xt3)=map("xmm$_",(0..7));
+
+ #&movdqa ($xa0,&QWP(16*0-128,"ebx")); # it's there
+ &movdqa ($xa1,&QWP(16*1-128,"ebx"));
+ &movdqa ($xa2,&QWP(16*2-128,"ebx"));
+ &movdqa ($xa3,&QWP(16*3-128,"ebx"));
+
+ for($i=0;$i<256;$i+=64) {
+ &paddd ($xa0,&QWP($i+16*0-128,"ebp")); # accumulate key material
+ &paddd ($xa1,&QWP($i+16*1-128,"ebp"));
+ &paddd ($xa2,&QWP($i+16*2-128,"ebp"));
+ &paddd ($xa3,&QWP($i+16*3-128,"ebp"));
+
+ &movdqa ($xt2,$xa0); # "de-interlace" data
+ &punpckldq ($xa0,$xa1);
+ &movdqa ($xt3,$xa2);
+ &punpckldq ($xa2,$xa3);
+ &punpckhdq ($xt2,$xa1);
+ &punpckhdq ($xt3,$xa3);
+ &movdqa ($xa1,$xa0);
+ &punpcklqdq ($xa0,$xa2); # "a0"
+ &movdqa ($xa3,$xt2);
+ &punpcklqdq ($xt2,$xt3); # "a2"
+ &punpckhqdq ($xa1,$xa2); # "a1"
+ &punpckhqdq ($xa3,$xt3); # "a3"
+
+ #($xa2,$xt2)=($xt2,$xa2);
+
+ &movdqu ($xt0,&QWP(64*0-128,$inp)); # load input
+ &movdqu ($xt1,&QWP(64*1-128,$inp));
+ &movdqu ($xa2,&QWP(64*2-128,$inp));
+ &movdqu ($xt3,&QWP(64*3-128,$inp));
+ &lea ($inp,&QWP($i<192?16:(64*4-16*3),$inp));
+ &pxor ($xt0,$xa0);
+ &movdqa ($xa0,&QWP($i+16*4-128,"ebx")) if ($i<192);
+ &pxor ($xt1,$xa1);
+ &movdqa ($xa1,&QWP($i+16*5-128,"ebx")) if ($i<192);
+ &pxor ($xt2,$xa2);
+ &movdqa ($xa2,&QWP($i+16*6-128,"ebx")) if ($i<192);
+ &pxor ($xt3,$xa3);
+ &movdqa ($xa3,&QWP($i+16*7-128,"ebx")) if ($i<192);
+ &movdqu (&QWP(64*0-128,$out),$xt0); # store output
+ &movdqu (&QWP(64*1-128,$out),$xt1);
+ &movdqu (&QWP(64*2-128,$out),$xt2);
+ &movdqu (&QWP(64*3-128,$out),$xt3);
+ &lea ($out,&QWP($i<192?16:(64*4-16*3),$out));
+ }
+ &sub ($len,64*4);
+ &jnc (&label("outer_loop"));
+
+ &add ($len,64*4);
+ &jz (&label("done"));
+
+ &mov ("ebx",&DWP(512+8,"esp")); # restore pointers
+ &lea ($inp,&DWP(-128,$inp));
+ &mov ("edx",&DWP(512+4,"esp"));
+ &lea ($out,&DWP(-128,$out));
+
+ &movd ("xmm2",&DWP(16*12-128,"ebp")); # counter value
+ &movdqu ("xmm3",&QWP(0,"ebx"));
+ &paddd ("xmm2",&QWP(16*6,"eax")); # +four
+ &pand ("xmm3",&QWP(16*7,"eax"));
+ &por ("xmm3","xmm2"); # counter value
+{
+my ($a,$b,$c,$d,$t,$t1,$rot16,$rot24)=map("xmm$_",(0..7));
+
+sub SSSE3ROUND { # critical path is 20 "SIMD ticks" per round
+ &paddd ($a,$b);
+ &pxor ($d,$a);
+ &pshufb ($d,$rot16);
+
+ &paddd ($c,$d);
+ &pxor ($b,$c);
+ &movdqa ($t,$b);
+ &psrld ($b,20);
+ &pslld ($t,12);
+ &por ($b,$t);
+
+ &paddd ($a,$b);
+ &pxor ($d,$a);
+ &pshufb ($d,$rot24);
+
+ &paddd ($c,$d);
+ &pxor ($b,$c);
+ &movdqa ($t,$b);
+ &psrld ($b,25);
+ &pslld ($t,7);
+ &por ($b,$t);
+}
+
+&set_label("1x");
+ &movdqa ($a,&QWP(16*2,"eax")); # sigma
+ &movdqu ($b,&QWP(0,"edx"));
+ &movdqu ($c,&QWP(16,"edx"));
+ #&movdqu ($d,&QWP(0,"ebx")); # already loaded
+ &movdqa ($rot16,&QWP(0,"eax"));
+ &movdqa ($rot24,&QWP(16,"eax"));
+ &mov (&DWP(16*3,"esp"),"ebp");
+
+ &movdqa (&QWP(16*0,"esp"),$a);
+ &movdqa (&QWP(16*1,"esp"),$b);
+ &movdqa (&QWP(16*2,"esp"),$c);
+ &movdqa (&QWP(16*3,"esp"),$d);
+ &mov ("edx",10);
+ &jmp (&label("loop1x"));
+
+&set_label("outer1x",16);
+ &movdqa ($d,&QWP(16*5,"eax")); # one
+ &movdqa ($a,&QWP(16*0,"esp"));
+ &movdqa ($b,&QWP(16*1,"esp"));
+ &movdqa ($c,&QWP(16*2,"esp"));
+ &paddd ($d,&QWP(16*3,"esp"));
+ &mov ("edx",10);
+ &movdqa (&QWP(16*3,"esp"),$d);
+ &jmp (&label("loop1x"));
+
+&set_label("loop1x",16);
+ &SSSE3ROUND();
+ &pshufd ($c,$c,0b01001110);
+ &pshufd ($b,$b,0b00111001);
+ &pshufd ($d,$d,0b10010011);
+ &nop ();
+
+ &SSSE3ROUND();
+ &pshufd ($c,$c,0b01001110);
+ &pshufd ($b,$b,0b10010011);
+ &pshufd ($d,$d,0b00111001);
+
+ &dec ("edx");
+ &jnz (&label("loop1x"));
+
+ &paddd ($a,&QWP(16*0,"esp"));
+ &paddd ($b,&QWP(16*1,"esp"));
+ &paddd ($c,&QWP(16*2,"esp"));
+ &paddd ($d,&QWP(16*3,"esp"));
+
+ &cmp ($len,64);
+ &jb (&label("tail"));
+
+ &movdqu ($t,&QWP(16*0,$inp));
+ &movdqu ($t1,&QWP(16*1,$inp));
+ &pxor ($a,$t); # xor with input
+ &movdqu ($t,&QWP(16*2,$inp));
+ &pxor ($b,$t1);
+ &movdqu ($t1,&QWP(16*3,$inp));
+ &pxor ($c,$t);
+ &pxor ($d,$t1);
+ &lea ($inp,&DWP(16*4,$inp)); # inp+=64
+
+ &movdqu (&QWP(16*0,$out),$a); # write output
+ &movdqu (&QWP(16*1,$out),$b);
+ &movdqu (&QWP(16*2,$out),$c);
+ &movdqu (&QWP(16*3,$out),$d);
+ &lea ($out,&DWP(16*4,$out)); # inp+=64
+
+ &sub ($len,64);
+ &jnz (&label("outer1x"));
+
+ &jmp (&label("done"));
+
+&set_label("tail");
+ &movdqa (&QWP(16*0,"esp"),$a);
+ &movdqa (&QWP(16*1,"esp"),$b);
+ &movdqa (&QWP(16*2,"esp"),$c);
+ &movdqa (&QWP(16*3,"esp"),$d);
+
+ &xor ("eax","eax");
+ &xor ("edx","edx");
+ &xor ("ebp","ebp");
+
+&set_label("tail_loop");
+ &movb ("al",&BP(0,"esp","ebp"));
+ &movb ("dl",&BP(0,$inp,"ebp"));
+ &lea ("ebp",&DWP(1,"ebp"));
+ &xor ("al","dl");
+ &movb (&BP(-1,$out,"ebp"),"al");
+ &dec ($len);
+ &jnz (&label("tail_loop"));
+}
+&set_label("done");
+ &mov ("esp",&DWP(512,"esp"));
+&function_end("ChaCha20_ssse3");
+
+&align (64);
+&set_label("ssse3_data");
+&data_byte(0x2,0x3,0x0,0x1, 0x6,0x7,0x4,0x5, 0xa,0xb,0x8,0x9, 0xe,0xf,0xc,0xd);
+&data_byte(0x3,0x0,0x1,0x2, 0x7,0x4,0x5,0x6, 0xb,0x8,0x9,0xa, 0xf,0xc,0xd,0xe);
+&data_word(0x61707865,0x3320646e,0x79622d32,0x6b206574);
+&data_word(0,1,2,3);
+&data_word(4,4,4,4);
+&data_word(1,0,0,0);
+&data_word(4,0,0,0);
+&data_word(0,-1,-1,-1);
+&align (64);
+}
+&asciz ("ChaCha20 for x86, CRYPTOGAMS by <appro\@openssl.org>");
+
+&asm_finish();
diff --git a/crypto/chacha/asm/chacha-x86_64.pl b/crypto/chacha/asm/chacha-x86_64.pl
new file mode 100755
index 00000000..55b726d2
--- /dev/null
+++ b/crypto/chacha/asm/chacha-x86_64.pl
@@ -0,0 +1,1767 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# November 2014
+#
+# ChaCha20 for x86_64.
+#
+# Performance in cycles per byte out of large buffer.
+#
+# IALU/gcc 4.8(i) 1xSSSE3/SSE2 4xSSSE3 8xAVX2
+#
+# P4 9.48/+99% -/22.7(ii) -
+# Core2 7.83/+55% 7.90/8.08 4.35
+# Westmere 7.19/+50% 5.60/6.70 3.00
+# Sandy Bridge 8.31/+42% 5.45/6.76 2.72
+# Ivy Bridge 6.71/+46% 5.40/6.49 2.41
+# Haswell 5.92/+43% 5.20/6.45 2.42 1.23
+# Silvermont 12.0/+33% 7.75/7.40 7.03(iii)
+# Sledgehammer 7.28/+52% -/14.2(ii) -
+# Bulldozer 9.66/+28% 9.85/11.1 3.06(iv)
+# VIA Nano 10.5/+46% 6.72/8.60 6.05
+#
+# (i) compared to older gcc 3.x one can observe >2x improvement on
+# most platforms;
+# (ii) as it can be seen, SSE2 performance is too low on legacy
+# processors; NxSSE2 results are naturally better, but not
+# impressively better than IALU ones, which is why you won't
+# find SSE2 code below;
+# (iii) this is not optimal result for Atom because of MSROM
+# limitations, SSE2 can do better, but gain is considered too
+# low to justify the [maintenance] effort;
+# (iv) Bulldozer actually executes 4xXOP code path that delivers 2.20;
+#
+# Modified from upstream OpenSSL to remove the XOP code.
+
+$flavour = shift;
+$output = shift;
+if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
+
+$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
+( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
+die "can't locate x86_64-xlate.pl";
+
+$avx = 2;
+
+open OUT,"| \"$^X\" $xlate $flavour $output";
+*STDOUT=*OUT;
+
+# input parameter block
+($out,$inp,$len,$key,$counter)=("%rdi","%rsi","%rdx","%rcx","%r8");
+
+$code.=<<___;
+.text
+
+.extern OPENSSL_ia32cap_P
+
+.align 64
+.Lzero:
+.long 0,0,0,0
+.Lone:
+.long 1,0,0,0
+.Linc:
+.long 0,1,2,3
+.Lfour:
+.long 4,4,4,4
+.Lincy:
+.long 0,2,4,6,1,3,5,7
+.Leight:
+.long 8,8,8,8,8,8,8,8
+.Lrot16:
+.byte 0x2,0x3,0x0,0x1, 0x6,0x7,0x4,0x5, 0xa,0xb,0x8,0x9, 0xe,0xf,0xc,0xd
+.Lrot24:
+.byte 0x3,0x0,0x1,0x2, 0x7,0x4,0x5,0x6, 0xb,0x8,0x9,0xa, 0xf,0xc,0xd,0xe
+.Lsigma:
+.asciz "expand 32-byte k"
+.asciz "ChaCha20 for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+___
+
+sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm
+{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
+ my $arg = pop;
+ $arg = "\$$arg" if ($arg*1 eq $arg);
+ $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
+}
+
+@x=("%eax","%ebx","%ecx","%edx",map("%r${_}d",(8..11)),
+ "%nox","%nox","%nox","%nox",map("%r${_}d",(12..15)));
+@t=("%esi","%edi");
+
+sub ROUND { # critical path is 24 cycles per round
+my ($a0,$b0,$c0,$d0)=@_;
+my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
+my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
+my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
+my ($xc,$xc_)=map("\"$_\"",@t);
+my @x=map("\"$_\"",@x);
+
+ # Consider order in which variables are addressed by their
+ # index:
+ #
+ # a b c d
+ #
+ # 0 4 8 12 < even round
+ # 1 5 9 13
+ # 2 6 10 14
+ # 3 7 11 15
+ # 0 5 10 15 < odd round
+ # 1 6 11 12
+ # 2 7 8 13
+ # 3 4 9 14
+ #
+ # 'a', 'b' and 'd's are permanently allocated in registers,
+ # @x[0..7,12..15], while 'c's are maintained in memory. If
+ # you observe 'c' column, you'll notice that pair of 'c's is
+ # invariant between rounds. This means that we have to reload
+ # them once per round, in the middle. This is why you'll see
+ # bunch of 'c' stores and loads in the middle, but none in
+ # the beginning or end.
+
+ # Normally instructions would be interleaved to favour in-order
+ # execution. Generally out-of-order cores manage it gracefully,
+ # but not this time for some reason. As in-order execution
+ # cores are dying breed, old Atom is the only one around,
+ # instructions are left uninterleaved. Besides, Atom is better
+ # off executing 1xSSSE3 code anyway...
+
+ (
+ "&add (@x[$a0],@x[$b0])", # Q1
+ "&xor (@x[$d0],@x[$a0])",
+ "&rol (@x[$d0],16)",
+ "&add (@x[$a1],@x[$b1])", # Q2
+ "&xor (@x[$d1],@x[$a1])",
+ "&rol (@x[$d1],16)",
+
+ "&add ($xc,@x[$d0])",
+ "&xor (@x[$b0],$xc)",
+ "&rol (@x[$b0],12)",
+ "&add ($xc_,@x[$d1])",
+ "&xor (@x[$b1],$xc_)",
+ "&rol (@x[$b1],12)",
+
+ "&add (@x[$a0],@x[$b0])",
+ "&xor (@x[$d0],@x[$a0])",
+ "&rol (@x[$d0],8)",
+ "&add (@x[$a1],@x[$b1])",
+ "&xor (@x[$d1],@x[$a1])",
+ "&rol (@x[$d1],8)",
+
+ "&add ($xc,@x[$d0])",
+ "&xor (@x[$b0],$xc)",
+ "&rol (@x[$b0],7)",
+ "&add ($xc_,@x[$d1])",
+ "&xor (@x[$b1],$xc_)",
+ "&rol (@x[$b1],7)",
+
+ "&mov (\"4*$c0(%rsp)\",$xc)", # reload pair of 'c's
+ "&mov (\"4*$c1(%rsp)\",$xc_)",
+ "&mov ($xc,\"4*$c2(%rsp)\")",
+ "&mov ($xc_,\"4*$c3(%rsp)\")",
+
+ "&add (@x[$a2],@x[$b2])", # Q3
+ "&xor (@x[$d2],@x[$a2])",
+ "&rol (@x[$d2],16)",
+ "&add (@x[$a3],@x[$b3])", # Q4
+ "&xor (@x[$d3],@x[$a3])",
+ "&rol (@x[$d3],16)",
+
+ "&add ($xc,@x[$d2])",
+ "&xor (@x[$b2],$xc)",
+ "&rol (@x[$b2],12)",
+ "&add ($xc_,@x[$d3])",
+ "&xor (@x[$b3],$xc_)",
+ "&rol (@x[$b3],12)",
+
+ "&add (@x[$a2],@x[$b2])",
+ "&xor (@x[$d2],@x[$a2])",
+ "&rol (@x[$d2],8)",
+ "&add (@x[$a3],@x[$b3])",
+ "&xor (@x[$d3],@x[$a3])",
+ "&rol (@x[$d3],8)",
+
+ "&add ($xc,@x[$d2])",
+ "&xor (@x[$b2],$xc)",
+ "&rol (@x[$b2],7)",
+ "&add ($xc_,@x[$d3])",
+ "&xor (@x[$b3],$xc_)",
+ "&rol (@x[$b3],7)"
+ );
+}
+
+########################################################################
+# Generic code path that handles all lengths on pre-SSSE3 processors.
+$code.=<<___;
+.globl ChaCha20_ctr32
+.type ChaCha20_ctr32,\@function,5
+.align 64
+ChaCha20_ctr32:
+ cmp \$0,$len
+ je .Lno_data
+ mov OPENSSL_ia32cap_P+4(%rip),%r10
+ test \$`1<<(41-32)`,%r10d
+ jnz .LChaCha20_ssse3
+
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ sub \$64+24,%rsp
+
+ #movdqa .Lsigma(%rip),%xmm0
+ movdqu ($key),%xmm1
+ movdqu 16($key),%xmm2
+ movdqu ($counter),%xmm3
+ movdqa .Lone(%rip),%xmm4
+
+ #movdqa %xmm0,4*0(%rsp) # key[0]
+ movdqa %xmm1,4*4(%rsp) # key[1]
+ movdqa %xmm2,4*8(%rsp) # key[2]
+ movdqa %xmm3,4*12(%rsp) # key[3]
+ mov $len,%rbp # reassign $len
+ jmp .Loop_outer
+
+.align 32
+.Loop_outer:
+ mov \$0x61707865,@x[0] # 'expa'
+ mov \$0x3320646e,@x[1] # 'nd 3'
+ mov \$0x79622d32,@x[2] # '2-by'
+ mov \$0x6b206574,@x[3] # 'te k'
+ mov 4*4(%rsp),@x[4]
+ mov 4*5(%rsp),@x[5]
+ mov 4*6(%rsp),@x[6]
+ mov 4*7(%rsp),@x[7]
+ movd %xmm3,@x[12]
+ mov 4*13(%rsp),@x[13]
+ mov 4*14(%rsp),@x[14]
+ mov 4*15(%rsp),@x[15]
+
+ mov %rbp,64+0(%rsp) # save len
+ mov \$10,%ebp
+ mov $inp,64+8(%rsp) # save inp
+ movq %xmm2,%rsi # "@x[8]"
+ mov $out,64+16(%rsp) # save out
+ mov %rsi,%rdi
+ shr \$32,%rdi # "@x[9]"
+ jmp .Loop
+
+.align 32
+.Loop:
+___
+ foreach (&ROUND (0, 4, 8,12)) { eval; }
+ foreach (&ROUND (0, 5,10,15)) { eval; }
+ &dec ("%ebp");
+ &jnz (".Loop");
+
+$code.=<<___;
+ mov @t[1],4*9(%rsp) # modulo-scheduled
+ mov @t[0],4*8(%rsp)
+ mov 64(%rsp),%rbp # load len
+ movdqa %xmm2,%xmm1
+ mov 64+8(%rsp),$inp # load inp
+ paddd %xmm4,%xmm3 # increment counter
+ mov 64+16(%rsp),$out # load out
+
+ add \$0x61707865,@x[0] # 'expa'
+ add \$0x3320646e,@x[1] # 'nd 3'
+ add \$0x79622d32,@x[2] # '2-by'
+ add \$0x6b206574,@x[3] # 'te k'
+ add 4*4(%rsp),@x[4]
+ add 4*5(%rsp),@x[5]
+ add 4*6(%rsp),@x[6]
+ add 4*7(%rsp),@x[7]
+ add 4*12(%rsp),@x[12]
+ add 4*13(%rsp),@x[13]
+ add 4*14(%rsp),@x[14]
+ add 4*15(%rsp),@x[15]
+ paddd 4*8(%rsp),%xmm1
+
+ cmp \$64,%rbp
+ jb .Ltail
+
+ xor 4*0($inp),@x[0] # xor with input
+ xor 4*1($inp),@x[1]
+ xor 4*2($inp),@x[2]
+ xor 4*3($inp),@x[3]
+ xor 4*4($inp),@x[4]
+ xor 4*5($inp),@x[5]
+ xor 4*6($inp),@x[6]
+ xor 4*7($inp),@x[7]
+ movdqu 4*8($inp),%xmm0
+ xor 4*12($inp),@x[12]
+ xor 4*13($inp),@x[13]
+ xor 4*14($inp),@x[14]
+ xor 4*15($inp),@x[15]
+ lea 4*16($inp),$inp # inp+=64
+ pxor %xmm1,%xmm0
+
+ movdqa %xmm2,4*8(%rsp)
+ movd %xmm3,4*12(%rsp)
+
+ mov @x[0],4*0($out) # write output
+ mov @x[1],4*1($out)
+ mov @x[2],4*2($out)
+ mov @x[3],4*3($out)
+ mov @x[4],4*4($out)
+ mov @x[5],4*5($out)
+ mov @x[6],4*6($out)
+ mov @x[7],4*7($out)
+ movdqu %xmm0,4*8($out)
+ mov @x[12],4*12($out)
+ mov @x[13],4*13($out)
+ mov @x[14],4*14($out)
+ mov @x[15],4*15($out)
+ lea 4*16($out),$out # out+=64
+
+ sub \$64,%rbp
+ jnz .Loop_outer
+
+ jmp .Ldone
+
+.align 16
+.Ltail:
+ mov @x[0],4*0(%rsp)
+ mov @x[1],4*1(%rsp)
+ xor %rbx,%rbx
+ mov @x[2],4*2(%rsp)
+ mov @x[3],4*3(%rsp)
+ mov @x[4],4*4(%rsp)
+ mov @x[5],4*5(%rsp)
+ mov @x[6],4*6(%rsp)
+ mov @x[7],4*7(%rsp)
+ movdqa %xmm1,4*8(%rsp)
+ mov @x[12],4*12(%rsp)
+ mov @x[13],4*13(%rsp)
+ mov @x[14],4*14(%rsp)
+ mov @x[15],4*15(%rsp)
+
+.Loop_tail:
+ movzb ($inp,%rbx),%eax
+ movzb (%rsp,%rbx),%edx
+ lea 1(%rbx),%rbx
+ xor %edx,%eax
+ mov %al,-1($out,%rbx)
+ dec %rbp
+ jnz .Loop_tail
+
+.Ldone:
+ add \$64+24,%rsp
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+.Lno_data:
+ ret
+.size ChaCha20_ctr32,.-ChaCha20_ctr32
+___
+
+########################################################################
+# SSSE3 code path that handles shorter lengths
+{
+my ($a,$b,$c,$d,$t,$t1,$rot16,$rot24)=map("%xmm$_",(0..7));
+
+sub SSSE3ROUND { # critical path is 20 "SIMD ticks" per round
+ &paddd ($a,$b);
+ &pxor ($d,$a);
+ &pshufb ($d,$rot16);
+
+ &paddd ($c,$d);
+ &pxor ($b,$c);
+ &movdqa ($t,$b);
+ &psrld ($b,20);
+ &pslld ($t,12);
+ &por ($b,$t);
+
+ &paddd ($a,$b);
+ &pxor ($d,$a);
+ &pshufb ($d,$rot24);
+
+ &paddd ($c,$d);
+ &pxor ($b,$c);
+ &movdqa ($t,$b);
+ &psrld ($b,25);
+ &pslld ($t,7);
+ &por ($b,$t);
+}
+
+my $xframe = $win64 ? 32+32+8 : 24;
+
+$code.=<<___;
+.type ChaCha20_ssse3,\@function,5
+.align 32
+ChaCha20_ssse3:
+.LChaCha20_ssse3:
+___
+$code.=<<___;
+ cmp \$128,$len # we might throw away some data,
+ ja .LChaCha20_4x # but overall it won't be slower
+
+.Ldo_sse3_after_all:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ sub \$64+$xframe,%rsp
+___
+$code.=<<___ if ($win64);
+ movaps %xmm6,64+32(%rsp)
+ movaps %xmm7,64+48(%rsp)
+___
+$code.=<<___;
+ movdqa .Lsigma(%rip),$a
+ movdqu ($key),$b
+ movdqu 16($key),$c
+ movdqu ($counter),$d
+ movdqa .Lrot16(%rip),$rot16
+ movdqa .Lrot24(%rip),$rot24
+
+ movdqa $a,0x00(%rsp)
+ movdqa $b,0x10(%rsp)
+ movdqa $c,0x20(%rsp)
+ movdqa $d,0x30(%rsp)
+ mov \$10,%ebp
+ jmp .Loop_ssse3
+
+.align 32
+.Loop_outer_ssse3:
+ movdqa .Lone(%rip),$d
+ movdqa 0x00(%rsp),$a
+ movdqa 0x10(%rsp),$b
+ movdqa 0x20(%rsp),$c
+ paddd 0x30(%rsp),$d
+ mov \$10,%ebp
+ movdqa $d,0x30(%rsp)
+ jmp .Loop_ssse3
+
+.align 32
+.Loop_ssse3:
+___
+ &SSSE3ROUND();
+ &pshufd ($c,$c,0b01001110);
+ &pshufd ($b,$b,0b00111001);
+ &pshufd ($d,$d,0b10010011);
+ &nop ();
+
+ &SSSE3ROUND();
+ &pshufd ($c,$c,0b01001110);
+ &pshufd ($b,$b,0b10010011);
+ &pshufd ($d,$d,0b00111001);
+
+ &dec ("%ebp");
+ &jnz (".Loop_ssse3");
+
+$code.=<<___;
+ paddd 0x00(%rsp),$a
+ paddd 0x10(%rsp),$b
+ paddd 0x20(%rsp),$c
+ paddd 0x30(%rsp),$d
+
+ cmp \$64,$len
+ jb .Ltail_ssse3
+
+ movdqu 0x00($inp),$t
+ movdqu 0x10($inp),$t1
+ pxor $t,$a # xor with input
+ movdqu 0x20($inp),$t
+ pxor $t1,$b
+ movdqu 0x30($inp),$t1
+ lea 0x40($inp),$inp # inp+=64
+ pxor $t,$c
+ pxor $t1,$d
+
+ movdqu $a,0x00($out) # write output
+ movdqu $b,0x10($out)
+ movdqu $c,0x20($out)
+ movdqu $d,0x30($out)
+ lea 0x40($out),$out # out+=64
+
+ sub \$64,$len
+ jnz .Loop_outer_ssse3
+
+ jmp .Ldone_ssse3
+
+.align 16
+.Ltail_ssse3:
+ movdqa $a,0x00(%rsp)
+ movdqa $b,0x10(%rsp)
+ movdqa $c,0x20(%rsp)
+ movdqa $d,0x30(%rsp)
+ xor %rbx,%rbx
+
+.Loop_tail_ssse3:
+ movzb ($inp,%rbx),%eax
+ movzb (%rsp,%rbx),%ecx
+ lea 1(%rbx),%rbx
+ xor %ecx,%eax
+ mov %al,-1($out,%rbx)
+ dec $len
+ jnz .Loop_tail_ssse3
+
+.Ldone_ssse3:
+___
+$code.=<<___ if ($win64);
+ movaps 64+32(%rsp),%xmm6
+ movaps 64+48(%rsp),%xmm7
+___
+$code.=<<___;
+ add \$64+$xframe,%rsp
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ ret
+.size ChaCha20_ssse3,.-ChaCha20_ssse3
+___
+}
+
+########################################################################
+# SSSE3 code path that handles longer messages.
+{
+# assign variables to favor Atom front-end
+my ($xd0,$xd1,$xd2,$xd3, $xt0,$xt1,$xt2,$xt3,
+ $xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3)=map("%xmm$_",(0..15));
+my @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
+ "%nox","%nox","%nox","%nox", $xd0,$xd1,$xd2,$xd3);
+
+sub SSSE3_lane_ROUND {
+my ($a0,$b0,$c0,$d0)=@_;
+my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
+my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
+my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
+my ($xc,$xc_,$t0,$t1)=map("\"$_\"",$xt0,$xt1,$xt2,$xt3);
+my @x=map("\"$_\"",@xx);
+
+ # Consider order in which variables are addressed by their
+ # index:
+ #
+ # a b c d
+ #
+ # 0 4 8 12 < even round
+ # 1 5 9 13
+ # 2 6 10 14
+ # 3 7 11 15
+ # 0 5 10 15 < odd round
+ # 1 6 11 12
+ # 2 7 8 13
+ # 3 4 9 14
+ #
+ # 'a', 'b' and 'd's are permanently allocated in registers,
+ # @x[0..7,12..15], while 'c's are maintained in memory. If
+ # you observe 'c' column, you'll notice that pair of 'c's is
+ # invariant between rounds. This means that we have to reload
+ # them once per round, in the middle. This is why you'll see
+ # bunch of 'c' stores and loads in the middle, but none in
+ # the beginning or end.
+
+ (
+ "&paddd (@x[$a0],@x[$b0])", # Q1
+ "&paddd (@x[$a1],@x[$b1])", # Q2
+ "&pxor (@x[$d0],@x[$a0])",
+ "&pxor (@x[$d1],@x[$a1])",
+ "&pshufb (@x[$d0],$t1)",
+ "&pshufb (@x[$d1],$t1)",
+
+ "&paddd ($xc,@x[$d0])",
+ "&paddd ($xc_,@x[$d1])",
+ "&pxor (@x[$b0],$xc)",
+ "&pxor (@x[$b1],$xc_)",
+ "&movdqa ($t0,@x[$b0])",
+ "&pslld (@x[$b0],12)",
+ "&psrld ($t0,20)",
+ "&movdqa ($t1,@x[$b1])",
+ "&pslld (@x[$b1],12)",
+ "&por (@x[$b0],$t0)",
+ "&psrld ($t1,20)",
+ "&movdqa ($t0,'(%r11)')", # .Lrot24(%rip)
+ "&por (@x[$b1],$t1)",
+
+ "&paddd (@x[$a0],@x[$b0])",
+ "&paddd (@x[$a1],@x[$b1])",
+ "&pxor (@x[$d0],@x[$a0])",
+ "&pxor (@x[$d1],@x[$a1])",
+ "&pshufb (@x[$d0],$t0)",
+ "&pshufb (@x[$d1],$t0)",
+
+ "&paddd ($xc,@x[$d0])",
+ "&paddd ($xc_,@x[$d1])",
+ "&pxor (@x[$b0],$xc)",
+ "&pxor (@x[$b1],$xc_)",
+ "&movdqa ($t1,@x[$b0])",
+ "&pslld (@x[$b0],7)",
+ "&psrld ($t1,25)",
+ "&movdqa ($t0,@x[$b1])",
+ "&pslld (@x[$b1],7)",
+ "&por (@x[$b0],$t1)",
+ "&psrld ($t0,25)",
+ "&movdqa ($t1,'(%r10)')", # .Lrot16(%rip)
+ "&por (@x[$b1],$t0)",
+
+ "&movdqa (\"`16*($c0-8)`(%rsp)\",$xc)", # reload pair of 'c's
+ "&movdqa (\"`16*($c1-8)`(%rsp)\",$xc_)",
+ "&movdqa ($xc,\"`16*($c2-8)`(%rsp)\")",
+ "&movdqa ($xc_,\"`16*($c3-8)`(%rsp)\")",
+
+ "&paddd (@x[$a2],@x[$b2])", # Q3
+ "&paddd (@x[$a3],@x[$b3])", # Q4
+ "&pxor (@x[$d2],@x[$a2])",
+ "&pxor (@x[$d3],@x[$a3])",
+ "&pshufb (@x[$d2],$t1)",
+ "&pshufb (@x[$d3],$t1)",
+
+ "&paddd ($xc,@x[$d2])",
+ "&paddd ($xc_,@x[$d3])",
+ "&pxor (@x[$b2],$xc)",
+ "&pxor (@x[$b3],$xc_)",
+ "&movdqa ($t0,@x[$b2])",
+ "&pslld (@x[$b2],12)",
+ "&psrld ($t0,20)",
+ "&movdqa ($t1,@x[$b3])",
+ "&pslld (@x[$b3],12)",
+ "&por (@x[$b2],$t0)",
+ "&psrld ($t1,20)",
+ "&movdqa ($t0,'(%r11)')", # .Lrot24(%rip)
+ "&por (@x[$b3],$t1)",
+
+ "&paddd (@x[$a2],@x[$b2])",
+ "&paddd (@x[$a3],@x[$b3])",
+ "&pxor (@x[$d2],@x[$a2])",
+ "&pxor (@x[$d3],@x[$a3])",
+ "&pshufb (@x[$d2],$t0)",
+ "&pshufb (@x[$d3],$t0)",
+
+ "&paddd ($xc,@x[$d2])",
+ "&paddd ($xc_,@x[$d3])",
+ "&pxor (@x[$b2],$xc)",
+ "&pxor (@x[$b3],$xc_)",
+ "&movdqa ($t1,@x[$b2])",
+ "&pslld (@x[$b2],7)",
+ "&psrld ($t1,25)",
+ "&movdqa ($t0,@x[$b3])",
+ "&pslld (@x[$b3],7)",
+ "&por (@x[$b2],$t1)",
+ "&psrld ($t0,25)",
+ "&movdqa ($t1,'(%r10)')", # .Lrot16(%rip)
+ "&por (@x[$b3],$t0)"
+ );
+}
+
+my $xframe = $win64 ? 0xa0 : 0;
+
+$code.=<<___;
+.type ChaCha20_4x,\@function,5
+.align 32
+ChaCha20_4x:
+.LChaCha20_4x:
+ mov %r10,%r11
+___
+$code.=<<___ if ($avx>1);
+ shr \$32,%r10 # OPENSSL_ia32cap_P+8
+ test \$`1<<5`,%r10 # test AVX2
+ jnz .LChaCha20_8x
+___
+$code.=<<___;
+ cmp \$192,$len
+ ja .Lproceed4x
+
+ and \$`1<<26|1<<22`,%r11 # isolate XSAVE+MOVBE
+ cmp \$`1<<22`,%r11 # check for MOVBE without XSAVE
+ je .Ldo_sse3_after_all # to detect Atom
+
+.Lproceed4x:
+ lea -0x78(%rsp),%r11
+ sub \$0x148+$xframe,%rsp
+___
+ ################ stack layout
+ # +0x00 SIMD equivalent of @x[8-12]
+ # ...
+ # +0x40 constant copy of key[0-2] smashed by lanes
+ # ...
+ # +0x100 SIMD counters (with nonce smashed by lanes)
+ # ...
+ # +0x140
+$code.=<<___ if ($win64);
+ movaps %xmm6,-0x30(%r11)
+ movaps %xmm7,-0x20(%r11)
+ movaps %xmm8,-0x10(%r11)
+ movaps %xmm9,0x00(%r11)
+ movaps %xmm10,0x10(%r11)
+ movaps %xmm11,0x20(%r11)
+ movaps %xmm12,0x30(%r11)
+ movaps %xmm13,0x40(%r11)
+ movaps %xmm14,0x50(%r11)
+ movaps %xmm15,0x60(%r11)
+___
+$code.=<<___;
+ movdqa .Lsigma(%rip),$xa3 # key[0]
+ movdqu ($key),$xb3 # key[1]
+ movdqu 16($key),$xt3 # key[2]
+ movdqu ($counter),$xd3 # key[3]
+ lea 0x100(%rsp),%rcx # size optimization
+ lea .Lrot16(%rip),%r10
+ lea .Lrot24(%rip),%r11
+
+ pshufd \$0x00,$xa3,$xa0 # smash key by lanes...
+ pshufd \$0x55,$xa3,$xa1
+ movdqa $xa0,0x40(%rsp) # ... and offload
+ pshufd \$0xaa,$xa3,$xa2
+ movdqa $xa1,0x50(%rsp)
+ pshufd \$0xff,$xa3,$xa3
+ movdqa $xa2,0x60(%rsp)
+ movdqa $xa3,0x70(%rsp)
+
+ pshufd \$0x00,$xb3,$xb0
+ pshufd \$0x55,$xb3,$xb1
+ movdqa $xb0,0x80-0x100(%rcx)
+ pshufd \$0xaa,$xb3,$xb2
+ movdqa $xb1,0x90-0x100(%rcx)
+ pshufd \$0xff,$xb3,$xb3
+ movdqa $xb2,0xa0-0x100(%rcx)
+ movdqa $xb3,0xb0-0x100(%rcx)
+
+ pshufd \$0x00,$xt3,$xt0 # "$xc0"
+ pshufd \$0x55,$xt3,$xt1 # "$xc1"
+ movdqa $xt0,0xc0-0x100(%rcx)
+ pshufd \$0xaa,$xt3,$xt2 # "$xc2"
+ movdqa $xt1,0xd0-0x100(%rcx)
+ pshufd \$0xff,$xt3,$xt3 # "$xc3"
+ movdqa $xt2,0xe0-0x100(%rcx)
+ movdqa $xt3,0xf0-0x100(%rcx)
+
+ pshufd \$0x00,$xd3,$xd0
+ pshufd \$0x55,$xd3,$xd1
+ paddd .Linc(%rip),$xd0 # don't save counters yet
+ pshufd \$0xaa,$xd3,$xd2
+ movdqa $xd1,0x110-0x100(%rcx)
+ pshufd \$0xff,$xd3,$xd3
+ movdqa $xd2,0x120-0x100(%rcx)
+ movdqa $xd3,0x130-0x100(%rcx)
+
+ jmp .Loop_enter4x
+
+.align 32
+.Loop_outer4x:
+ movdqa 0x40(%rsp),$xa0 # re-load smashed key
+ movdqa 0x50(%rsp),$xa1
+ movdqa 0x60(%rsp),$xa2
+ movdqa 0x70(%rsp),$xa3
+ movdqa 0x80-0x100(%rcx),$xb0
+ movdqa 0x90-0x100(%rcx),$xb1
+ movdqa 0xa0-0x100(%rcx),$xb2
+ movdqa 0xb0-0x100(%rcx),$xb3
+ movdqa 0xc0-0x100(%rcx),$xt0 # "$xc0"
+ movdqa 0xd0-0x100(%rcx),$xt1 # "$xc1"
+ movdqa 0xe0-0x100(%rcx),$xt2 # "$xc2"
+ movdqa 0xf0-0x100(%rcx),$xt3 # "$xc3"
+ movdqa 0x100-0x100(%rcx),$xd0
+ movdqa 0x110-0x100(%rcx),$xd1
+ movdqa 0x120-0x100(%rcx),$xd2
+ movdqa 0x130-0x100(%rcx),$xd3
+ paddd .Lfour(%rip),$xd0 # next SIMD counters
+
+.Loop_enter4x:
+ movdqa $xt2,0x20(%rsp) # SIMD equivalent of "@x[10]"
+ movdqa $xt3,0x30(%rsp) # SIMD equivalent of "@x[11]"
+ movdqa (%r10),$xt3 # .Lrot16(%rip)
+ mov \$10,%eax
+ movdqa $xd0,0x100-0x100(%rcx) # save SIMD counters
+ jmp .Loop4x
+
+.align 32
+.Loop4x:
+___
+ foreach (&SSSE3_lane_ROUND(0, 4, 8,12)) { eval; }
+ foreach (&SSSE3_lane_ROUND(0, 5,10,15)) { eval; }
+$code.=<<___;
+ dec %eax
+ jnz .Loop4x
+
+ paddd 0x40(%rsp),$xa0 # accumulate key material
+ paddd 0x50(%rsp),$xa1
+ paddd 0x60(%rsp),$xa2
+ paddd 0x70(%rsp),$xa3
+
+ movdqa $xa0,$xt2 # "de-interlace" data
+ punpckldq $xa1,$xa0
+ movdqa $xa2,$xt3
+ punpckldq $xa3,$xa2
+ punpckhdq $xa1,$xt2
+ punpckhdq $xa3,$xt3
+ movdqa $xa0,$xa1
+ punpcklqdq $xa2,$xa0 # "a0"
+ movdqa $xt2,$xa3
+ punpcklqdq $xt3,$xt2 # "a2"
+ punpckhqdq $xa2,$xa1 # "a1"
+ punpckhqdq $xt3,$xa3 # "a3"
+___
+ ($xa2,$xt2)=($xt2,$xa2);
+$code.=<<___;
+ paddd 0x80-0x100(%rcx),$xb0
+ paddd 0x90-0x100(%rcx),$xb1
+ paddd 0xa0-0x100(%rcx),$xb2
+ paddd 0xb0-0x100(%rcx),$xb3
+
+ movdqa $xa0,0x00(%rsp) # offload $xaN
+ movdqa $xa1,0x10(%rsp)
+ movdqa 0x20(%rsp),$xa0 # "xc2"
+ movdqa 0x30(%rsp),$xa1 # "xc3"
+
+ movdqa $xb0,$xt2
+ punpckldq $xb1,$xb0
+ movdqa $xb2,$xt3
+ punpckldq $xb3,$xb2
+ punpckhdq $xb1,$xt2
+ punpckhdq $xb3,$xt3
+ movdqa $xb0,$xb1
+ punpcklqdq $xb2,$xb0 # "b0"
+ movdqa $xt2,$xb3
+ punpcklqdq $xt3,$xt2 # "b2"
+ punpckhqdq $xb2,$xb1 # "b1"
+ punpckhqdq $xt3,$xb3 # "b3"
+___
+ ($xb2,$xt2)=($xt2,$xb2);
+ my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
+$code.=<<___;
+ paddd 0xc0-0x100(%rcx),$xc0
+ paddd 0xd0-0x100(%rcx),$xc1
+ paddd 0xe0-0x100(%rcx),$xc2
+ paddd 0xf0-0x100(%rcx),$xc3
+
+ movdqa $xa2,0x20(%rsp) # keep offloading $xaN
+ movdqa $xa3,0x30(%rsp)
+
+ movdqa $xc0,$xt2
+ punpckldq $xc1,$xc0
+ movdqa $xc2,$xt3
+ punpckldq $xc3,$xc2
+ punpckhdq $xc1,$xt2
+ punpckhdq $xc3,$xt3
+ movdqa $xc0,$xc1
+ punpcklqdq $xc2,$xc0 # "c0"
+ movdqa $xt2,$xc3
+ punpcklqdq $xt3,$xt2 # "c2"
+ punpckhqdq $xc2,$xc1 # "c1"
+ punpckhqdq $xt3,$xc3 # "c3"
+___
+ ($xc2,$xt2)=($xt2,$xc2);
+ ($xt0,$xt1)=($xa2,$xa3); # use $xaN as temporary
+$code.=<<___;
+ paddd 0x100-0x100(%rcx),$xd0
+ paddd 0x110-0x100(%rcx),$xd1
+ paddd 0x120-0x100(%rcx),$xd2
+ paddd 0x130-0x100(%rcx),$xd3
+
+ movdqa $xd0,$xt2
+ punpckldq $xd1,$xd0
+ movdqa $xd2,$xt3
+ punpckldq $xd3,$xd2
+ punpckhdq $xd1,$xt2
+ punpckhdq $xd3,$xt3
+ movdqa $xd0,$xd1
+ punpcklqdq $xd2,$xd0 # "d0"
+ movdqa $xt2,$xd3
+ punpcklqdq $xt3,$xt2 # "d2"
+ punpckhqdq $xd2,$xd1 # "d1"
+ punpckhqdq $xt3,$xd3 # "d3"
+___
+ ($xd2,$xt2)=($xt2,$xd2);
+$code.=<<___;
+ cmp \$64*4,$len
+ jb .Ltail4x
+
+ movdqu 0x00($inp),$xt0 # xor with input
+ movdqu 0x10($inp),$xt1
+ movdqu 0x20($inp),$xt2
+ movdqu 0x30($inp),$xt3
+ pxor 0x00(%rsp),$xt0 # $xaN is offloaded, remember?
+ pxor $xb0,$xt1
+ pxor $xc0,$xt2
+ pxor $xd0,$xt3
+
+ movdqu $xt0,0x00($out)
+ movdqu 0x40($inp),$xt0
+ movdqu $xt1,0x10($out)
+ movdqu 0x50($inp),$xt1
+ movdqu $xt2,0x20($out)
+ movdqu 0x60($inp),$xt2
+ movdqu $xt3,0x30($out)
+ movdqu 0x70($inp),$xt3
+ lea 0x80($inp),$inp # size optimization
+ pxor 0x10(%rsp),$xt0
+ pxor $xb1,$xt1
+ pxor $xc1,$xt2
+ pxor $xd1,$xt3
+
+ movdqu $xt0,0x40($out)
+ movdqu 0x00($inp),$xt0
+ movdqu $xt1,0x50($out)
+ movdqu 0x10($inp),$xt1
+ movdqu $xt2,0x60($out)
+ movdqu 0x20($inp),$xt2
+ movdqu $xt3,0x70($out)
+ lea 0x80($out),$out # size optimization
+ movdqu 0x30($inp),$xt3
+ pxor 0x20(%rsp),$xt0
+ pxor $xb2,$xt1
+ pxor $xc2,$xt2
+ pxor $xd2,$xt3
+
+ movdqu $xt0,0x00($out)
+ movdqu 0x40($inp),$xt0
+ movdqu $xt1,0x10($out)
+ movdqu 0x50($inp),$xt1
+ movdqu $xt2,0x20($out)
+ movdqu 0x60($inp),$xt2
+ movdqu $xt3,0x30($out)
+ movdqu 0x70($inp),$xt3
+ lea 0x80($inp),$inp # inp+=64*4
+ pxor 0x30(%rsp),$xt0
+ pxor $xb3,$xt1
+ pxor $xc3,$xt2
+ pxor $xd3,$xt3
+ movdqu $xt0,0x40($out)
+ movdqu $xt1,0x50($out)
+ movdqu $xt2,0x60($out)
+ movdqu $xt3,0x70($out)
+ lea 0x80($out),$out # out+=64*4
+
+ sub \$64*4,$len
+ jnz .Loop_outer4x
+
+ jmp .Ldone4x
+
+.Ltail4x:
+ cmp \$192,$len
+ jae .L192_or_more4x
+ cmp \$128,$len
+ jae .L128_or_more4x
+ cmp \$64,$len
+ jae .L64_or_more4x
+
+ #movdqa 0x00(%rsp),$xt0 # $xaN is offloaded, remember?
+ xor %r10,%r10
+ #movdqa $xt0,0x00(%rsp)
+ movdqa $xb0,0x10(%rsp)
+ movdqa $xc0,0x20(%rsp)
+ movdqa $xd0,0x30(%rsp)
+ jmp .Loop_tail4x
+
+.align 32
+.L64_or_more4x:
+ movdqu 0x00($inp),$xt0 # xor with input
+ movdqu 0x10($inp),$xt1
+ movdqu 0x20($inp),$xt2
+ movdqu 0x30($inp),$xt3
+ pxor 0x00(%rsp),$xt0 # $xaxN is offloaded, remember?
+ pxor $xb0,$xt1
+ pxor $xc0,$xt2
+ pxor $xd0,$xt3
+ movdqu $xt0,0x00($out)
+ movdqu $xt1,0x10($out)
+ movdqu $xt2,0x20($out)
+ movdqu $xt3,0x30($out)
+ je .Ldone4x
+
+ movdqa 0x10(%rsp),$xt0 # $xaN is offloaded, remember?
+ lea 0x40($inp),$inp # inp+=64*1
+ xor %r10,%r10
+ movdqa $xt0,0x00(%rsp)
+ movdqa $xb1,0x10(%rsp)
+ lea 0x40($out),$out # out+=64*1
+ movdqa $xc1,0x20(%rsp)
+ sub \$64,$len # len-=64*1
+ movdqa $xd1,0x30(%rsp)
+ jmp .Loop_tail4x
+
+.align 32
+.L128_or_more4x:
+ movdqu 0x00($inp),$xt0 # xor with input
+ movdqu 0x10($inp),$xt1
+ movdqu 0x20($inp),$xt2
+ movdqu 0x30($inp),$xt3
+ pxor 0x00(%rsp),$xt0 # $xaN is offloaded, remember?
+ pxor $xb0,$xt1
+ pxor $xc0,$xt2
+ pxor $xd0,$xt3
+
+ movdqu $xt0,0x00($out)
+ movdqu 0x40($inp),$xt0
+ movdqu $xt1,0x10($out)
+ movdqu 0x50($inp),$xt1
+ movdqu $xt2,0x20($out)
+ movdqu 0x60($inp),$xt2
+ movdqu $xt3,0x30($out)
+ movdqu 0x70($inp),$xt3
+ pxor 0x10(%rsp),$xt0
+ pxor $xb1,$xt1
+ pxor $xc1,$xt2
+ pxor $xd1,$xt3
+ movdqu $xt0,0x40($out)
+ movdqu $xt1,0x50($out)
+ movdqu $xt2,0x60($out)
+ movdqu $xt3,0x70($out)
+ je .Ldone4x
+
+ movdqa 0x20(%rsp),$xt0 # $xaN is offloaded, remember?
+ lea 0x80($inp),$inp # inp+=64*2
+ xor %r10,%r10
+ movdqa $xt0,0x00(%rsp)
+ movdqa $xb2,0x10(%rsp)
+ lea 0x80($out),$out # out+=64*2
+ movdqa $xc2,0x20(%rsp)
+ sub \$128,$len # len-=64*2
+ movdqa $xd2,0x30(%rsp)
+ jmp .Loop_tail4x
+
+.align 32
+.L192_or_more4x:
+ movdqu 0x00($inp),$xt0 # xor with input
+ movdqu 0x10($inp),$xt1
+ movdqu 0x20($inp),$xt2
+ movdqu 0x30($inp),$xt3
+ pxor 0x00(%rsp),$xt0 # $xaN is offloaded, remember?
+ pxor $xb0,$xt1
+ pxor $xc0,$xt2
+ pxor $xd0,$xt3
+
+ movdqu $xt0,0x00($out)
+ movdqu 0x40($inp),$xt0
+ movdqu $xt1,0x10($out)
+ movdqu 0x50($inp),$xt1
+ movdqu $xt2,0x20($out)
+ movdqu 0x60($inp),$xt2
+ movdqu $xt3,0x30($out)
+ movdqu 0x70($inp),$xt3
+ lea 0x80($inp),$inp # size optimization
+ pxor 0x10(%rsp),$xt0
+ pxor $xb1,$xt1
+ pxor $xc1,$xt2
+ pxor $xd1,$xt3
+
+ movdqu $xt0,0x40($out)
+ movdqu 0x00($inp),$xt0
+ movdqu $xt1,0x50($out)
+ movdqu 0x10($inp),$xt1
+ movdqu $xt2,0x60($out)
+ movdqu 0x20($inp),$xt2
+ movdqu $xt3,0x70($out)
+ lea 0x80($out),$out # size optimization
+ movdqu 0x30($inp),$xt3
+ pxor 0x20(%rsp),$xt0
+ pxor $xb2,$xt1
+ pxor $xc2,$xt2
+ pxor $xd2,$xt3
+ movdqu $xt0,0x00($out)
+ movdqu $xt1,0x10($out)
+ movdqu $xt2,0x20($out)
+ movdqu $xt3,0x30($out)
+ je .Ldone4x
+
+ movdqa 0x30(%rsp),$xt0 # $xaN is offloaded, remember?
+ lea 0x40($inp),$inp # inp+=64*3
+ xor %r10,%r10
+ movdqa $xt0,0x00(%rsp)
+ movdqa $xb3,0x10(%rsp)
+ lea 0x40($out),$out # out+=64*3
+ movdqa $xc3,0x20(%rsp)
+ sub \$192,$len # len-=64*3
+ movdqa $xd3,0x30(%rsp)
+
+.Loop_tail4x:
+ movzb ($inp,%r10),%eax
+ movzb (%rsp,%r10),%ecx
+ lea 1(%r10),%r10
+ xor %ecx,%eax
+ mov %al,-1($out,%r10)
+ dec $len
+ jnz .Loop_tail4x
+
+.Ldone4x:
+___
+$code.=<<___ if ($win64);
+ lea 0x140+0x30(%rsp),%r11
+ movaps -0x30(%r11),%xmm6
+ movaps -0x20(%r11),%xmm7
+ movaps -0x10(%r11),%xmm8
+ movaps 0x00(%r11),%xmm9
+ movaps 0x10(%r11),%xmm10
+ movaps 0x20(%r11),%xmm11
+ movaps 0x30(%r11),%xmm12
+ movaps 0x40(%r11),%xmm13
+ movaps 0x50(%r11),%xmm14
+ movaps 0x60(%r11),%xmm15
+___
+$code.=<<___;
+ add \$0x148+$xframe,%rsp
+ ret
+.size ChaCha20_4x,.-ChaCha20_4x
+___
+}
+
+########################################################################
+# AVX2 code path
+if ($avx>1) {
+my ($xb0,$xb1,$xb2,$xb3, $xd0,$xd1,$xd2,$xd3,
+ $xa0,$xa1,$xa2,$xa3, $xt0,$xt1,$xt2,$xt3)=map("%ymm$_",(0..15));
+my @xx=($xa0,$xa1,$xa2,$xa3, $xb0,$xb1,$xb2,$xb3,
+ "%nox","%nox","%nox","%nox", $xd0,$xd1,$xd2,$xd3);
+
+sub AVX2_lane_ROUND {
+my ($a0,$b0,$c0,$d0)=@_;
+my ($a1,$b1,$c1,$d1)=map(($_&~3)+(($_+1)&3),($a0,$b0,$c0,$d0));
+my ($a2,$b2,$c2,$d2)=map(($_&~3)+(($_+1)&3),($a1,$b1,$c1,$d1));
+my ($a3,$b3,$c3,$d3)=map(($_&~3)+(($_+1)&3),($a2,$b2,$c2,$d2));
+my ($xc,$xc_,$t0,$t1)=map("\"$_\"",$xt0,$xt1,$xt2,$xt3);
+my @x=map("\"$_\"",@xx);
+
+ # Consider order in which variables are addressed by their
+ # index:
+ #
+ # a b c d
+ #
+ # 0 4 8 12 < even round
+ # 1 5 9 13
+ # 2 6 10 14
+ # 3 7 11 15
+ # 0 5 10 15 < odd round
+ # 1 6 11 12
+ # 2 7 8 13
+ # 3 4 9 14
+ #
+ # 'a', 'b' and 'd's are permanently allocated in registers,
+ # @x[0..7,12..15], while 'c's are maintained in memory. If
+ # you observe 'c' column, you'll notice that pair of 'c's is
+ # invariant between rounds. This means that we have to reload
+ # them once per round, in the middle. This is why you'll see
+ # bunch of 'c' stores and loads in the middle, but none in
+ # the beginning or end.
+
+ (
+ "&vpaddd (@x[$a0],@x[$a0],@x[$b0])", # Q1
+ "&vpxor (@x[$d0],@x[$a0],@x[$d0])",
+ "&vpshufb (@x[$d0],@x[$d0],$t1)",
+ "&vpaddd (@x[$a1],@x[$a1],@x[$b1])", # Q2
+ "&vpxor (@x[$d1],@x[$a1],@x[$d1])",
+ "&vpshufb (@x[$d1],@x[$d1],$t1)",
+
+ "&vpaddd ($xc,$xc,@x[$d0])",
+ "&vpxor (@x[$b0],$xc,@x[$b0])",
+ "&vpslld ($t0,@x[$b0],12)",
+ "&vpsrld (@x[$b0],@x[$b0],20)",
+ "&vpor (@x[$b0],$t0,@x[$b0])",
+ "&vbroadcasti128($t0,'(%r11)')", # .Lrot24(%rip)
+ "&vpaddd ($xc_,$xc_,@x[$d1])",
+ "&vpxor (@x[$b1],$xc_,@x[$b1])",
+ "&vpslld ($t1,@x[$b1],12)",
+ "&vpsrld (@x[$b1],@x[$b1],20)",
+ "&vpor (@x[$b1],$t1,@x[$b1])",
+
+ "&vpaddd (@x[$a0],@x[$a0],@x[$b0])",
+ "&vpxor (@x[$d0],@x[$a0],@x[$d0])",
+ "&vpshufb (@x[$d0],@x[$d0],$t0)",
+ "&vpaddd (@x[$a1],@x[$a1],@x[$b1])",
+ "&vpxor (@x[$d1],@x[$a1],@x[$d1])",
+ "&vpshufb (@x[$d1],@x[$d1],$t0)",
+
+ "&vpaddd ($xc,$xc,@x[$d0])",
+ "&vpxor (@x[$b0],$xc,@x[$b0])",
+ "&vpslld ($t1,@x[$b0],7)",
+ "&vpsrld (@x[$b0],@x[$b0],25)",
+ "&vpor (@x[$b0],$t1,@x[$b0])",
+ "&vbroadcasti128($t1,'(%r10)')", # .Lrot16(%rip)
+ "&vpaddd ($xc_,$xc_,@x[$d1])",
+ "&vpxor (@x[$b1],$xc_,@x[$b1])",
+ "&vpslld ($t0,@x[$b1],7)",
+ "&vpsrld (@x[$b1],@x[$b1],25)",
+ "&vpor (@x[$b1],$t0,@x[$b1])",
+
+ "&vmovdqa (\"`32*($c0-8)`(%rsp)\",$xc)", # reload pair of 'c's
+ "&vmovdqa (\"`32*($c1-8)`(%rsp)\",$xc_)",
+ "&vmovdqa ($xc,\"`32*($c2-8)`(%rsp)\")",
+ "&vmovdqa ($xc_,\"`32*($c3-8)`(%rsp)\")",
+
+ "&vpaddd (@x[$a2],@x[$a2],@x[$b2])", # Q3
+ "&vpxor (@x[$d2],@x[$a2],@x[$d2])",
+ "&vpshufb (@x[$d2],@x[$d2],$t1)",
+ "&vpaddd (@x[$a3],@x[$a3],@x[$b3])", # Q4
+ "&vpxor (@x[$d3],@x[$a3],@x[$d3])",
+ "&vpshufb (@x[$d3],@x[$d3],$t1)",
+
+ "&vpaddd ($xc,$xc,@x[$d2])",
+ "&vpxor (@x[$b2],$xc,@x[$b2])",
+ "&vpslld ($t0,@x[$b2],12)",
+ "&vpsrld (@x[$b2],@x[$b2],20)",
+ "&vpor (@x[$b2],$t0,@x[$b2])",
+ "&vbroadcasti128($t0,'(%r11)')", # .Lrot24(%rip)
+ "&vpaddd ($xc_,$xc_,@x[$d3])",
+ "&vpxor (@x[$b3],$xc_,@x[$b3])",
+ "&vpslld ($t1,@x[$b3],12)",
+ "&vpsrld (@x[$b3],@x[$b3],20)",
+ "&vpor (@x[$b3],$t1,@x[$b3])",
+
+ "&vpaddd (@x[$a2],@x[$a2],@x[$b2])",
+ "&vpxor (@x[$d2],@x[$a2],@x[$d2])",
+ "&vpshufb (@x[$d2],@x[$d2],$t0)",
+ "&vpaddd (@x[$a3],@x[$a3],@x[$b3])",
+ "&vpxor (@x[$d3],@x[$a3],@x[$d3])",
+ "&vpshufb (@x[$d3],@x[$d3],$t0)",
+
+ "&vpaddd ($xc,$xc,@x[$d2])",
+ "&vpxor (@x[$b2],$xc,@x[$b2])",
+ "&vpslld ($t1,@x[$b2],7)",
+ "&vpsrld (@x[$b2],@x[$b2],25)",
+ "&vpor (@x[$b2],$t1,@x[$b2])",
+ "&vbroadcasti128($t1,'(%r10)')", # .Lrot16(%rip)
+ "&vpaddd ($xc_,$xc_,@x[$d3])",
+ "&vpxor (@x[$b3],$xc_,@x[$b3])",
+ "&vpslld ($t0,@x[$b3],7)",
+ "&vpsrld (@x[$b3],@x[$b3],25)",
+ "&vpor (@x[$b3],$t0,@x[$b3])"
+ );
+}
+
+my $xframe = $win64 ? 0xb0 : 8;
+
+$code.=<<___;
+.type ChaCha20_8x,\@function,5
+.align 32
+ChaCha20_8x:
+.LChaCha20_8x:
+ mov %rsp,%r10
+ sub \$0x280+$xframe,%rsp
+ and \$-32,%rsp
+___
+$code.=<<___ if ($win64);
+ lea 0x290+0x30(%rsp),%r11
+ movaps %xmm6,-0x30(%r11)
+ movaps %xmm7,-0x20(%r11)
+ movaps %xmm8,-0x10(%r11)
+ movaps %xmm9,0x00(%r11)
+ movaps %xmm10,0x10(%r11)
+ movaps %xmm11,0x20(%r11)
+ movaps %xmm12,0x30(%r11)
+ movaps %xmm13,0x40(%r11)
+ movaps %xmm14,0x50(%r11)
+ movaps %xmm15,0x60(%r11)
+___
+$code.=<<___;
+ vzeroupper
+ mov %r10,0x280(%rsp)
+
+ ################ stack layout
+ # +0x00 SIMD equivalent of @x[8-12]
+ # ...
+ # +0x80 constant copy of key[0-2] smashed by lanes
+ # ...
+ # +0x200 SIMD counters (with nonce smashed by lanes)
+ # ...
+ # +0x280 saved %rsp
+
+ vbroadcasti128 .Lsigma(%rip),$xa3 # key[0]
+ vbroadcasti128 ($key),$xb3 # key[1]
+ vbroadcasti128 16($key),$xt3 # key[2]
+ vbroadcasti128 ($counter),$xd3 # key[3]
+ lea 0x100(%rsp),%rcx # size optimization
+ lea 0x200(%rsp),%rax # size optimization
+ lea .Lrot16(%rip),%r10
+ lea .Lrot24(%rip),%r11
+
+ vpshufd \$0x00,$xa3,$xa0 # smash key by lanes...
+ vpshufd \$0x55,$xa3,$xa1
+ vmovdqa $xa0,0x80-0x100(%rcx) # ... and offload
+ vpshufd \$0xaa,$xa3,$xa2
+ vmovdqa $xa1,0xa0-0x100(%rcx)
+ vpshufd \$0xff,$xa3,$xa3
+ vmovdqa $xa2,0xc0-0x100(%rcx)
+ vmovdqa $xa3,0xe0-0x100(%rcx)
+
+ vpshufd \$0x00,$xb3,$xb0
+ vpshufd \$0x55,$xb3,$xb1
+ vmovdqa $xb0,0x100-0x100(%rcx)
+ vpshufd \$0xaa,$xb3,$xb2
+ vmovdqa $xb1,0x120-0x100(%rcx)
+ vpshufd \$0xff,$xb3,$xb3
+ vmovdqa $xb2,0x140-0x100(%rcx)
+ vmovdqa $xb3,0x160-0x100(%rcx)
+
+ vpshufd \$0x00,$xt3,$xt0 # "xc0"
+ vpshufd \$0x55,$xt3,$xt1 # "xc1"
+ vmovdqa $xt0,0x180-0x200(%rax)
+ vpshufd \$0xaa,$xt3,$xt2 # "xc2"
+ vmovdqa $xt1,0x1a0-0x200(%rax)
+ vpshufd \$0xff,$xt3,$xt3 # "xc3"
+ vmovdqa $xt2,0x1c0-0x200(%rax)
+ vmovdqa $xt3,0x1e0-0x200(%rax)
+
+ vpshufd \$0x00,$xd3,$xd0
+ vpshufd \$0x55,$xd3,$xd1
+ vpaddd .Lincy(%rip),$xd0,$xd0 # don't save counters yet
+ vpshufd \$0xaa,$xd3,$xd2
+ vmovdqa $xd1,0x220-0x200(%rax)
+ vpshufd \$0xff,$xd3,$xd3
+ vmovdqa $xd2,0x240-0x200(%rax)
+ vmovdqa $xd3,0x260-0x200(%rax)
+
+ jmp .Loop_enter8x
+
+.align 32
+.Loop_outer8x:
+ vmovdqa 0x80-0x100(%rcx),$xa0 # re-load smashed key
+ vmovdqa 0xa0-0x100(%rcx),$xa1
+ vmovdqa 0xc0-0x100(%rcx),$xa2
+ vmovdqa 0xe0-0x100(%rcx),$xa3
+ vmovdqa 0x100-0x100(%rcx),$xb0
+ vmovdqa 0x120-0x100(%rcx),$xb1
+ vmovdqa 0x140-0x100(%rcx),$xb2
+ vmovdqa 0x160-0x100(%rcx),$xb3
+ vmovdqa 0x180-0x200(%rax),$xt0 # "xc0"
+ vmovdqa 0x1a0-0x200(%rax),$xt1 # "xc1"
+ vmovdqa 0x1c0-0x200(%rax),$xt2 # "xc2"
+ vmovdqa 0x1e0-0x200(%rax),$xt3 # "xc3"
+ vmovdqa 0x200-0x200(%rax),$xd0
+ vmovdqa 0x220-0x200(%rax),$xd1
+ vmovdqa 0x240-0x200(%rax),$xd2
+ vmovdqa 0x260-0x200(%rax),$xd3
+ vpaddd .Leight(%rip),$xd0,$xd0 # next SIMD counters
+
+.Loop_enter8x:
+ vmovdqa $xt2,0x40(%rsp) # SIMD equivalent of "@x[10]"
+ vmovdqa $xt3,0x60(%rsp) # SIMD equivalent of "@x[11]"
+ vbroadcasti128 (%r10),$xt3
+ vmovdqa $xd0,0x200-0x200(%rax) # save SIMD counters
+ mov \$10,%eax
+ jmp .Loop8x
+
+.align 32
+.Loop8x:
+___
+ foreach (&AVX2_lane_ROUND(0, 4, 8,12)) { eval; }
+ foreach (&AVX2_lane_ROUND(0, 5,10,15)) { eval; }
+$code.=<<___;
+ dec %eax
+ jnz .Loop8x
+
+ lea 0x200(%rsp),%rax # size optimization
+ vpaddd 0x80-0x100(%rcx),$xa0,$xa0 # accumulate key
+ vpaddd 0xa0-0x100(%rcx),$xa1,$xa1
+ vpaddd 0xc0-0x100(%rcx),$xa2,$xa2
+ vpaddd 0xe0-0x100(%rcx),$xa3,$xa3
+
+ vpunpckldq $xa1,$xa0,$xt2 # "de-interlace" data
+ vpunpckldq $xa3,$xa2,$xt3
+ vpunpckhdq $xa1,$xa0,$xa0
+ vpunpckhdq $xa3,$xa2,$xa2
+ vpunpcklqdq $xt3,$xt2,$xa1 # "a0"
+ vpunpckhqdq $xt3,$xt2,$xt2 # "a1"
+ vpunpcklqdq $xa2,$xa0,$xa3 # "a2"
+ vpunpckhqdq $xa2,$xa0,$xa0 # "a3"
+___
+ ($xa0,$xa1,$xa2,$xa3,$xt2)=($xa1,$xt2,$xa3,$xa0,$xa2);
+$code.=<<___;
+ vpaddd 0x100-0x100(%rcx),$xb0,$xb0
+ vpaddd 0x120-0x100(%rcx),$xb1,$xb1
+ vpaddd 0x140-0x100(%rcx),$xb2,$xb2
+ vpaddd 0x160-0x100(%rcx),$xb3,$xb3
+
+ vpunpckldq $xb1,$xb0,$xt2
+ vpunpckldq $xb3,$xb2,$xt3
+ vpunpckhdq $xb1,$xb0,$xb0
+ vpunpckhdq $xb3,$xb2,$xb2
+ vpunpcklqdq $xt3,$xt2,$xb1 # "b0"
+ vpunpckhqdq $xt3,$xt2,$xt2 # "b1"
+ vpunpcklqdq $xb2,$xb0,$xb3 # "b2"
+ vpunpckhqdq $xb2,$xb0,$xb0 # "b3"
+___
+ ($xb0,$xb1,$xb2,$xb3,$xt2)=($xb1,$xt2,$xb3,$xb0,$xb2);
+$code.=<<___;
+ vperm2i128 \$0x20,$xb0,$xa0,$xt3 # "de-interlace" further
+ vperm2i128 \$0x31,$xb0,$xa0,$xb0
+ vperm2i128 \$0x20,$xb1,$xa1,$xa0
+ vperm2i128 \$0x31,$xb1,$xa1,$xb1
+ vperm2i128 \$0x20,$xb2,$xa2,$xa1
+ vperm2i128 \$0x31,$xb2,$xa2,$xb2
+ vperm2i128 \$0x20,$xb3,$xa3,$xa2
+ vperm2i128 \$0x31,$xb3,$xa3,$xb3
+___
+ ($xa0,$xa1,$xa2,$xa3,$xt3)=($xt3,$xa0,$xa1,$xa2,$xa3);
+ my ($xc0,$xc1,$xc2,$xc3)=($xt0,$xt1,$xa0,$xa1);
+$code.=<<___;
+ vmovdqa $xa0,0x00(%rsp) # offload $xaN
+ vmovdqa $xa1,0x20(%rsp)
+ vmovdqa 0x40(%rsp),$xc2 # $xa0
+ vmovdqa 0x60(%rsp),$xc3 # $xa1
+
+ vpaddd 0x180-0x200(%rax),$xc0,$xc0
+ vpaddd 0x1a0-0x200(%rax),$xc1,$xc1
+ vpaddd 0x1c0-0x200(%rax),$xc2,$xc2
+ vpaddd 0x1e0-0x200(%rax),$xc3,$xc3
+
+ vpunpckldq $xc1,$xc0,$xt2
+ vpunpckldq $xc3,$xc2,$xt3
+ vpunpckhdq $xc1,$xc0,$xc0
+ vpunpckhdq $xc3,$xc2,$xc2
+ vpunpcklqdq $xt3,$xt2,$xc1 # "c0"
+ vpunpckhqdq $xt3,$xt2,$xt2 # "c1"
+ vpunpcklqdq $xc2,$xc0,$xc3 # "c2"
+ vpunpckhqdq $xc2,$xc0,$xc0 # "c3"
+___
+ ($xc0,$xc1,$xc2,$xc3,$xt2)=($xc1,$xt2,$xc3,$xc0,$xc2);
+$code.=<<___;
+ vpaddd 0x200-0x200(%rax),$xd0,$xd0
+ vpaddd 0x220-0x200(%rax),$xd1,$xd1
+ vpaddd 0x240-0x200(%rax),$xd2,$xd2
+ vpaddd 0x260-0x200(%rax),$xd3,$xd3
+
+ vpunpckldq $xd1,$xd0,$xt2
+ vpunpckldq $xd3,$xd2,$xt3
+ vpunpckhdq $xd1,$xd0,$xd0
+ vpunpckhdq $xd3,$xd2,$xd2
+ vpunpcklqdq $xt3,$xt2,$xd1 # "d0"
+ vpunpckhqdq $xt3,$xt2,$xt2 # "d1"
+ vpunpcklqdq $xd2,$xd0,$xd3 # "d2"
+ vpunpckhqdq $xd2,$xd0,$xd0 # "d3"
+___
+ ($xd0,$xd1,$xd2,$xd3,$xt2)=($xd1,$xt2,$xd3,$xd0,$xd2);
+$code.=<<___;
+ vperm2i128 \$0x20,$xd0,$xc0,$xt3 # "de-interlace" further
+ vperm2i128 \$0x31,$xd0,$xc0,$xd0
+ vperm2i128 \$0x20,$xd1,$xc1,$xc0
+ vperm2i128 \$0x31,$xd1,$xc1,$xd1
+ vperm2i128 \$0x20,$xd2,$xc2,$xc1
+ vperm2i128 \$0x31,$xd2,$xc2,$xd2
+ vperm2i128 \$0x20,$xd3,$xc3,$xc2
+ vperm2i128 \$0x31,$xd3,$xc3,$xd3
+___
+ ($xc0,$xc1,$xc2,$xc3,$xt3)=($xt3,$xc0,$xc1,$xc2,$xc3);
+ ($xb0,$xb1,$xb2,$xb3,$xc0,$xc1,$xc2,$xc3)=
+ ($xc0,$xc1,$xc2,$xc3,$xb0,$xb1,$xb2,$xb3);
+ ($xa0,$xa1)=($xt2,$xt3);
+$code.=<<___;
+ vmovdqa 0x00(%rsp),$xa0 # $xaN was offloaded, remember?
+ vmovdqa 0x20(%rsp),$xa1
+
+ cmp \$64*8,$len
+ jb .Ltail8x
+
+ vpxor 0x00($inp),$xa0,$xa0 # xor with input
+ vpxor 0x20($inp),$xb0,$xb0
+ vpxor 0x40($inp),$xc0,$xc0
+ vpxor 0x60($inp),$xd0,$xd0
+ lea 0x80($inp),$inp # size optimization
+ vmovdqu $xa0,0x00($out)
+ vmovdqu $xb0,0x20($out)
+ vmovdqu $xc0,0x40($out)
+ vmovdqu $xd0,0x60($out)
+ lea 0x80($out),$out # size optimization
+
+ vpxor 0x00($inp),$xa1,$xa1
+ vpxor 0x20($inp),$xb1,$xb1
+ vpxor 0x40($inp),$xc1,$xc1
+ vpxor 0x60($inp),$xd1,$xd1
+ lea 0x80($inp),$inp # size optimization
+ vmovdqu $xa1,0x00($out)
+ vmovdqu $xb1,0x20($out)
+ vmovdqu $xc1,0x40($out)
+ vmovdqu $xd1,0x60($out)
+ lea 0x80($out),$out # size optimization
+
+ vpxor 0x00($inp),$xa2,$xa2
+ vpxor 0x20($inp),$xb2,$xb2
+ vpxor 0x40($inp),$xc2,$xc2
+ vpxor 0x60($inp),$xd2,$xd2
+ lea 0x80($inp),$inp # size optimization
+ vmovdqu $xa2,0x00($out)
+ vmovdqu $xb2,0x20($out)
+ vmovdqu $xc2,0x40($out)
+ vmovdqu $xd2,0x60($out)
+ lea 0x80($out),$out # size optimization
+
+ vpxor 0x00($inp),$xa3,$xa3
+ vpxor 0x20($inp),$xb3,$xb3
+ vpxor 0x40($inp),$xc3,$xc3
+ vpxor 0x60($inp),$xd3,$xd3
+ lea 0x80($inp),$inp # size optimization
+ vmovdqu $xa3,0x00($out)
+ vmovdqu $xb3,0x20($out)
+ vmovdqu $xc3,0x40($out)
+ vmovdqu $xd3,0x60($out)
+ lea 0x80($out),$out # size optimization
+
+ sub \$64*8,$len
+ jnz .Loop_outer8x
+
+ jmp .Ldone8x
+
+.Ltail8x:
+ cmp \$448,$len
+ jae .L448_or_more8x
+ cmp \$384,$len
+ jae .L384_or_more8x
+ cmp \$320,$len
+ jae .L320_or_more8x
+ cmp \$256,$len
+ jae .L256_or_more8x
+ cmp \$192,$len
+ jae .L192_or_more8x
+ cmp \$128,$len
+ jae .L128_or_more8x
+ cmp \$64,$len
+ jae .L64_or_more8x
+
+ xor %r10,%r10
+ vmovdqa $xa0,0x00(%rsp)
+ vmovdqa $xb0,0x20(%rsp)
+ jmp .Loop_tail8x
+
+.align 32
+.L64_or_more8x:
+ vpxor 0x00($inp),$xa0,$xa0 # xor with input
+ vpxor 0x20($inp),$xb0,$xb0
+ vmovdqu $xa0,0x00($out)
+ vmovdqu $xb0,0x20($out)
+ je .Ldone8x
+
+ lea 0x40($inp),$inp # inp+=64*1
+ xor %r10,%r10
+ vmovdqa $xc0,0x00(%rsp)
+ lea 0x40($out),$out # out+=64*1
+ sub \$64,$len # len-=64*1
+ vmovdqa $xd0,0x20(%rsp)
+ jmp .Loop_tail8x
+
+.align 32
+.L128_or_more8x:
+ vpxor 0x00($inp),$xa0,$xa0 # xor with input
+ vpxor 0x20($inp),$xb0,$xb0
+ vpxor 0x40($inp),$xc0,$xc0
+ vpxor 0x60($inp),$xd0,$xd0
+ vmovdqu $xa0,0x00($out)
+ vmovdqu $xb0,0x20($out)
+ vmovdqu $xc0,0x40($out)
+ vmovdqu $xd0,0x60($out)
+ je .Ldone8x
+
+ lea 0x80($inp),$inp # inp+=64*2
+ xor %r10,%r10
+ vmovdqa $xa1,0x00(%rsp)
+ lea 0x80($out),$out # out+=64*2
+ sub \$128,$len # len-=64*2
+ vmovdqa $xb1,0x20(%rsp)
+ jmp .Loop_tail8x
+
+.align 32
+.L192_or_more8x:
+ vpxor 0x00($inp),$xa0,$xa0 # xor with input
+ vpxor 0x20($inp),$xb0,$xb0
+ vpxor 0x40($inp),$xc0,$xc0
+ vpxor 0x60($inp),$xd0,$xd0
+ vpxor 0x80($inp),$xa1,$xa1
+ vpxor 0xa0($inp),$xb1,$xb1
+ vmovdqu $xa0,0x00($out)
+ vmovdqu $xb0,0x20($out)
+ vmovdqu $xc0,0x40($out)
+ vmovdqu $xd0,0x60($out)
+ vmovdqu $xa1,0x80($out)
+ vmovdqu $xb1,0xa0($out)
+ je .Ldone8x
+
+ lea 0xc0($inp),$inp # inp+=64*3
+ xor %r10,%r10
+ vmovdqa $xc1,0x00(%rsp)
+ lea 0xc0($out),$out # out+=64*3
+ sub \$192,$len # len-=64*3
+ vmovdqa $xd1,0x20(%rsp)
+ jmp .Loop_tail8x
+
+.align 32
+.L256_or_more8x:
+ vpxor 0x00($inp),$xa0,$xa0 # xor with input
+ vpxor 0x20($inp),$xb0,$xb0
+ vpxor 0x40($inp),$xc0,$xc0
+ vpxor 0x60($inp),$xd0,$xd0
+ vpxor 0x80($inp),$xa1,$xa1
+ vpxor 0xa0($inp),$xb1,$xb1
+ vpxor 0xc0($inp),$xc1,$xc1
+ vpxor 0xe0($inp),$xd1,$xd1
+ vmovdqu $xa0,0x00($out)
+ vmovdqu $xb0,0x20($out)
+ vmovdqu $xc0,0x40($out)
+ vmovdqu $xd0,0x60($out)
+ vmovdqu $xa1,0x80($out)
+ vmovdqu $xb1,0xa0($out)
+ vmovdqu $xc1,0xc0($out)
+ vmovdqu $xd1,0xe0($out)
+ je .Ldone8x
+
+ lea 0x100($inp),$inp # inp+=64*4
+ xor %r10,%r10
+ vmovdqa $xa2,0x00(%rsp)
+ lea 0x100($out),$out # out+=64*4
+ sub \$256,$len # len-=64*4
+ vmovdqa $xb2,0x20(%rsp)
+ jmp .Loop_tail8x
+
+.align 32
+.L320_or_more8x:
+ vpxor 0x00($inp),$xa0,$xa0 # xor with input
+ vpxor 0x20($inp),$xb0,$xb0
+ vpxor 0x40($inp),$xc0,$xc0
+ vpxor 0x60($inp),$xd0,$xd0
+ vpxor 0x80($inp),$xa1,$xa1
+ vpxor 0xa0($inp),$xb1,$xb1
+ vpxor 0xc0($inp),$xc1,$xc1
+ vpxor 0xe0($inp),$xd1,$xd1
+ vpxor 0x100($inp),$xa2,$xa2
+ vpxor 0x120($inp),$xb2,$xb2
+ vmovdqu $xa0,0x00($out)
+ vmovdqu $xb0,0x20($out)
+ vmovdqu $xc0,0x40($out)
+ vmovdqu $xd0,0x60($out)
+ vmovdqu $xa1,0x80($out)
+ vmovdqu $xb1,0xa0($out)
+ vmovdqu $xc1,0xc0($out)
+ vmovdqu $xd1,0xe0($out)
+ vmovdqu $xa2,0x100($out)
+ vmovdqu $xb2,0x120($out)
+ je .Ldone8x
+
+ lea 0x140($inp),$inp # inp+=64*5
+ xor %r10,%r10
+ vmovdqa $xc2,0x00(%rsp)
+ lea 0x140($out),$out # out+=64*5
+ sub \$320,$len # len-=64*5
+ vmovdqa $xd2,0x20(%rsp)
+ jmp .Loop_tail8x
+
+.align 32
+.L384_or_more8x:
+ vpxor 0x00($inp),$xa0,$xa0 # xor with input
+ vpxor 0x20($inp),$xb0,$xb0
+ vpxor 0x40($inp),$xc0,$xc0
+ vpxor 0x60($inp),$xd0,$xd0
+ vpxor 0x80($inp),$xa1,$xa1
+ vpxor 0xa0($inp),$xb1,$xb1
+ vpxor 0xc0($inp),$xc1,$xc1
+ vpxor 0xe0($inp),$xd1,$xd1
+ vpxor 0x100($inp),$xa2,$xa2
+ vpxor 0x120($inp),$xb2,$xb2
+ vpxor 0x140($inp),$xc2,$xc2
+ vpxor 0x160($inp),$xd2,$xd2
+ vmovdqu $xa0,0x00($out)
+ vmovdqu $xb0,0x20($out)
+ vmovdqu $xc0,0x40($out)
+ vmovdqu $xd0,0x60($out)
+ vmovdqu $xa1,0x80($out)
+ vmovdqu $xb1,0xa0($out)
+ vmovdqu $xc1,0xc0($out)
+ vmovdqu $xd1,0xe0($out)
+ vmovdqu $xa2,0x100($out)
+ vmovdqu $xb2,0x120($out)
+ vmovdqu $xc2,0x140($out)
+ vmovdqu $xd2,0x160($out)
+ je .Ldone8x
+
+ lea 0x180($inp),$inp # inp+=64*6
+ xor %r10,%r10
+ vmovdqa $xa3,0x00(%rsp)
+ lea 0x180($out),$out # out+=64*6
+ sub \$384,$len # len-=64*6
+ vmovdqa $xb3,0x20(%rsp)
+ jmp .Loop_tail8x
+
+.align 32
+.L448_or_more8x:
+ vpxor 0x00($inp),$xa0,$xa0 # xor with input
+ vpxor 0x20($inp),$xb0,$xb0
+ vpxor 0x40($inp),$xc0,$xc0
+ vpxor 0x60($inp),$xd0,$xd0
+ vpxor 0x80($inp),$xa1,$xa1
+ vpxor 0xa0($inp),$xb1,$xb1
+ vpxor 0xc0($inp),$xc1,$xc1
+ vpxor 0xe0($inp),$xd1,$xd1
+ vpxor 0x100($inp),$xa2,$xa2
+ vpxor 0x120($inp),$xb2,$xb2
+ vpxor 0x140($inp),$xc2,$xc2
+ vpxor 0x160($inp),$xd2,$xd2
+ vpxor 0x180($inp),$xa3,$xa3
+ vpxor 0x1a0($inp),$xb3,$xb3
+ vmovdqu $xa0,0x00($out)
+ vmovdqu $xb0,0x20($out)
+ vmovdqu $xc0,0x40($out)
+ vmovdqu $xd0,0x60($out)
+ vmovdqu $xa1,0x80($out)
+ vmovdqu $xb1,0xa0($out)
+ vmovdqu $xc1,0xc0($out)
+ vmovdqu $xd1,0xe0($out)
+ vmovdqu $xa2,0x100($out)
+ vmovdqu $xb2,0x120($out)
+ vmovdqu $xc2,0x140($out)
+ vmovdqu $xd2,0x160($out)
+ vmovdqu $xa3,0x180($out)
+ vmovdqu $xb3,0x1a0($out)
+ je .Ldone8x
+
+ lea 0x1c0($inp),$inp # inp+=64*7
+ xor %r10,%r10
+ vmovdqa $xc3,0x00(%rsp)
+ lea 0x1c0($out),$out # out+=64*7
+ sub \$448,$len # len-=64*7
+ vmovdqa $xd3,0x20(%rsp)
+
+.Loop_tail8x:
+ movzb ($inp,%r10),%eax
+ movzb (%rsp,%r10),%ecx
+ lea 1(%r10),%r10
+ xor %ecx,%eax
+ mov %al,-1($out,%r10)
+ dec $len
+ jnz .Loop_tail8x
+
+.Ldone8x:
+ vzeroall
+___
+$code.=<<___ if ($win64);
+ lea 0x290+0x30(%rsp),%r11
+ movaps -0x30(%r11),%xmm6
+ movaps -0x20(%r11),%xmm7
+ movaps -0x10(%r11),%xmm8
+ movaps 0x00(%r11),%xmm9
+ movaps 0x10(%r11),%xmm10
+ movaps 0x20(%r11),%xmm11
+ movaps 0x30(%r11),%xmm12
+ movaps 0x40(%r11),%xmm13
+ movaps 0x50(%r11),%xmm14
+ movaps 0x60(%r11),%xmm15
+___
+$code.=<<___;
+ mov 0x280(%rsp),%rsp
+ ret
+.size ChaCha20_8x,.-ChaCha20_8x
+___
+}
+
+foreach (split("\n",$code)) {
+ s/\`([^\`]*)\`/eval $1/geo;
+
+ s/%x#%y/%x/go;
+
+ print $_,"\n";
+}
+
+close STDOUT;
diff --git a/crypto/chacha/chacha_generic.c b/crypto/chacha/chacha.c
index f262033c..15620894 100644
--- a/crypto/chacha/chacha_generic.c
+++ b/crypto/chacha/chacha.c
@@ -16,12 +16,58 @@
#include <openssl/chacha.h>
+#include <assert.h>
#include <string.h>
#include <openssl/cpu.h>
+#include "../internal.h"
-#if defined(OPENSSL_WINDOWS) || (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) || !defined(__SSE2__)
+
+#define U8TO32_LITTLE(p) \
+ (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \
+ ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24))
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
+ defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64))
+
+/* ChaCha20_ctr32 is defined in asm/chacha-*.pl. */
+void ChaCha20_ctr32(uint8_t *out, const uint8_t *in, size_t in_len,
+ const uint32_t key[8], const uint32_t counter[4]);
+
+void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
+ const uint8_t key[32], const uint8_t nonce[12],
+ uint32_t counter) {
+ assert(!buffers_alias(out, in_len, in, in_len) || in == out);
+
+ uint32_t counter_nonce[4]; counter_nonce[0] = counter;
+ counter_nonce[1] = U8TO32_LITTLE(nonce + 0);
+ counter_nonce[2] = U8TO32_LITTLE(nonce + 4);
+ counter_nonce[3] = U8TO32_LITTLE(nonce + 8);
+
+ const uint32_t *key_ptr = (const uint32_t *)key;
+#if !defined(OPENSSL_X86) && !defined(OPENSSL_X86_64)
+ /* The assembly expects the key to be four-byte aligned. */
+ uint32_t key_u32[8];
+ if ((((uintptr_t)key) & 3) != 0) {
+ key_u32[0] = U8TO32_LITTLE(key + 0);
+ key_u32[1] = U8TO32_LITTLE(key + 4);
+ key_u32[2] = U8TO32_LITTLE(key + 8);
+ key_u32[3] = U8TO32_LITTLE(key + 12);
+ key_u32[4] = U8TO32_LITTLE(key + 16);
+ key_u32[5] = U8TO32_LITTLE(key + 20);
+ key_u32[6] = U8TO32_LITTLE(key + 24);
+ key_u32[7] = U8TO32_LITTLE(key + 28);
+
+ key_ptr = key_u32;
+ }
+#endif
+
+ ChaCha20_ctr32(out, in, in_len, key_ptr, counter_nonce);
+}
+
+#else
/* sigma contains the ChaCha constants, which happen to be an ASCII string. */
static const uint8_t sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3',
@@ -40,10 +86,6 @@ static const uint8_t sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3',
(p)[3] = (v >> 24) & 0xff; \
}
-#define U8TO32_LITTLE(p) \
- (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \
- ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24))
-
/* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */
#define QUARTERROUND(a,b,c,d) \
x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
@@ -51,13 +93,6 @@ static const uint8_t sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3',
x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
-#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
-/* Defined in chacha_vec.c */
-void CRYPTO_chacha_20_neon(uint8_t *out, const uint8_t *in, size_t in_len,
- const uint8_t key[32], const uint8_t nonce[12],
- uint32_t counter);
-#endif
-
/* chacha_core performs 20 rounds of ChaCha on the input words in
* |input| and writes the 64 output bytes to |output|. */
static void chacha_core(uint8_t output[64], const uint32_t input[16]) {
@@ -87,17 +122,12 @@ static void chacha_core(uint8_t output[64], const uint32_t input[16]) {
void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
const uint8_t key[32], const uint8_t nonce[12],
uint32_t counter) {
+ assert(!buffers_alias(out, in_len, in, in_len) || in == out);
+
uint32_t input[16];
uint8_t buf[64];
size_t todo, i;
-#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
- if (CRYPTO_is_NEON_capable()) {
- CRYPTO_chacha_20_neon(out, in, in_len, key, nonce, counter);
- return;
- }
-#endif
-
input[0] = U8TO32_LITTLE(sigma + 0);
input[1] = U8TO32_LITTLE(sigma + 4);
input[2] = U8TO32_LITTLE(sigma + 8);
@@ -137,4 +167,4 @@ void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
}
}
-#endif /* OPENSSL_WINDOWS || !OPENSSL_X86_64 && !OPENSSL_X86 || !__SSE2__ */
+#endif
diff --git a/crypto/chacha/chacha_test.cc b/crypto/chacha/chacha_test.cc
new file mode 100644
index 00000000..0a5972f7
--- /dev/null
+++ b/crypto/chacha/chacha_test.cc
@@ -0,0 +1,248 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <memory>
+
+#include <openssl/crypto.h>
+#include <openssl/chacha.h>
+
+
+static const uint8_t kKey[32] = {
+ 0x98, 0xbe, 0xf1, 0x46, 0x9b, 0xe7, 0x26, 0x98, 0x37, 0xa4, 0x5b,
+ 0xfb, 0xc9, 0x2a, 0x5a, 0x6a, 0xc7, 0x62, 0x50, 0x7c, 0xf9, 0x64,
+ 0x43, 0xbf, 0x33, 0xb9, 0x6b, 0x1b, 0xd4, 0xc6, 0xf8, 0xf6,
+};
+
+static const uint8_t kNonce[12] = {
+ 0x44, 0xe7, 0x92, 0xd6, 0x33, 0x35, 0xab, 0xb1, 0x58, 0x2e, 0x92, 0x53,
+};
+
+static uint32_t kCounter = 42;
+
+static const uint8_t kInput[] = {
+ 0x58, 0x28, 0xd5, 0x30, 0x36, 0x2c, 0x60, 0x55, 0x29, 0xf8, 0xe1, 0x8c,
+ 0xae, 0x15, 0x15, 0x26, 0xf2, 0x3a, 0x73, 0xa0, 0xf3, 0x12, 0xa3, 0x88,
+ 0x5f, 0x2b, 0x74, 0x23, 0x3d, 0xc9, 0x05, 0x23, 0xc6, 0x54, 0x49, 0x1e,
+ 0x44, 0x88, 0x14, 0xd9, 0xda, 0x37, 0x15, 0xdc, 0xb7, 0xe4, 0x23, 0xb3,
+ 0x9d, 0x7e, 0x16, 0x68, 0x35, 0xfc, 0x02, 0x6d, 0xcc, 0x8a, 0xe5, 0xdd,
+ 0x5f, 0xe4, 0xd2, 0x56, 0x6f, 0x12, 0x9c, 0x9c, 0x7d, 0x6a, 0x38, 0x48,
+ 0xbd, 0xdf, 0xd9, 0xac, 0x1b, 0xa2, 0x4d, 0xc5, 0x43, 0x04, 0x3c, 0xd7,
+ 0x99, 0xe1, 0xa7, 0x13, 0x9c, 0x51, 0xc2, 0x6d, 0xf9, 0xcf, 0x07, 0x3b,
+ 0xe4, 0xbf, 0x93, 0xa3, 0xa9, 0xb4, 0xc5, 0xf0, 0x1a, 0xe4, 0x8d, 0x5f,
+ 0xc6, 0xc4, 0x7c, 0x69, 0x7a, 0xde, 0x1a, 0xc1, 0xc9, 0xcf, 0xc2, 0x4e,
+ 0x7a, 0x25, 0x2c, 0x32, 0xe9, 0x17, 0xba, 0x68, 0xf1, 0x37, 0x5d, 0x62,
+ 0x84, 0x46, 0xf5, 0x80, 0x7f, 0x1a, 0x71, 0xf7, 0xbe, 0x72, 0x4b, 0xb8,
+ 0x1c, 0xfe, 0x3e, 0xbd, 0xae, 0x0d, 0x73, 0x0d, 0x87, 0x4a, 0x31, 0xc3,
+ 0x3d, 0x46, 0x6f, 0xb3, 0xd7, 0x6b, 0xe3, 0xb8, 0x70, 0x17, 0x8e, 0x7a,
+ 0x6a, 0x0e, 0xbf, 0xa8, 0xbc, 0x2b, 0xdb, 0xfa, 0x4f, 0xb6, 0x26, 0x20,
+ 0xee, 0x63, 0xf0, 0x6d, 0x26, 0xac, 0x6a, 0x18, 0x37, 0x6e, 0x59, 0x81,
+ 0xd1, 0x60, 0xe6, 0x40, 0xd5, 0x6d, 0x68, 0xba, 0x8b, 0x65, 0x4a, 0xf9,
+ 0xf1, 0xae, 0x56, 0x24, 0x8f, 0xe3, 0x8e, 0xe7, 0x7e, 0x6f, 0xcf, 0x92,
+ 0xdf, 0xa9, 0x75, 0x3a, 0xd6, 0x2e, 0x1c, 0xaf, 0xf2, 0xd6, 0x8b, 0x39,
+ 0xad, 0xd2, 0x5d, 0xfb, 0xd7, 0xdf, 0x05, 0x57, 0x0d, 0xf7, 0xf6, 0x8f,
+ 0x2d, 0x14, 0xb0, 0x4e, 0x1a, 0x3c, 0x77, 0x04, 0xcd, 0x3c, 0x5c, 0x58,
+ 0x52, 0x10, 0x6f, 0xcf, 0x5c, 0x03, 0xc8, 0x5f, 0x85, 0x2b, 0x05, 0x82,
+ 0x60, 0xda, 0xcc, 0xcd, 0xd6, 0x88, 0xbf, 0xc0, 0x10, 0xb3, 0x6f, 0x54,
+ 0x54, 0x42, 0xbc, 0x4b, 0x77, 0x21, 0x4d, 0xee, 0x87, 0x45, 0x06, 0x4c,
+ 0x60, 0x38, 0xd2, 0x7e, 0x1d, 0x30, 0x6c, 0x55, 0xf0, 0x38, 0x80, 0x1c,
+ 0xde, 0x3d, 0xea, 0x68, 0x3e, 0xf6, 0x3e, 0x59, 0xcf, 0x0d, 0x08, 0xae,
+ 0x8c, 0x02, 0x0b, 0xc1, 0x72, 0x6a, 0xb4, 0x6d, 0xf3, 0xf7, 0xb3, 0xef,
+ 0x3a, 0xb1, 0x06, 0xf2, 0xf4, 0xd6, 0x69, 0x7b, 0x3e, 0xa2, 0x16, 0x31,
+ 0x31, 0x79, 0xb6, 0x33, 0xa9, 0xca, 0x8a, 0xa8, 0xbe, 0xf3, 0xe9, 0x38,
+ 0x28, 0xd1, 0xe1, 0x3b, 0x4e, 0x2e, 0x47, 0x35, 0xa4, 0x61, 0x14, 0x1e,
+ 0x42, 0x2c, 0x49, 0x55, 0xea, 0xe3, 0xb3, 0xce, 0x39, 0xd3, 0xb3, 0xef,
+ 0x4a, 0x4d, 0x78, 0x49, 0xbd, 0xf6, 0x7c, 0x0a, 0x2c, 0xd3, 0x26, 0xcb,
+ 0xd9, 0x6a, 0xad, 0x63, 0x93, 0xa7, 0x29, 0x92, 0xdc, 0x1f, 0xaf, 0x61,
+ 0x82, 0x80, 0x74, 0xb2, 0x9c, 0x4a, 0x86, 0x73, 0x50, 0xd8, 0xd1, 0xff,
+ 0xee, 0x1a, 0xe2, 0xdd, 0xa2, 0x61, 0xbd, 0x10, 0xc3, 0x5f, 0x67, 0x9f,
+ 0x29, 0xe4, 0xd3, 0x70, 0xe5, 0x67, 0x3a, 0xd2, 0x20, 0x00, 0xcc, 0x25,
+ 0x15, 0x96, 0x54, 0x45, 0x85, 0xed, 0x82, 0x88, 0x3b, 0x9f, 0x3b, 0xc3,
+ 0x04, 0xd4, 0x23, 0xb1, 0x0d, 0xdc, 0xc8, 0x26, 0x9d, 0x28, 0xb3, 0x25,
+ 0x4d, 0x52, 0xe5, 0x33, 0xf3, 0xed, 0x2c, 0xb8, 0x1a, 0xcf, 0xc3, 0x52,
+ 0xb4, 0x2f, 0xc7, 0x79, 0x96, 0x14, 0x7d, 0x72, 0x27, 0x72, 0x85, 0xea,
+ 0x6d, 0x41, 0xa0, 0x22, 0x13, 0x6d, 0x06, 0x83, 0xa4, 0xdd, 0x0f, 0x69,
+ 0xd2, 0x01, 0xcd, 0xc6, 0xb8, 0x64, 0x5c, 0x2c, 0x79, 0xd1, 0xc7, 0xd3,
+ 0x31, 0xdb, 0x2c, 0xff, 0xda, 0xd0, 0x69, 0x31, 0xad, 0x83, 0x5f, 0xed,
+ 0x6a, 0x97, 0xe4, 0x00, 0x43, 0xb0, 0x2e, 0x97, 0xae, 0x00, 0x5f, 0x5c,
+ 0xb9, 0xe8, 0x39, 0x80, 0x10, 0xca, 0x0c, 0xfa, 0xf0, 0xb5, 0xcd, 0xaa,
+ 0x27, 0x11, 0x60, 0xd9, 0x21, 0x86, 0x93, 0x91, 0x9f, 0x2d, 0x1a, 0x8e,
+ 0xde, 0x0b, 0xb5, 0xcb, 0x05, 0x24, 0x30, 0x45, 0x4d, 0x11, 0x75, 0xfd,
+ 0xe5, 0xa0, 0xa9, 0x4e, 0x3a, 0x8c, 0x3b, 0x52, 0x5a, 0x37, 0x18, 0x05,
+ 0x4a, 0x7a, 0x09, 0x6a, 0xe6, 0xd5, 0xa9, 0xa6, 0x71, 0x47, 0x4c, 0x50,
+ 0xe1, 0x3e, 0x8a, 0x21, 0x2b, 0x4f, 0x0e, 0xe3, 0xcb, 0x72, 0xc5, 0x28,
+ 0x3e, 0x5a, 0x33, 0xec, 0x48, 0x92, 0x2e, 0xa1, 0x24, 0x57, 0x09, 0x0f,
+ 0x01, 0x85, 0x3b, 0x34, 0x39, 0x7e, 0xc7, 0x90, 0x62, 0xe2, 0xdc, 0x5d,
+ 0x0a, 0x2c, 0x51, 0x26, 0x95, 0x3a, 0x95, 0x92, 0xa5, 0x39, 0x8f, 0x0c,
+ 0x83, 0x0b, 0x9d, 0x38, 0xab, 0x98, 0x2a, 0xc4, 0x01, 0xc4, 0x0d, 0x77,
+ 0x13, 0xcb, 0xca, 0xf1, 0x28, 0x31, 0x52, 0x75, 0x27, 0x2c, 0xf0, 0x04,
+ 0x86, 0xc8, 0xf3, 0x3d, 0xf2, 0x9d, 0x8f, 0x55, 0x52, 0x40, 0x3f, 0xaa,
+ 0x22, 0x7f, 0xe7, 0x69, 0x3b, 0xee, 0x44, 0x09, 0xde, 0xff, 0xb0, 0x69,
+ 0x3a, 0xae, 0x74, 0xe9, 0x9d, 0x33, 0xae, 0x8b, 0x6d, 0x60, 0x04, 0xff,
+ 0x53, 0x3f, 0x88, 0xe9, 0x63, 0x9b, 0xb1, 0x6d, 0x2c, 0x22, 0x15, 0x5a,
+ 0x15, 0xd9, 0xe5, 0xcb, 0x03, 0x78, 0x3c, 0xca, 0x59, 0x8c, 0xc8, 0xc2,
+ 0x86, 0xff, 0xd2, 0x79, 0xd6, 0xc6, 0xec, 0x5b, 0xbb, 0xa0, 0xae, 0x01,
+ 0x20, 0x09, 0x2e, 0x38, 0x5d, 0xda, 0x5d, 0xe0, 0x59, 0x4e, 0xe5, 0x8b,
+ 0x84, 0x8f, 0xb6, 0xe0, 0x56, 0x9f, 0x21, 0xa1, 0xcf, 0xb2, 0x0f, 0x2c,
+ 0x93, 0xf8, 0xcf, 0x37, 0xc1, 0x9f, 0x32, 0x98, 0x21, 0x65, 0x52, 0x66,
+ 0x6e, 0xd3, 0x71, 0x98, 0x55, 0xb9, 0x46, 0x9f, 0x1a, 0x35, 0xc4, 0x47,
+ 0x69, 0x62, 0x70, 0x4b, 0x77, 0x9e, 0xe4, 0x21, 0xe6, 0x32, 0x5a, 0x26,
+ 0x05, 0xba, 0x57, 0x53, 0xd7, 0x9b, 0x55, 0x3c, 0xbb, 0x53, 0x79, 0x60,
+ 0x9c, 0xc8, 0x4d, 0xf7, 0xf5, 0x1d, 0x54, 0x02, 0x91, 0x68, 0x0e, 0xaa,
+ 0xca, 0x5a, 0x78, 0x0c, 0x28, 0x9a, 0xc3, 0xac, 0x49, 0xc0, 0xf4, 0x85,
+ 0xee, 0x59, 0x76, 0x7e, 0x28, 0x4e, 0xf1, 0x5c, 0x63, 0xf7, 0xce, 0x0e,
+ 0x2c, 0x21, 0xa0, 0x58, 0xe9, 0x01, 0xfd, 0xeb, 0xd1, 0xaf, 0xe6, 0xef,
+ 0x93, 0xb3, 0x95, 0x51, 0x60, 0xa2, 0x74, 0x40, 0x15, 0xe5, 0xf4, 0x0a,
+ 0xca, 0x6d, 0x9a, 0x37, 0x42, 0x4d, 0x5a, 0x58, 0x49, 0x0f, 0xe9, 0x02,
+ 0xfc, 0x77, 0xd8, 0x59, 0xde, 0xdd, 0xad, 0x4b, 0x99, 0x2e, 0x64, 0x73,
+ 0xad, 0x42, 0x2f, 0xf3, 0x2c, 0x0d, 0x49, 0xe4, 0x2e, 0x6c, 0xa4, 0x73,
+ 0x75, 0x18, 0x14, 0x85, 0xbb, 0x64, 0xb4, 0xa1, 0xb0, 0x6e, 0x01, 0xc0,
+ 0xcf, 0x17, 0x9c, 0xc5, 0x28, 0xc3, 0x2d, 0x6c, 0x17, 0x2a, 0x3d, 0x06,
+ 0x5c, 0xf3, 0xb4, 0x49, 0x75, 0xad, 0x17, 0x69, 0xd4, 0xca, 0x65, 0xae,
+ 0x44, 0x71, 0xa5, 0xf6, 0x0d, 0x0f, 0x8e, 0x37, 0xc7, 0x43, 0xce, 0x6b,
+ 0x08, 0xe9, 0xd1, 0x34, 0x48, 0x8f, 0xc9, 0xfc, 0xf3, 0x5d, 0x2d, 0xec,
+ 0x62, 0xd3, 0xf0, 0xb3, 0xfe, 0x2e, 0x40, 0x55, 0x76, 0x54, 0xc7, 0xb4,
+ 0x61, 0x16, 0xcc, 0x7c, 0x1c, 0x19, 0x24, 0xe6, 0x4d, 0xd4, 0xc3, 0x77,
+ 0x67, 0x1f, 0x3c, 0x74, 0x79, 0xa1, 0xf8, 0x85, 0x88, 0x1d, 0x6f, 0xa4,
+ 0x7e, 0x2c, 0x21, 0x9f, 0x49, 0xf5, 0xaa, 0x4e, 0xf3, 0x4a, 0xfa, 0x9d,
+ 0xbe, 0xf6, 0xce, 0xda, 0xb5, 0xab, 0x39, 0xbd, 0x16, 0x41, 0xa9, 0x4a,
+ 0xac, 0x09, 0x01, 0xca,
+};
+static const uint8_t kOutput[] = {
+ 0x54, 0x30, 0x6a, 0x13, 0xda, 0x59, 0x6b, 0x6d, 0x59, 0x49, 0xc8, 0xc5,
+ 0xab, 0x26, 0xd4, 0x8a, 0xad, 0xc0, 0x3d, 0xaf, 0x14, 0xb9, 0x15, 0xb8,
+ 0xca, 0xdf, 0x17, 0xa7, 0x03, 0xd3, 0xc5, 0x06, 0x01, 0xef, 0x21, 0xdd,
+ 0xa3, 0x0b, 0x9e, 0x48, 0xb8, 0x5e, 0x0b, 0x87, 0x9f, 0x95, 0x23, 0x68,
+ 0x85, 0x69, 0xd2, 0x5d, 0xaf, 0x57, 0xe9, 0x27, 0x11, 0x3d, 0x49, 0xfa,
+ 0xf1, 0x08, 0xcc, 0x15, 0xec, 0x1d, 0x19, 0x16, 0x12, 0x9b, 0xc8, 0x66,
+ 0x1f, 0xfa, 0x2c, 0x93, 0xf4, 0x99, 0x11, 0x27, 0x31, 0x0e, 0xd8, 0x46,
+ 0x47, 0x40, 0x11, 0x70, 0x01, 0xca, 0xe8, 0x5b, 0xc5, 0x91, 0xc8, 0x3a,
+ 0xdc, 0xaa, 0xf3, 0x4b, 0x80, 0xe5, 0xbc, 0x03, 0xd0, 0x89, 0x72, 0xbc,
+ 0xce, 0x2a, 0x76, 0x0c, 0xf5, 0xda, 0x4c, 0x10, 0x06, 0x35, 0x41, 0xb1,
+ 0xe6, 0xb4, 0xaa, 0x7a, 0xef, 0xf0, 0x62, 0x4a, 0xc5, 0x9f, 0x2c, 0xaf,
+ 0xb8, 0x2f, 0xd9, 0xd1, 0x01, 0x7a, 0x36, 0x2f, 0x3e, 0x83, 0xa5, 0xeb,
+ 0x81, 0x70, 0xa0, 0x57, 0x17, 0x46, 0xea, 0x9e, 0xcb, 0x0e, 0x74, 0xd3,
+ 0x44, 0x57, 0x1d, 0x40, 0x06, 0xf8, 0xb7, 0xcb, 0x5f, 0xf4, 0x79, 0xbd,
+ 0x11, 0x19, 0xd6, 0xee, 0xf8, 0xb0, 0xaa, 0xdd, 0x00, 0x62, 0xad, 0x3b,
+ 0x88, 0x9a, 0x88, 0x5b, 0x1b, 0x07, 0xc9, 0xae, 0x9e, 0xa6, 0x94, 0xe5,
+ 0x55, 0xdb, 0x45, 0x23, 0xb9, 0x2c, 0xcd, 0x29, 0xd3, 0x54, 0xc3, 0x88,
+ 0x1e, 0x5f, 0x52, 0xf2, 0x09, 0x00, 0x26, 0x26, 0x1a, 0xed, 0xf5, 0xc2,
+ 0xa9, 0x7d, 0xf9, 0x21, 0x5a, 0xaf, 0x6d, 0xab, 0x8e, 0x16, 0x84, 0x96,
+ 0xb5, 0x4f, 0xcf, 0x1e, 0xa3, 0xaf, 0x08, 0x9f, 0x79, 0x86, 0xc3, 0xbe,
+ 0x0c, 0x70, 0xcb, 0x8f, 0xf3, 0xc5, 0xf8, 0xe8, 0x4b, 0x21, 0x7d, 0x18,
+ 0xa9, 0xed, 0x8b, 0xfb, 0x6b, 0x5a, 0x6f, 0x26, 0x0b, 0x56, 0x04, 0x7c,
+ 0xfe, 0x0e, 0x1e, 0xc1, 0x3f, 0x82, 0xc5, 0x73, 0xbd, 0x53, 0x0c, 0xf0,
+ 0xe2, 0xc9, 0xf3, 0x3d, 0x1b, 0x6d, 0xba, 0x70, 0xc1, 0x6d, 0xb6, 0x00,
+ 0x28, 0xe1, 0xc4, 0x78, 0x62, 0x04, 0xda, 0x23, 0x86, 0xc3, 0xda, 0x74,
+ 0x3d, 0x7c, 0xd6, 0x76, 0x29, 0xb2, 0x27, 0x2e, 0xb2, 0x35, 0x42, 0x60,
+ 0x82, 0xcf, 0x30, 0x2c, 0x59, 0xe4, 0xe3, 0xd0, 0x74, 0x1f, 0x58, 0xe8,
+ 0xda, 0x47, 0x45, 0x73, 0x1c, 0x05, 0x93, 0xae, 0x75, 0xbe, 0x1f, 0x81,
+ 0xd8, 0xb7, 0xb3, 0xff, 0xfc, 0x8b, 0x52, 0x9e, 0xed, 0x8b, 0x37, 0x9f,
+ 0xe0, 0xb8, 0xa2, 0x66, 0xe1, 0x6a, 0xc5, 0x1f, 0x1d, 0xf0, 0xde, 0x3f,
+ 0x3d, 0xb0, 0x28, 0xf3, 0xaa, 0x4e, 0x4d, 0x31, 0xb0, 0x26, 0x79, 0x2b,
+ 0x08, 0x0f, 0xe9, 0x2f, 0x79, 0xb3, 0xc8, 0xdd, 0xa7, 0x89, 0xa8, 0xa8,
+ 0x1d, 0x59, 0x0e, 0x4f, 0x1e, 0x93, 0x1f, 0x70, 0x7f, 0x4e, 0x7e, 0xfe,
+ 0xb8, 0xca, 0x63, 0xe0, 0xa6, 0x05, 0xcc, 0xd7, 0xde, 0x2a, 0x49, 0x31,
+ 0x78, 0x5c, 0x5f, 0x44, 0xb2, 0x9b, 0x91, 0x99, 0x14, 0x29, 0x63, 0x09,
+ 0x12, 0xdd, 0x02, 0xd9, 0x7b, 0xe9, 0xf5, 0x12, 0x07, 0xd0, 0xe7, 0xe6,
+ 0xe8, 0xdd, 0xda, 0xa4, 0x73, 0xc4, 0x8e, 0xbd, 0x7b, 0xb7, 0xbb, 0xcb,
+ 0x83, 0x2f, 0x43, 0xf6, 0x1c, 0x50, 0xae, 0x9b, 0x2e, 0x52, 0x80, 0x18,
+ 0x85, 0xa8, 0x23, 0x52, 0x7a, 0x6a, 0xf7, 0x42, 0x36, 0xca, 0x91, 0x5a,
+ 0x3d, 0x2a, 0xa0, 0x35, 0x7d, 0x70, 0xfc, 0x4c, 0x18, 0x7c, 0x57, 0x72,
+ 0xcf, 0x9b, 0x29, 0xd6, 0xd0, 0xb4, 0xd7, 0xe6, 0x89, 0x70, 0x69, 0x22,
+ 0x5e, 0x45, 0x09, 0x4d, 0x49, 0x87, 0x84, 0x5f, 0x8a, 0x5f, 0xe4, 0x15,
+ 0xd3, 0xe3, 0x72, 0xaf, 0xb2, 0x30, 0x9c, 0xc1, 0xff, 0x8e, 0x6d, 0x2a,
+ 0x76, 0x9e, 0x08, 0x03, 0x7e, 0xe0, 0xc3, 0xc2, 0x97, 0x06, 0x6b, 0x33,
+ 0x2b, 0x08, 0xe3, 0xd5, 0x0b, 0xd8, 0x32, 0x67, 0x61, 0x10, 0xed, 0x6b,
+ 0xed, 0x50, 0xef, 0xd7, 0x1c, 0x1b, 0xe0, 0x6d, 0xa1, 0x64, 0x19, 0x34,
+ 0x2f, 0xe4, 0xe8, 0x54, 0xbf, 0x84, 0x0e, 0xdf, 0x0e, 0x8b, 0xd8, 0xdd,
+ 0x77, 0x96, 0xb8, 0x54, 0xab, 0xf2, 0x95, 0x59, 0x0d, 0x0d, 0x0a, 0x15,
+ 0x6e, 0x01, 0xf2, 0x24, 0xab, 0xa0, 0xd8, 0xdf, 0x38, 0xea, 0x97, 0x58,
+ 0x76, 0x88, 0xbe, 0xaf, 0x45, 0xe3, 0x56, 0x4f, 0x68, 0xe8, 0x4b, 0xe7,
+ 0x2b, 0x22, 0x18, 0x96, 0x82, 0x89, 0x25, 0x34, 0xd1, 0xdd, 0x08, 0xea,
+ 0x7e, 0x21, 0xef, 0x57, 0x55, 0x43, 0xf7, 0xfa, 0xca, 0x1c, 0xde, 0x99,
+ 0x2e, 0x8b, 0xd8, 0xc3, 0xcf, 0x89, 0x4d, 0xfc, 0x3b, 0x7d, 0x4a, 0xc9,
+ 0x99, 0xc4, 0x31, 0xb6, 0x7a, 0xae, 0xf8, 0x49, 0xb2, 0x46, 0xc1, 0x60,
+ 0x05, 0x75, 0xf3, 0x3d, 0xf2, 0xc9, 0x84, 0xa4, 0xb9, 0x8a, 0x87, 0x2a,
+ 0x87, 0x5c, 0x0a, 0xbc, 0x51, 0x7d, 0x9a, 0xf5, 0xc9, 0x24, 0x2d, 0x5e,
+ 0xe6, 0xc6, 0xe3, 0xcd, 0x7e, 0xe4, 0xaf, 0x8a, 0x6c, 0x00, 0x04, 0xc8,
+ 0xd7, 0xa5, 0xad, 0xfa, 0xb2, 0x08, 0x4a, 0x26, 0x9b, 0x7c, 0xd0, 0xc6,
+ 0x13, 0xb1, 0xb9, 0x65, 0x3f, 0x70, 0x30, 0xf9, 0x98, 0x9d, 0x87, 0x99,
+ 0x57, 0x71, 0x3e, 0xb1, 0xc3, 0x24, 0xf0, 0xa6, 0xa2, 0x60, 0x9d, 0x66,
+ 0xd2, 0x5f, 0xae, 0xe3, 0x94, 0x87, 0xea, 0xd1, 0xea, 0x0d, 0x2a, 0x77,
+ 0xef, 0x31, 0xcc, 0xeb, 0xf9, 0x0c, 0xdc, 0x9c, 0x12, 0x80, 0xbb, 0xb0,
+ 0x8e, 0xab, 0x9a, 0x04, 0xcd, 0x4b, 0x95, 0x4f, 0x7a, 0x0b, 0x53, 0x7c,
+ 0x16, 0xcc, 0x0e, 0xb1, 0x73, 0x10, 0xdd, 0xaa, 0x76, 0x94, 0x90, 0xd9,
+ 0x8b, 0x66, 0x41, 0x31, 0xed, 0x8c, 0x7d, 0x74, 0xc4, 0x33, 0xfa, 0xc3,
+ 0x43, 0x8d, 0x10, 0xbc, 0x84, 0x4d, 0x0e, 0x95, 0x32, 0xdf, 0x17, 0x43,
+ 0x6d, 0xd2, 0x5e, 0x12, 0xb9, 0xed, 0x33, 0xd9, 0x97, 0x6f, 0x4a, 0xcd,
+ 0xc3, 0xcd, 0x81, 0x34, 0xbe, 0x7e, 0xa2, 0xd0, 0xa7, 0x91, 0x5d, 0x90,
+ 0xf6, 0x5e, 0x4a, 0x25, 0x0f, 0xcc, 0x24, 0xeb, 0xe1, 0xe4, 0x62, 0x6c,
+ 0x8f, 0x45, 0x36, 0x97, 0x5d, 0xda, 0x20, 0x2b, 0x86, 0x00, 0x8c, 0x94,
+ 0xa9, 0x6a, 0x69, 0xb2, 0xe9, 0xbb, 0x82, 0x8e, 0x41, 0x95, 0xb4, 0xb7,
+ 0xf1, 0x55, 0x52, 0x30, 0x39, 0x48, 0xb3, 0x25, 0x82, 0xa9, 0x10, 0x27,
+ 0x89, 0xb5, 0xe5, 0x1f, 0xab, 0x72, 0x3c, 0x70, 0x08, 0xce, 0xe6, 0x61,
+ 0xbf, 0x19, 0xc8, 0x90, 0x2b, 0x29, 0x30, 0x3e, 0xb8, 0x4c, 0x33, 0xf0,
+ 0xf0, 0x15, 0x2e, 0xb7, 0x25, 0xca, 0x99, 0x4b, 0x6f, 0x4b, 0x41, 0x50,
+ 0xee, 0x56, 0x99, 0xcf, 0x2b, 0xa4, 0xc4, 0x7c, 0x5c, 0xa6, 0xd4, 0x67,
+ 0x04, 0x5c, 0x5d, 0x5f, 0x26, 0x9e, 0x0f, 0xe2, 0x58, 0x68, 0x4c, 0x30,
+ 0xcd, 0xef, 0x46, 0xdb, 0x37, 0x6f, 0xbb, 0xc4, 0x80, 0xca, 0x8a, 0x54,
+ 0x5d, 0x71, 0x9d, 0x0c, 0xe8, 0xb8, 0x2c, 0x10, 0x90, 0x44, 0xa4, 0x88,
+ 0x3f, 0xbc, 0x15, 0x3c, 0xd2, 0xca, 0x0e, 0xc3, 0xe4, 0x6e, 0xef, 0xb0,
+ 0xcb, 0xfd, 0x61, 0x7c, 0x27, 0xf2, 0x25, 0xea, 0x71, 0x6d, 0xf7, 0x49,
+ 0x9c, 0x81, 0x27, 0xf0, 0x61, 0x33, 0xcf, 0x55, 0x68, 0xd3, 0x73, 0xa4,
+ 0xed, 0x35, 0x65, 0x2a, 0xf2, 0x3e, 0xcf, 0x90, 0x98, 0x54, 0x6d, 0x95,
+ 0x6a, 0x0c, 0x9c, 0x24, 0x0e, 0xb4, 0xb7, 0x9b, 0x8d, 0x6e, 0x1c, 0xbc,
+ 0xeb, 0x17, 0x10, 0x86, 0xda, 0x91, 0x6d, 0x89, 0x4c, 0xeb, 0xf5, 0x50,
+ 0x8f, 0x40, 0xcf, 0x4a,
+};
+
+static_assert(sizeof(kInput) == sizeof(kOutput),
+ "Input and output lengths don't match.");
+
+static bool TestChaCha20(size_t len) {
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[len]);
+ CRYPTO_chacha_20(buf.get(), kInput, len, kKey, kNonce, kCounter);
+ if (memcmp(buf.get(), kOutput, len) != 0) {
+ fprintf(stderr, "Mismatch at length %zu.\n", len);
+ return false;
+ }
+
+ // Test in-place.
+ memcpy(buf.get(), kInput, len);
+ CRYPTO_chacha_20(buf.get(), buf.get(), len, kKey, kNonce, kCounter);
+ if (memcmp(buf.get(), kOutput, len) != 0) {
+ fprintf(stderr, "Mismatch at length %zu, in-place.\n", len);
+ return false;
+ }
+
+ return true;
+}
+
+int main(int argc, char **argv) {
+ CRYPTO_library_init();
+
+ // Run the test with the test vector at all lengths.
+ for (size_t len = 0; len <= sizeof(kInput); len++) {
+ if (!TestChaCha20(len)) {
+ return 1;
+ }
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/chacha/chacha_vec.c b/crypto/chacha/chacha_vec.c
deleted file mode 100644
index 90d62002..00000000
--- a/crypto/chacha/chacha_vec.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/* Copyright (c) 2014, Google Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
-
-/* ====================================================================
- *
- * When updating this file, also update chacha_vec_arm.S
- *
- * ==================================================================== */
-
-
-/* This implementation is by Ted Krovetz and was submitted to SUPERCOP and
- * marked as public domain. It was been altered to allow for non-aligned inputs
- * and to allow the block counter to be passed in specifically. */
-
-#include <openssl/chacha.h>
-
-#include "../internal.h"
-
-
-#if defined(ASM_GEN) || \
- !defined(OPENSSL_WINDOWS) && \
- (defined(OPENSSL_X86_64) || defined(OPENSSL_X86)) && defined(__SSE2__)
-
-#define CHACHA_RNDS 20 /* 8 (high speed), 20 (conservative), 12 (middle) */
-
-/* Architecture-neutral way to specify 16-byte vector of ints */
-typedef unsigned vec __attribute__((vector_size(16)));
-
-/* This implementation is designed for Neon, SSE and AltiVec machines. The
- * following specify how to do certain vector operations efficiently on
- * each architecture, using intrinsics.
- * This implementation supports parallel processing of multiple blocks,
- * including potentially using general-purpose registers. */
-#if __ARM_NEON__
-#include <string.h>
-#include <arm_neon.h>
-#define GPR_TOO 1
-#define VBPI 2
-#define ONE (vec) vsetq_lane_u32(1, vdupq_n_u32(0), 0)
-#define LOAD_ALIGNED(m) (vec)(*((vec *)(m)))
-#define LOAD(m) ({ \
- memcpy(alignment_buffer, m, 16); \
- LOAD_ALIGNED(alignment_buffer); \
- })
-#define STORE(m, r) ({ \
- (*((vec *)(alignment_buffer))) = (r); \
- memcpy(m, alignment_buffer, 16); \
- })
-#define ROTV1(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 1)
-#define ROTV2(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 2)
-#define ROTV3(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 3)
-#define ROTW16(x) (vec) vrev32q_u16((uint16x8_t)x)
-#if __clang__
-#define ROTW7(x) (x << ((vec) {7, 7, 7, 7})) ^ (x >> ((vec) {25, 25, 25, 25}))
-#define ROTW8(x) (x << ((vec) {8, 8, 8, 8})) ^ (x >> ((vec) {24, 24, 24, 24}))
-#define ROTW12(x) \
- (x << ((vec) {12, 12, 12, 12})) ^ (x >> ((vec) {20, 20, 20, 20}))
-#else
-#define ROTW7(x) \
- (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 7), (uint32x4_t)x, 25)
-#define ROTW8(x) \
- (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 8), (uint32x4_t)x, 24)
-#define ROTW12(x) \
- (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 12), (uint32x4_t)x, 20)
-#endif
-#elif __SSE2__
-#include <emmintrin.h>
-#define GPR_TOO 0
-#if __clang__
-#define VBPI 4
-#else
-#define VBPI 3
-#endif
-#define ONE (vec) _mm_set_epi32(0, 0, 0, 1)
-#define LOAD(m) (vec) _mm_loadu_si128((const __m128i *)(m))
-#define LOAD_ALIGNED(m) (vec) _mm_load_si128((const __m128i *)(m))
-#define STORE(m, r) _mm_storeu_si128((__m128i *)(m), (__m128i)(r))
-#define ROTV1(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(0, 3, 2, 1))
-#define ROTV2(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(1, 0, 3, 2))
-#define ROTV3(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(2, 1, 0, 3))
-#define ROTW7(x) \
- (vec)(_mm_slli_epi32((__m128i)x, 7) ^ _mm_srli_epi32((__m128i)x, 25))
-#define ROTW12(x) \
- (vec)(_mm_slli_epi32((__m128i)x, 12) ^ _mm_srli_epi32((__m128i)x, 20))
-#if __SSSE3__
-#include <tmmintrin.h>
-#define ROTW8(x) \
- (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, \
- 11, 6, 5, 4, 7, 2, 1, 0, 3))
-#define ROTW16(x) \
- (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, \
- 10, 5, 4, 7, 6, 1, 0, 3, 2))
-#else
-#define ROTW8(x) \
- (vec)(_mm_slli_epi32((__m128i)x, 8) ^ _mm_srli_epi32((__m128i)x, 24))
-#define ROTW16(x) \
- (vec)(_mm_slli_epi32((__m128i)x, 16) ^ _mm_srli_epi32((__m128i)x, 16))
-#endif
-#else
-#error-- Implementation supports only machines with neon or SSE2
-#endif
-
-#ifndef REVV_BE
-#define REVV_BE(x) (x)
-#endif
-
-#ifndef REVW_BE
-#define REVW_BE(x) (x)
-#endif
-
-#define BPI (VBPI + GPR_TOO) /* Blocks computed per loop iteration */
-
-#define DQROUND_VECTORS(a,b,c,d) \
- a += b; d ^= a; d = ROTW16(d); \
- c += d; b ^= c; b = ROTW12(b); \
- a += b; d ^= a; d = ROTW8(d); \
- c += d; b ^= c; b = ROTW7(b); \
- b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); \
- a += b; d ^= a; d = ROTW16(d); \
- c += d; b ^= c; b = ROTW12(b); \
- a += b; d ^= a; d = ROTW8(d); \
- c += d; b ^= c; b = ROTW7(b); \
- b = ROTV3(b); c = ROTV2(c); d = ROTV1(d);
-
-#define QROUND_WORDS(a,b,c,d) \
- a = a+b; d ^= a; d = d<<16 | d>>16; \
- c = c+d; b ^= c; b = b<<12 | b>>20; \
- a = a+b; d ^= a; d = d<< 8 | d>>24; \
- c = c+d; b ^= c; b = b<< 7 | b>>25;
-
-#define WRITE_XOR(in, op, d, v0, v1, v2, v3) \
- STORE(op + d + 0, LOAD(in + d + 0) ^ REVV_BE(v0)); \
- STORE(op + d + 4, LOAD(in + d + 4) ^ REVV_BE(v1)); \
- STORE(op + d + 8, LOAD(in + d + 8) ^ REVV_BE(v2)); \
- STORE(op + d +12, LOAD(in + d +12) ^ REVV_BE(v3));
-
-#if __ARM_NEON__
-/* For ARM, we can't depend on NEON support, so this function is compiled with
- * a different name, along with the generic code, and can be enabled at
- * run-time. */
-void CRYPTO_chacha_20_neon(
-#else
-void CRYPTO_chacha_20(
-#endif
- uint8_t *out,
- const uint8_t *in,
- size_t inlen,
- const uint8_t key[32],
- const uint8_t nonce[12],
- uint32_t counter)
- {
- unsigned iters, i;
- unsigned *op = (unsigned *)out;
- const unsigned *ip = (const unsigned *)in;
- const unsigned *kp = (const unsigned *)key;
-#if defined(__ARM_NEON__)
- uint32_t np[3];
- alignas(16) uint8_t alignment_buffer[16];
-#endif
- vec s0, s1, s2, s3;
- alignas(16) unsigned chacha_const[] =
- {0x61707865,0x3320646E,0x79622D32,0x6B206574};
-#if defined(__ARM_NEON__)
- memcpy(np, nonce, 12);
-#endif
- s0 = LOAD_ALIGNED(chacha_const);
- s1 = LOAD(&((const vec*)kp)[0]);
- s2 = LOAD(&((const vec*)kp)[1]);
- s3 = (vec){
- counter,
- ((const uint32_t*)nonce)[0],
- ((const uint32_t*)nonce)[1],
- ((const uint32_t*)nonce)[2]
- };
-
- for (iters = 0; iters < inlen/(BPI*64); iters++)
- {
-#if GPR_TOO
- register unsigned x0, x1, x2, x3, x4, x5, x6, x7, x8,
- x9, x10, x11, x12, x13, x14, x15;
-#endif
-#if VBPI > 2
- vec v8,v9,v10,v11;
-#endif
-#if VBPI > 3
- vec v12,v13,v14,v15;
-#endif
-
- vec v0,v1,v2,v3,v4,v5,v6,v7;
- v4 = v0 = s0; v5 = v1 = s1; v6 = v2 = s2; v3 = s3;
- v7 = v3 + ONE;
-#if VBPI > 2
- v8 = v4; v9 = v5; v10 = v6;
- v11 = v7 + ONE;
-#endif
-#if VBPI > 3
- v12 = v8; v13 = v9; v14 = v10;
- v15 = v11 + ONE;
-#endif
-#if GPR_TOO
- x0 = chacha_const[0]; x1 = chacha_const[1];
- x2 = chacha_const[2]; x3 = chacha_const[3];
- x4 = kp[0]; x5 = kp[1]; x6 = kp[2]; x7 = kp[3];
- x8 = kp[4]; x9 = kp[5]; x10 = kp[6]; x11 = kp[7];
- x12 = counter+BPI*iters+(BPI-1); x13 = np[0];
- x14 = np[1]; x15 = np[2];
-#endif
- for (i = CHACHA_RNDS/2; i; i--)
- {
- DQROUND_VECTORS(v0,v1,v2,v3)
- DQROUND_VECTORS(v4,v5,v6,v7)
-#if VBPI > 2
- DQROUND_VECTORS(v8,v9,v10,v11)
-#endif
-#if VBPI > 3
- DQROUND_VECTORS(v12,v13,v14,v15)
-#endif
-#if GPR_TOO
- QROUND_WORDS( x0, x4, x8,x12)
- QROUND_WORDS( x1, x5, x9,x13)
- QROUND_WORDS( x2, x6,x10,x14)
- QROUND_WORDS( x3, x7,x11,x15)
- QROUND_WORDS( x0, x5,x10,x15)
- QROUND_WORDS( x1, x6,x11,x12)
- QROUND_WORDS( x2, x7, x8,x13)
- QROUND_WORDS( x3, x4, x9,x14)
-#endif
- }
-
- WRITE_XOR(ip, op, 0, v0+s0, v1+s1, v2+s2, v3+s3)
- s3 += ONE;
- WRITE_XOR(ip, op, 16, v4+s0, v5+s1, v6+s2, v7+s3)
- s3 += ONE;
-#if VBPI > 2
- WRITE_XOR(ip, op, 32, v8+s0, v9+s1, v10+s2, v11+s3)
- s3 += ONE;
-#endif
-#if VBPI > 3
- WRITE_XOR(ip, op, 48, v12+s0, v13+s1, v14+s2, v15+s3)
- s3 += ONE;
-#endif
- ip += VBPI*16;
- op += VBPI*16;
-#if GPR_TOO
- op[0] = REVW_BE(REVW_BE(ip[0]) ^ (x0 + chacha_const[0]));
- op[1] = REVW_BE(REVW_BE(ip[1]) ^ (x1 + chacha_const[1]));
- op[2] = REVW_BE(REVW_BE(ip[2]) ^ (x2 + chacha_const[2]));
- op[3] = REVW_BE(REVW_BE(ip[3]) ^ (x3 + chacha_const[3]));
- op[4] = REVW_BE(REVW_BE(ip[4]) ^ (x4 + kp[0]));
- op[5] = REVW_BE(REVW_BE(ip[5]) ^ (x5 + kp[1]));
- op[6] = REVW_BE(REVW_BE(ip[6]) ^ (x6 + kp[2]));
- op[7] = REVW_BE(REVW_BE(ip[7]) ^ (x7 + kp[3]));
- op[8] = REVW_BE(REVW_BE(ip[8]) ^ (x8 + kp[4]));
- op[9] = REVW_BE(REVW_BE(ip[9]) ^ (x9 + kp[5]));
- op[10] = REVW_BE(REVW_BE(ip[10]) ^ (x10 + kp[6]));
- op[11] = REVW_BE(REVW_BE(ip[11]) ^ (x11 + kp[7]));
- op[12] = REVW_BE(REVW_BE(ip[12]) ^ (x12 + counter+BPI*iters+(BPI-1)));
- op[13] = REVW_BE(REVW_BE(ip[13]) ^ (x13 + np[0]));
- op[14] = REVW_BE(REVW_BE(ip[14]) ^ (x14 + np[1]));
- op[15] = REVW_BE(REVW_BE(ip[15]) ^ (x15 + np[2]));
- s3 += ONE;
- ip += 16;
- op += 16;
-#endif
- }
-
- for (iters = inlen%(BPI*64)/64; iters != 0; iters--)
- {
- vec v0 = s0, v1 = s1, v2 = s2, v3 = s3;
- for (i = CHACHA_RNDS/2; i; i--)
- {
- DQROUND_VECTORS(v0,v1,v2,v3);
- }
- WRITE_XOR(ip, op, 0, v0+s0, v1+s1, v2+s2, v3+s3)
- s3 += ONE;
- ip += 16;
- op += 16;
- }
-
- inlen = inlen % 64;
- if (inlen)
- {
- alignas(16) vec buf[4];
- vec v0,v1,v2,v3;
- v0 = s0; v1 = s1; v2 = s2; v3 = s3;
- for (i = CHACHA_RNDS/2; i; i--)
- {
- DQROUND_VECTORS(v0,v1,v2,v3);
- }
-
- if (inlen >= 16)
- {
- STORE(op + 0, LOAD(ip + 0) ^ REVV_BE(v0 + s0));
- if (inlen >= 32)
- {
- STORE(op + 4, LOAD(ip + 4) ^ REVV_BE(v1 + s1));
- if (inlen >= 48)
- {
- STORE(op + 8, LOAD(ip + 8) ^
- REVV_BE(v2 + s2));
- buf[3] = REVV_BE(v3 + s3);
- }
- else
- buf[2] = REVV_BE(v2 + s2);
- }
- else
- buf[1] = REVV_BE(v1 + s1);
- }
- else
- buf[0] = REVV_BE(v0 + s0);
-
- for (i=inlen & ~15; i<inlen; i++)
- ((char *)op)[i] = ((const char *)ip)[i] ^ ((const char *)buf)[i];
- }
- }
-
-#endif /* ASM_GEN || !OPENSSL_WINDOWS && (OPENSSL_X86_64 || OPENSSL_X86) && SSE2 */
diff --git a/crypto/chacha/chacha_vec_arm.S b/crypto/chacha/chacha_vec_arm.S
deleted file mode 100644
index f18c867e..00000000
--- a/crypto/chacha/chacha_vec_arm.S
+++ /dev/null
@@ -1,1447 +0,0 @@
-# Copyright (c) 2014, Google Inc.
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-# This file contains a pre-compiled version of chacha_vec.c for ARM. This is
-# needed to support switching on NEON code at runtime. If the whole of OpenSSL
-# were to be compiled with the needed flags to build chacha_vec.c, then it
-# wouldn't be possible to run on non-NEON systems.
-#
-# This file was generated by chacha_vec_arm_generate.go using the following
-# compiler command:
-#
-# /opt/gcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc -O3 -mcpu=cortex-a8 -mfpu=neon -fpic -DASM_GEN -I ../../include -S chacha_vec.c -o -
-
-#if !defined(OPENSSL_NO_ASM)
-#if defined(__arm__)
-
- .syntax unified
- .cpu cortex-a8
- .eabi_attribute 27, 3
-
-# EABI attribute 28 sets whether VFP register arguments were used to build this
-# file. If object files are inconsistent on this point, the linker will refuse
-# to link them. Thus we report whatever the compiler expects since we don't use
-# VFP arguments.
-
-#if defined(__ARM_PCS_VFP)
- .eabi_attribute 28, 1
-#else
- .eabi_attribute 28, 0
-#endif
-
- .fpu neon
- .eabi_attribute 20, 1
- .eabi_attribute 21, 1
- .eabi_attribute 23, 3
- .eabi_attribute 24, 1
- .eabi_attribute 25, 1
- .eabi_attribute 26, 2
- .eabi_attribute 30, 2
- .eabi_attribute 34, 1
- .eabi_attribute 18, 4
- .thumb
- .file "chacha_vec.c"
- .text
- .align 2
- .global CRYPTO_chacha_20_neon
- .hidden CRYPTO_chacha_20_neon
- .thumb
- .thumb_func
- .type CRYPTO_chacha_20_neon, %function
-CRYPTO_chacha_20_neon:
- @ args = 8, pretend = 0, frame = 160
- @ frame_needed = 1, uses_anonymous_args = 0
- push {r4, r5, r6, r7, r8, r9, r10, fp, lr}
- mov r9, r3
- vpush.64 {d8, d9, d10, d11, d12, d13, d14, d15}
- mov r10, r2
- ldr r4, .L91+16
- mov fp, r1
- mov r8, r9
-.LPIC16:
- add r4, pc
- sub sp, sp, #164
- add r7, sp, #0
- sub sp, sp, #112
- add lr, r7, #148
- str r0, [r7, #80]
- str r1, [r7, #12]
- str r2, [r7, #8]
- ldmia r4, {r0, r1, r2, r3}
- add r4, sp, #15
- bic r4, r4, #15
- ldr r6, [r7, #264]
- str r4, [r7, #88]
- mov r5, r4
- adds r4, r4, #64
- add ip, r5, #80
- str r9, [r7, #56]
- stmia r4, {r0, r1, r2, r3}
- movw r4, #43691
- ldr r0, [r6] @ unaligned
- movt r4, 43690
- ldr r1, [r6, #4] @ unaligned
- ldr r2, [r6, #8] @ unaligned
- ldr r3, [r9, #12] @ unaligned
- str ip, [r7, #84]
- stmia lr!, {r0, r1, r2}
- mov lr, ip
- ldr r1, [r9, #4] @ unaligned
- ldr r2, [r9, #8] @ unaligned
- ldr r0, [r9] @ unaligned
- vldr d24, [r5, #64]
- vldr d25, [r5, #72]
- umull r4, r5, r10, r4
- stmia ip!, {r0, r1, r2, r3}
- ldr r0, [r8, #16]! @ unaligned
- ldr r2, [r7, #88]
- ldr r4, [r7, #268]
- ldr r1, [r8, #4] @ unaligned
- vldr d26, [r2, #80]
- vldr d27, [r2, #88]
- ldr r3, [r8, #12] @ unaligned
- ldr r2, [r8, #8] @ unaligned
- stmia lr!, {r0, r1, r2, r3}
- ldr r3, [r6]
- ldr r1, [r6, #4]
- ldr r6, [r6, #8]
- str r3, [r7, #68]
- str r3, [r7, #132]
- lsrs r3, r5, #7
- str r6, [r7, #140]
- str r6, [r7, #60]
- ldr r6, [r7, #88]
- str r4, [r7, #128]
- str r1, [r7, #136]
- str r1, [r7, #64]
- vldr d28, [r6, #80]
- vldr d29, [r6, #88]
- vldr d22, [r7, #128]
- vldr d23, [r7, #136]
- beq .L26
- mov r5, r6
- lsls r2, r3, #8
- sub r3, r2, r3, lsl #6
- ldr r2, [r5, #68]
- ldr r6, [r6, #64]
- vldr d0, .L91
- vldr d1, .L91+8
- str r2, [r7, #48]
- ldr r2, [r5, #72]
- str r3, [r7, #4]
- str r6, [r7, #52]
- str r2, [r7, #44]
- adds r2, r4, #2
- str r2, [r7, #72]
- ldr r2, [r5, #76]
- str fp, [r7, #76]
- str r2, [r7, #40]
- ldr r2, [r7, #80]
- adds r3, r2, r3
- str r3, [r7, #16]
-.L4:
- ldr r5, [r7, #56]
- add r8, r7, #40
- ldr r4, [r7, #68]
- vadd.i32 q3, q11, q0
- ldmia r8, {r8, r9, r10, fp}
- mov r1, r5
- ldr r2, [r5, #4]
- vmov q8, q14 @ v4si
- ldr r3, [r5]
- vmov q1, q13 @ v4si
- ldr r6, [r1, #28]
- vmov q9, q12 @ v4si
- mov r0, r2
- ldr r2, [r5, #8]
- str r4, [r7, #112]
- movs r1, #10
- ldr r4, [r7, #72]
- vmov q2, q11 @ v4si
- ldr lr, [r5, #20]
- vmov q15, q14 @ v4si
- str r3, [r7, #108]
- vmov q5, q13 @ v4si
- str r2, [r7, #116]
- vmov q10, q12 @ v4si
- ldr r2, [r5, #12]
- ldr ip, [r5, #16]
- ldr r3, [r7, #64]
- ldr r5, [r5, #24]
- str r6, [r7, #120]
- str r1, [r7, #92]
- ldr r6, [r7, #60]
- str r4, [r7, #100]
- ldr r1, [r7, #116]
- ldr r4, [r7, #108]
- str r8, [r7, #96]
- mov r8, r10
- str lr, [r7, #104]
- mov r10, r9
- mov lr, r3
- mov r9, r5
- str r6, [r7, #124]
- b .L92
-.L93:
- .align 3
-.L91:
- .word 1
- .word 0
- .word 0
- .word 0
- .word .LANCHOR0-(.LPIC16+4)
-.L92:
-.L3:
- vadd.i32 q9, q9, q1
- add r3, r8, r0
- vadd.i32 q10, q10, q5
- add r5, fp, r4
- veor q3, q3, q9
- mov r6, r3
- veor q2, q2, q10
- ldr r3, [r7, #96]
- str r5, [r7, #116]
- add r10, r10, r1
- vrev32.16 q3, q3
- str r6, [r7, #108]
- vadd.i32 q8, q8, q3
- vrev32.16 q2, q2
- vadd.i32 q15, q15, q2
- mov fp, r3
- ldr r3, [r7, #100]
- veor q4, q8, q1
- veor q6, q15, q5
- add fp, fp, r2
- eors r3, r3, r5
- mov r5, r6
- ldr r6, [r7, #112]
- vshl.i32 q1, q4, #12
- vshl.i32 q5, q6, #12
- ror r3, r3, #16
- eors r6, r6, r5
- eor lr, lr, r10
- vsri.32 q1, q4, #20
- mov r5, r6
- ldr r6, [r7, #124]
- vsri.32 q5, q6, #20
- str r3, [r7, #124]
- eor r6, r6, fp
- ror r5, r5, #16
- vadd.i32 q9, q9, q1
- ror lr, lr, #16
- ror r3, r6, #16
- ldr r6, [r7, #124]
- vadd.i32 q10, q10, q5
- add r9, r9, lr
- veor q4, q9, q3
- add ip, ip, r6
- ldr r6, [r7, #104]
- veor q6, q10, q2
- eor r4, ip, r4
- str r3, [r7, #104]
- vshl.i32 q3, q4, #8
- eor r1, r9, r1
- mov r8, r6
- ldr r6, [r7, #120]
- vshl.i32 q2, q6, #8
- ror r4, r4, #20
- add r6, r6, r3
- vsri.32 q3, q4, #24
- str r6, [r7, #100]
- eors r2, r2, r6
- ldr r6, [r7, #116]
- vsri.32 q2, q6, #24
- add r8, r8, r5
- ror r2, r2, #20
- adds r6, r4, r6
- vadd.i32 q4, q8, q3
- eor r0, r8, r0
- vadd.i32 q15, q15, q2
- mov r3, r6
- ldr r6, [r7, #108]
- veor q6, q4, q1
- ror r0, r0, #20
- str r3, [r7, #112]
- veor q5, q15, q5
- adds r6, r0, r6
- str r6, [r7, #120]
- mov r6, r3
- ldr r3, [r7, #124]
- vshl.i32 q8, q6, #7
- add fp, fp, r2
- eors r3, r3, r6
- ldr r6, [r7, #120]
- vshl.i32 q1, q5, #7
- ror r1, r1, #20
- eors r5, r5, r6
- vsri.32 q8, q6, #25
- ldr r6, [r7, #104]
- ror r3, r3, #24
- ror r5, r5, #24
- vsri.32 q1, q5, #25
- str r5, [r7, #116]
- eor r6, fp, r6
- ldr r5, [r7, #116]
- add r10, r10, r1
- add ip, r3, ip
- vext.32 q8, q8, q8, #1
- str ip, [r7, #124]
- add ip, r5, r8
- ldr r5, [r7, #100]
- eor lr, r10, lr
- ror r6, r6, #24
- vext.32 q1, q1, q1, #1
- add r8, r6, r5
- vadd.i32 q9, q9, q8
- ldr r5, [r7, #124]
- vext.32 q3, q3, q3, #3
- vadd.i32 q10, q10, q1
- ror lr, lr, #24
- eor r0, ip, r0
- vext.32 q2, q2, q2, #3
- add r9, r9, lr
- eors r4, r4, r5
- veor q3, q9, q3
- ldr r5, [r7, #112]
- eor r1, r9, r1
- ror r0, r0, #25
- veor q2, q10, q2
- adds r5, r0, r5
- vext.32 q4, q4, q4, #2
- str r5, [r7, #112]
- ldr r5, [r7, #120]
- ror r1, r1, #25
- vrev32.16 q3, q3
- eor r2, r8, r2
- vext.32 q15, q15, q15, #2
- adds r5, r1, r5
- vadd.i32 q4, q4, q3
- ror r4, r4, #25
- vrev32.16 q2, q2
- str r5, [r7, #100]
- vadd.i32 q15, q15, q2
- eors r3, r3, r5
- ldr r5, [r7, #112]
- add fp, fp, r4
- veor q8, q4, q8
- ror r2, r2, #25
- veor q1, q15, q1
- eor lr, fp, lr
- eors r6, r6, r5
- ror r3, r3, #16
- ldr r5, [r7, #116]
- add r10, r10, r2
- str r3, [r7, #120]
- ror lr, lr, #16
- ldr r3, [r7, #120]
- eor r5, r10, r5
- vshl.i32 q5, q8, #12
- add ip, lr, ip
- vshl.i32 q6, q1, #12
- str ip, [r7, #104]
- add ip, r3, r8
- str ip, [r7, #116]
- ldr r3, [r7, #124]
- ror r5, r5, #16
- vsri.32 q5, q8, #20
- ror r6, r6, #16
- add ip, r5, r3
- ldr r3, [r7, #104]
- vsri.32 q6, q1, #20
- add r9, r9, r6
- eor r2, ip, r2
- eors r4, r4, r3
- ldr r3, [r7, #116]
- eor r0, r9, r0
- vadd.i32 q9, q9, q5
- ror r4, r4, #20
- eors r1, r1, r3
- vadd.i32 q10, q10, q6
- ror r3, r2, #20
- str r3, [r7, #108]
- ldr r3, [r7, #112]
- veor q3, q9, q3
- ror r0, r0, #20
- add r8, r4, fp
- veor q2, q10, q2
- add fp, r0, r3
- ldr r3, [r7, #100]
- ror r1, r1, #20
- mov r2, r8
- vshl.i32 q8, q3, #8
- str r8, [r7, #96]
- add r8, r1, r3
- ldr r3, [r7, #108]
- vmov q1, q6 @ v4si
- vshl.i32 q6, q2, #8
- eor r6, fp, r6
- add r10, r10, r3
- ldr r3, [r7, #120]
- vsri.32 q8, q3, #24
- eor lr, r2, lr
- eor r3, r8, r3
- ror r2, r6, #24
- vsri.32 q6, q2, #24
- eor r5, r10, r5
- str r2, [r7, #124]
- ror r2, r3, #24
- ldr r3, [r7, #104]
- vmov q3, q8 @ v4si
- vadd.i32 q15, q15, q6
- ror lr, lr, #24
- vadd.i32 q8, q4, q8
- ror r6, r5, #24
- add r5, lr, r3
- ldr r3, [r7, #124]
- veor q4, q8, q5
- add ip, ip, r6
- vmov q2, q6 @ v4si
- add r9, r9, r3
- veor q6, q15, q1
- ldr r3, [r7, #116]
- vshl.i32 q1, q4, #7
- str r2, [r7, #100]
- add r3, r3, r2
- str r3, [r7, #120]
- vshl.i32 q5, q6, #7
- eors r1, r1, r3
- ldr r3, [r7, #108]
- vsri.32 q1, q4, #25
- eors r4, r4, r5
- eor r0, r9, r0
- eor r2, ip, r3
- vsri.32 q5, q6, #25
- ldr r3, [r7, #92]
- ror r4, r4, #25
- str r6, [r7, #112]
- ror r0, r0, #25
- subs r3, r3, #1
- str r5, [r7, #104]
- ror r1, r1, #25
- ror r2, r2, #25
- vext.32 q15, q15, q15, #2
- str r3, [r7, #92]
- vext.32 q2, q2, q2, #1
- vext.32 q8, q8, q8, #2
- vext.32 q3, q3, q3, #1
- vext.32 q5, q5, q5, #3
- vext.32 q1, q1, q1, #3
- bne .L3
- ldr r3, [r7, #84]
- vadd.i32 q4, q12, q10
- str r9, [r7, #92]
- mov r9, r10
- mov r10, r8
- ldr r8, [r7, #96]
- str lr, [r7, #96]
- mov lr, r5
- ldr r5, [r7, #52]
- vadd.i32 q5, q13, q5
- ldr r6, [r7, #76]
- vadd.i32 q15, q14, q15
- add fp, fp, r5
- ldr r5, [r7, #48]
- str r3, [r7, #104]
- vadd.i32 q7, q14, q8
- ldr r3, [r6, #12] @ unaligned
- add r10, r10, r5
- str r0, [r7, #36]
- vadd.i32 q2, q11, q2
- ldr r0, [r6] @ unaligned
- vadd.i32 q6, q12, q9
- ldr r5, [r7, #104]
- vadd.i32 q1, q13, q1
- str r1, [r7, #116]
- vadd.i32 q11, q11, q0
- ldr r1, [r6, #4] @ unaligned
- str r2, [r7, #32]
- vadd.i32 q3, q11, q3
- ldr r2, [r6, #8] @ unaligned
- vadd.i32 q11, q11, q0
- str r4, [r7, #108]
- ldr r4, [r7, #100]
- vadd.i32 q11, q11, q0
- stmia r5!, {r0, r1, r2, r3}
- ldr r2, [r7, #88]
- ldr r3, [r7, #44]
- ldr r5, [r7, #84]
- vldr d20, [r2, #80]
- vldr d21, [r2, #88]
- add r3, r9, r3
- str r3, [r7, #104]
- veor q10, q10, q4
- ldr r3, [r7, #40]
- add r3, r8, r3
- str r3, [r7, #100]
- ldr r3, [r7, #72]
- vstr d20, [r2, #80]
- vstr d21, [r2, #88]
- adds r1, r4, r3
- str r1, [r7, #28]
- ldmia r5!, {r0, r1, r2, r3}
- ldr r4, [r7, #68]
- ldr r5, [r7, #112]
- ldr r8, [r7, #84]
- add r5, r5, r4
- ldr r4, [r7, #96]
- str r5, [r7, #24]
- ldr r5, [r7, #64]
- add r4, r4, r5
- ldr r5, [r7, #60]
- str r4, [r7, #96]
- ldr r4, [r7, #124]
- add r4, r4, r5
- str r4, [r7, #20]
- ldr r4, [r7, #80]
- mov r5, r8
- str r0, [r4] @ unaligned
- mov r0, r4
- str r1, [r4, #4] @ unaligned
- mov r4, r8
- str r2, [r0, #8] @ unaligned
- mov r8, r0
- str r3, [r0, #12] @ unaligned
- mov r9, r4
- ldr r0, [r6, #16]! @ unaligned
- ldr r3, [r6, #12] @ unaligned
- ldr r1, [r6, #4] @ unaligned
- ldr r2, [r6, #8] @ unaligned
- ldr r6, [r7, #76]
- stmia r5!, {r0, r1, r2, r3}
- mov r5, r8
- ldr r3, [r7, #88]
- vldr d20, [r3, #80]
- vldr d21, [r3, #88]
- veor q10, q10, q5
- vstr d20, [r3, #80]
- vstr d21, [r3, #88]
- ldmia r4!, {r0, r1, r2, r3}
- mov r4, r9
- str r0, [r8, #16] @ unaligned
- str r1, [r8, #20] @ unaligned
- str r2, [r8, #24] @ unaligned
- str r3, [r8, #28] @ unaligned
- mov r8, r5
- ldr r0, [r6, #32]! @ unaligned
- mov r5, r9
- ldr r1, [r6, #4] @ unaligned
- ldr r2, [r6, #8] @ unaligned
- ldr r3, [r6, #12] @ unaligned
- ldr r6, [r7, #76]
- stmia r5!, {r0, r1, r2, r3}
- mov r5, r8
- ldr r1, [r7, #88]
- vldr d16, [r1, #80]
- vldr d17, [r1, #88]
- veor q15, q8, q15
- vstr d30, [r1, #80]
- vstr d31, [r1, #88]
- ldmia r4!, {r0, r1, r2, r3}
- mov r4, r9
- str r0, [r8, #32] @ unaligned
- str r1, [r8, #36] @ unaligned
- str r2, [r8, #40] @ unaligned
- str r3, [r8, #44] @ unaligned
- mov r8, r5
- ldr r0, [r6, #48]! @ unaligned
- ldr r1, [r6, #4] @ unaligned
- ldr r2, [r6, #8] @ unaligned
- ldr r3, [r6, #12] @ unaligned
- ldr r6, [r7, #76]
- stmia r4!, {r0, r1, r2, r3}
- mov r4, r9
- ldr r1, [r7, #88]
- str r9, [r7, #112]
- vldr d18, [r1, #80]
- vldr d19, [r1, #88]
- veor q9, q9, q2
- vstr d18, [r1, #80]
- vstr d19, [r1, #88]
- ldmia r9!, {r0, r1, r2, r3}
- str r0, [r5, #48] @ unaligned
- str r1, [r5, #52] @ unaligned
- str r2, [r5, #56] @ unaligned
- str r3, [r5, #60] @ unaligned
- ldr r0, [r6, #64]! @ unaligned
- ldr r1, [r6, #4] @ unaligned
- ldr r2, [r6, #8] @ unaligned
- ldr r3, [r6, #12] @ unaligned
- ldr r6, [r7, #76]
- mov r9, r6
- mov r6, r4
- stmia r6!, {r0, r1, r2, r3}
- mov r6, r4
- ldr r1, [r7, #88]
- vldr d18, [r1, #80]
- vldr d19, [r1, #88]
- veor q9, q9, q6
- vstr d18, [r1, #80]
- vstr d19, [r1, #88]
- ldmia r4!, {r0, r1, r2, r3}
- mov r4, r6
- str r3, [r5, #76] @ unaligned
- mov r3, r9
- str r2, [r5, #72] @ unaligned
- str r0, [r5, #64] @ unaligned
- str r1, [r5, #68] @ unaligned
- mov r5, r4
- ldr r0, [r3, #80]! @ unaligned
- mov r9, r3
- ldr r1, [r9, #4] @ unaligned
- ldr r2, [r9, #8] @ unaligned
- ldr r3, [r9, #12] @ unaligned
- mov r9, r4
- ldr r6, [r7, #76]
- str r9, [r7, #124]
- stmia r5!, {r0, r1, r2, r3}
- mov r5, r8
- ldr r1, [r7, #88]
- vldr d18, [r1, #80]
- vldr d19, [r1, #88]
- veor q1, q9, q1
- vstr d2, [r1, #80]
- vstr d3, [r1, #88]
- ldmia r4!, {r0, r1, r2, r3}
- mov r4, r9
- str r0, [r8, #80] @ unaligned
- str r1, [r8, #84] @ unaligned
- str r2, [r8, #88] @ unaligned
- str r3, [r8, #92] @ unaligned
- ldr r0, [r6, #96]! @ unaligned
- ldr r3, [r6, #12] @ unaligned
- ldr r1, [r6, #4] @ unaligned
- ldr r2, [r6, #8] @ unaligned
- ldr r6, [r7, #76]
- stmia r4!, {r0, r1, r2, r3}
- mov r4, r9
- ldr r3, [r7, #88]
- vldr d16, [r3, #80]
- vldr d17, [r3, #88]
- veor q8, q8, q7
- vstr d16, [r3, #80]
- vstr d17, [r3, #88]
- ldmia r9!, {r0, r1, r2, r3}
- str r0, [r5, #96] @ unaligned
- str r1, [r5, #100] @ unaligned
- str r2, [r5, #104] @ unaligned
- str r3, [r5, #108] @ unaligned
- ldr r0, [r6, #112]! @ unaligned
- ldr r1, [r6, #4] @ unaligned
- ldr r2, [r6, #8] @ unaligned
- ldr r3, [r6, #12] @ unaligned
- mov r6, r4
- stmia r6!, {r0, r1, r2, r3}
- mov r6, r5
- ldr r3, [r7, #88]
- vldr d16, [r3, #80]
- vldr d17, [r3, #88]
- veor q8, q8, q3
- vstr d16, [r3, #80]
- vstr d17, [r3, #88]
- ldmia r4!, {r0, r1, r2, r3}
- mov r4, r5
- mov r8, r4
- str r2, [r5, #120] @ unaligned
- ldr r2, [r7, #76]
- str r0, [r5, #112] @ unaligned
- str r1, [r5, #116] @ unaligned
- str r3, [r5, #124] @ unaligned
- ldr r3, [r2, #128]
- ldr r1, [r7, #104]
- eor r3, fp, r3
- str r3, [r5, #128]
- ldr r3, [r2, #132]
- mov r5, r2
- eor r3, r10, r3
- str r3, [r6, #132]
- ldr r3, [r2, #136]
- mov r6, r5
- eors r1, r1, r3
- str r1, [r8, #136]
- ldr r1, [r7, #56]
- ldr r3, [r2, #140]
- ldr r2, [r7, #100]
- ldr r0, [r7, #108]
- eors r3, r3, r2
- str r3, [r4, #140]
- ldr r3, [r1]
- ldr r2, [r5, #144]
- mov r8, r0
- add r8, r8, r3
- mov r5, r6
- mov r3, r8
- eors r2, r2, r3
- str r2, [r4, #144]
- ldr r3, [r6, #148]
- ldr r2, [r1, #4]
- ldr r6, [r7, #36]
- add r6, r6, r2
- eors r3, r3, r6
- mov r6, r1
- str r3, [r4, #148]
- ldr r2, [r1, #8]
- ldr r1, [r7, #116]
- ldr r3, [r5, #152]
- mov r8, r1
- add r8, r8, r2
- ldr r1, [r7, #32]
- mov r2, r8
- eors r3, r3, r2
- str r3, [r4, #152]
- mov r8, r4
- ldr r2, [r6, #12]
- ldr r3, [r5, #156]
- add r1, r1, r2
- eors r3, r3, r1
- str r3, [r4, #156]
- ldr r2, [r6, #16]
- mov r1, r4
- ldr r3, [r5, #160]
- mov r4, r5
- add ip, ip, r2
- mov r5, r6
- eor r3, ip, r3
- str r3, [r1, #160]
- ldr r2, [r6, #20]
- ldr r3, [r4, #164]
- add lr, lr, r2
- ldr r2, [r7, #92]
- eor r3, lr, r3
- str r3, [r1, #164]
- ldr r6, [r5, #24]
- mov lr, r4
- ldr r3, [r4, #168]
- add r2, r2, r6
- ldr r6, [r7, #120]
- eors r3, r3, r2
- str r3, [r1, #168]
- ldr r5, [r5, #28]
- ldr r3, [r4, #172]
- add r6, r6, r5
- eors r3, r3, r6
- str r3, [r1, #172]
- ldr r4, [r4, #176]
- ldr r0, [r7, #28]
- ldr r5, [r7, #24]
- eors r4, r4, r0
- str r4, [r8, #176]
- ldr r0, [lr, #180]
- ldr r2, [r7, #96]
- eors r0, r0, r5
- str r0, [r8, #180]
- ldr r1, [lr, #184]
- ldr r4, [r7, #20]
- eors r1, r1, r2
- str r1, [r8, #184]
- ldr r2, [lr, #188]
- add r1, lr, #192
- ldr r3, [r7, #72]
- eors r2, r2, r4
- str r2, [r8, #188]
- ldr r2, [r7, #16]
- adds r3, r3, #3
- str r3, [r7, #72]
- mov r3, r8
- adds r3, r3, #192
- str r1, [r7, #76]
- cmp r2, r3
- str r3, [r7, #80]
- bne .L4
- ldr r3, [r7, #12]
- ldr r2, [r7, #4]
- add r3, r3, r2
- str r3, [r7, #12]
-.L2:
- ldr r1, [r7, #8]
- movw r2, #43691
- movt r2, 43690
- umull r2, r3, r1, r2
- lsr fp, r3, #7
- lsl r3, fp, #8
- sub fp, r3, fp, lsl #6
- rsb fp, fp, r1
- lsrs fp, fp, #6
- beq .L6
- ldr r5, [r7, #12]
- ldr r4, [r7, #16]
- ldr r6, [r7, #88]
- ldr lr, [r7, #84]
- vldr d30, .L94
- vldr d31, .L94+8
- str fp, [r7, #120]
- str fp, [r7, #124]
-.L8:
- vmov q2, q11 @ v4si
- movs r3, #10
- vmov q8, q14 @ v4si
- vmov q9, q13 @ v4si
- vmov q10, q12 @ v4si
-.L7:
- vadd.i32 q10, q10, q9
- subs r3, r3, #1
- veor q3, q2, q10
- vrev32.16 q3, q3
- vadd.i32 q8, q8, q3
- veor q9, q8, q9
- vshl.i32 q2, q9, #12
- vsri.32 q2, q9, #20
- vadd.i32 q10, q10, q2
- veor q3, q10, q3
- vshl.i32 q9, q3, #8
- vsri.32 q9, q3, #24
- vadd.i32 q8, q8, q9
- vext.32 q9, q9, q9, #3
- veor q2, q8, q2
- vext.32 q8, q8, q8, #2
- vshl.i32 q3, q2, #7
- vsri.32 q3, q2, #25
- vext.32 q3, q3, q3, #1
- vadd.i32 q10, q10, q3
- veor q9, q10, q9
- vrev32.16 q9, q9
- vadd.i32 q8, q8, q9
- veor q3, q8, q3
- vshl.i32 q2, q3, #12
- vsri.32 q2, q3, #20
- vadd.i32 q10, q10, q2
- vmov q3, q2 @ v4si
- veor q9, q10, q9
- vshl.i32 q2, q9, #8
- vsri.32 q2, q9, #24
- vadd.i32 q8, q8, q2
- vext.32 q2, q2, q2, #1
- veor q3, q8, q3
- vext.32 q8, q8, q8, #2
- vshl.i32 q9, q3, #7
- vsri.32 q9, q3, #25
- vext.32 q9, q9, q9, #3
- bne .L7
- ldr r0, [r5] @ unaligned
- vadd.i32 q1, q12, q10
- ldr r1, [r5, #4] @ unaligned
- mov ip, lr
- ldr r2, [r5, #8] @ unaligned
- mov r9, lr
- ldr r3, [r5, #12] @ unaligned
- mov r10, r5
- vadd.i32 q9, q13, q9
- mov r8, lr
- vadd.i32 q8, q14, q8
- stmia ip!, {r0, r1, r2, r3}
- mov ip, lr
- vldr d20, [r6, #80]
- vldr d21, [r6, #88]
- vadd.i32 q3, q11, q2
- veor q10, q10, q1
- vadd.i32 q11, q11, q15
- vstr d20, [r6, #80]
- vstr d21, [r6, #88]
- ldmia r9!, {r0, r1, r2, r3}
- mov r9, r5
- str r0, [r4] @ unaligned
- str r1, [r4, #4] @ unaligned
- str r2, [r4, #8] @ unaligned
- str r3, [r4, #12] @ unaligned
- ldr r0, [r10, #16]! @ unaligned
- ldr r1, [r10, #4] @ unaligned
- ldr r2, [r10, #8] @ unaligned
- ldr r3, [r10, #12] @ unaligned
- add r10, r4, #48
- adds r4, r4, #64
- stmia r8!, {r0, r1, r2, r3}
- mov r8, lr
- vldr d20, [r6, #80]
- vldr d21, [r6, #88]
- veor q10, q10, q9
- vstr d20, [r6, #80]
- vstr d21, [r6, #88]
- ldmia ip!, {r0, r1, r2, r3}
- mov ip, lr
- str r0, [r4, #-48] @ unaligned
- str r1, [r4, #-44] @ unaligned
- str r2, [r4, #-40] @ unaligned
- str r3, [r4, #-36] @ unaligned
- ldr r0, [r9, #32]! @ unaligned
- ldr r1, [r9, #4] @ unaligned
- ldr r2, [r9, #8] @ unaligned
- ldr r3, [r9, #12] @ unaligned
- mov r9, r5
- adds r5, r5, #64
- stmia r8!, {r0, r1, r2, r3}
- mov r8, lr
- vldr d18, [r6, #80]
- vldr d19, [r6, #88]
- veor q9, q9, q8
- vstr d18, [r6, #80]
- vstr d19, [r6, #88]
- ldmia ip!, {r0, r1, r2, r3}
- mov ip, lr
- str r0, [r4, #-32] @ unaligned
- str r1, [r4, #-28] @ unaligned
- str r2, [r4, #-24] @ unaligned
- str r3, [r4, #-20] @ unaligned
- ldr r0, [r9, #48]! @ unaligned
- ldr r1, [r9, #4] @ unaligned
- ldr r2, [r9, #8] @ unaligned
- ldr r3, [r9, #12] @ unaligned
- stmia r8!, {r0, r1, r2, r3}
- vldr d16, [r6, #80]
- vldr d17, [r6, #88]
- veor q8, q8, q3
- vstr d16, [r6, #80]
- vstr d17, [r6, #88]
- ldmia ip!, {r0, r1, r2, r3}
- str r0, [r4, #-16] @ unaligned
- str r1, [r4, #-12] @ unaligned
- str r3, [r10, #12] @ unaligned
- ldr r3, [r7, #124]
- str r2, [r10, #8] @ unaligned
- cmp r3, #1
- beq .L87
- movs r3, #1
- str r3, [r7, #124]
- b .L8
-.L95:
- .align 3
-.L94:
- .word 1
- .word 0
- .word 0
- .word 0
-.L87:
- ldr fp, [r7, #120]
- ldr r3, [r7, #12]
- lsl fp, fp, #6
- add r3, r3, fp
- str r3, [r7, #12]
- ldr r3, [r7, #16]
- add r3, r3, fp
- str r3, [r7, #16]
-.L6:
- ldr r3, [r7, #8]
- ands r9, r3, #63
- beq .L1
- vmov q3, q11 @ v4si
- movs r3, #10
- vmov q8, q14 @ v4si
- mov r5, r9
- vmov q15, q13 @ v4si
- vmov q10, q12 @ v4si
-.L10:
- vadd.i32 q10, q10, q15
- subs r3, r3, #1
- veor q9, q3, q10
- vrev32.16 q9, q9
- vadd.i32 q8, q8, q9
- veor q15, q8, q15
- vshl.i32 q3, q15, #12
- vsri.32 q3, q15, #20
- vadd.i32 q10, q10, q3
- veor q15, q10, q9
- vshl.i32 q9, q15, #8
- vsri.32 q9, q15, #24
- vadd.i32 q8, q8, q9
- vext.32 q9, q9, q9, #3
- veor q3, q8, q3
- vext.32 q8, q8, q8, #2
- vshl.i32 q15, q3, #7
- vsri.32 q15, q3, #25
- vext.32 q15, q15, q15, #1
- vadd.i32 q10, q10, q15
- veor q9, q10, q9
- vrev32.16 q9, q9
- vadd.i32 q8, q8, q9
- veor q15, q8, q15
- vshl.i32 q3, q15, #12
- vsri.32 q3, q15, #20
- vadd.i32 q10, q10, q3
- vmov q15, q3 @ v4si
- veor q9, q10, q9
- vshl.i32 q3, q9, #8
- vsri.32 q3, q9, #24
- vadd.i32 q8, q8, q3
- vext.32 q3, q3, q3, #1
- veor q9, q8, q15
- vext.32 q8, q8, q8, #2
- vshl.i32 q15, q9, #7
- vsri.32 q15, q9, #25
- vext.32 q15, q15, q15, #3
- bne .L10
- cmp r5, #15
- mov r9, r5
- bhi .L88
- vadd.i32 q12, q12, q10
- ldr r3, [r7, #88]
- vst1.64 {d24-d25}, [r3:128]
-.L14:
- ldr r3, [r7, #8]
- and r2, r3, #48
- cmp r9, r2
- bls .L1
- ldr r6, [r7, #16]
- add r3, r2, #16
- ldr r1, [r7, #12]
- rsb ip, r2, r9
- adds r0, r1, r2
- mov r4, r6
- add r1, r1, r3
- add r4, r4, r2
- add r3, r3, r6
- cmp r0, r3
- it cc
- cmpcc r4, r1
- ite cs
- movcs r3, #1
- movcc r3, #0
- cmp ip, #18
- ite ls
- movls r3, #0
- andhi r3, r3, #1
- cmp r3, #0
- beq .L16
- and r1, r0, #7
- mov r3, r2
- negs r1, r1
- and r1, r1, #15
- cmp r1, ip
- it cs
- movcs r1, ip
- cmp r1, #0
- beq .L17
- ldr r5, [r7, #88]
- cmp r1, #1
- ldrb r0, [r0] @ zero_extendqisi2
- add r3, r2, #1
- ldrb lr, [r5, r2] @ zero_extendqisi2
- mov r6, r5
- eor r0, lr, r0
- strb r0, [r4]
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #2
- ldrb r4, [r5, r3] @ zero_extendqisi2
- ldr r5, [r7, #16]
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #2
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #3
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #3
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #4
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #4
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #5
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #5
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #6
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #6
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #7
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #7
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #8
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #8
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #9
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #9
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #10
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #10
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #11
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #11
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #12
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #12
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #13
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #13
- beq .L17
- ldr r0, [r7, #12]
- cmp r1, #15
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #14
- bne .L17
- ldr r0, [r7, #12]
- ldrb r4, [r6, r3] @ zero_extendqisi2
- ldrb r0, [r0, r3] @ zero_extendqisi2
- eors r0, r0, r4
- strb r0, [r5, r3]
- add r3, r2, #15
-.L17:
- rsb r4, r1, ip
- add r0, ip, #-1
- sub r6, r4, #16
- subs r0, r0, r1
- cmp r0, #14
- lsr r6, r6, #4
- add r6, r6, #1
- lsl lr, r6, #4
- bls .L19
- add r2, r2, r1
- ldr r1, [r7, #12]
- ldr r5, [r7, #16]
- cmp r6, #1
- add r0, r1, r2
- ldr r1, [r7, #88]
- add r1, r1, r2
- vld1.64 {d18-d19}, [r0:64]
- add r2, r2, r5
- vld1.8 {q8}, [r1]
- veor q8, q8, q9
- vst1.8 {q8}, [r2]
- beq .L20
- add r8, r1, #16
- add ip, r2, #16
- vldr d18, [r0, #16]
- vldr d19, [r0, #24]
- cmp r6, #2
- vld1.8 {q8}, [r8]
- veor q8, q8, q9
- vst1.8 {q8}, [ip]
- beq .L20
- add r8, r1, #32
- add ip, r2, #32
- vldr d18, [r0, #32]
- vldr d19, [r0, #40]
- cmp r6, #3
- vld1.8 {q8}, [r8]
- veor q8, q8, q9
- vst1.8 {q8}, [ip]
- beq .L20
- adds r1, r1, #48
- adds r2, r2, #48
- vldr d18, [r0, #48]
- vldr d19, [r0, #56]
- vld1.8 {q8}, [r1]
- veor q8, q8, q9
- vst1.8 {q8}, [r2]
-.L20:
- cmp lr, r4
- add r3, r3, lr
- beq .L1
-.L19:
- ldr r4, [r7, #88]
- adds r2, r3, #1
- ldr r1, [r7, #12]
- cmp r2, r9
- ldr r5, [r7, #16]
- ldrb r0, [r4, r3] @ zero_extendqisi2
- ldrb r1, [r1, r3] @ zero_extendqisi2
- eor r1, r1, r0
- strb r1, [r5, r3]
- bcs .L1
- ldr r0, [r7, #12]
- adds r1, r3, #2
- mov r6, r4
- cmp r9, r1
- ldrb r4, [r4, r2] @ zero_extendqisi2
- ldrb r0, [r0, r2] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r2]
- bls .L1
- ldr r0, [r7, #12]
- adds r2, r3, #3
- ldrb r4, [r6, r1] @ zero_extendqisi2
- cmp r9, r2
- ldrb r0, [r0, r1] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r1]
- bls .L1
- ldr r0, [r7, #12]
- adds r1, r3, #4
- ldrb r4, [r6, r2] @ zero_extendqisi2
- cmp r9, r1
- ldrb r0, [r0, r2] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r2]
- bls .L1
- ldr r0, [r7, #12]
- adds r2, r3, #5
- ldrb r4, [r6, r1] @ zero_extendqisi2
- cmp r9, r2
- ldrb r0, [r0, r1] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r1]
- bls .L1
- ldr r0, [r7, #12]
- adds r1, r3, #6
- ldrb r4, [r6, r2] @ zero_extendqisi2
- cmp r9, r1
- ldrb r0, [r0, r2] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r2]
- bls .L1
- ldr r0, [r7, #12]
- adds r2, r3, #7
- ldrb r4, [r6, r1] @ zero_extendqisi2
- cmp r9, r2
- ldrb r0, [r0, r1] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r1]
- bls .L1
- ldr r0, [r7, #12]
- add r1, r3, #8
- ldrb r4, [r6, r2] @ zero_extendqisi2
- cmp r9, r1
- ldrb r0, [r0, r2] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r2]
- bls .L1
- ldr r0, [r7, #12]
- add r2, r3, #9
- ldrb r4, [r6, r1] @ zero_extendqisi2
- cmp r9, r2
- ldrb r0, [r0, r1] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r1]
- bls .L1
- ldr r0, [r7, #12]
- add r1, r3, #10
- ldrb r4, [r6, r2] @ zero_extendqisi2
- cmp r9, r1
- ldrb r0, [r0, r2] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r2]
- bls .L1
- ldr r0, [r7, #12]
- add r2, r3, #11
- ldrb r4, [r6, r1] @ zero_extendqisi2
- cmp r9, r2
- ldrb r0, [r0, r1] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r1]
- bls .L1
- ldr r0, [r7, #12]
- add r1, r3, #12
- ldrb r4, [r6, r2] @ zero_extendqisi2
- cmp r9, r1
- ldrb r0, [r0, r2] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r2]
- bls .L1
- ldr r0, [r7, #12]
- add r2, r3, #13
- ldrb r4, [r6, r1] @ zero_extendqisi2
- cmp r9, r2
- ldrb r0, [r0, r1] @ zero_extendqisi2
- eor r0, r0, r4
- strb r0, [r5, r1]
- bls .L1
- ldr r1, [r7, #12]
- adds r3, r3, #14
- ldrb r0, [r6, r2] @ zero_extendqisi2
- cmp r9, r3
- ldrb r1, [r1, r2] @ zero_extendqisi2
- eor r1, r1, r0
- strb r1, [r5, r2]
- bls .L1
- ldr r2, [r7, #88]
- ldrb r1, [r2, r3] @ zero_extendqisi2
- ldr r2, [r7, #12]
- ldrb r2, [r2, r3] @ zero_extendqisi2
- eors r2, r2, r1
- ldr r1, [r7, #16]
- strb r2, [r1, r3]
-.L1:
- adds r7, r7, #164
- mov sp, r7
- @ sp needed
- vldm sp!, {d8-d15}
- pop {r4, r5, r6, r7, r8, r9, r10, fp, pc}
-.L88:
- ldr r5, [r7, #12]
- vadd.i32 q12, q12, q10
- ldr r4, [r7, #84]
- cmp r9, #31
- ldr r0, [r5] @ unaligned
- ldr r1, [r5, #4] @ unaligned
- mov r6, r4
- ldr r2, [r5, #8] @ unaligned
- ldr r3, [r5, #12] @ unaligned
- stmia r6!, {r0, r1, r2, r3}
- ldr r2, [r7, #88]
- ldr r6, [r7, #16]
- vldr d18, [r2, #80]
- vldr d19, [r2, #88]
- veor q9, q9, q12
- vstr d18, [r2, #80]
- vstr d19, [r2, #88]
- ldmia r4!, {r0, r1, r2, r3}
- str r1, [r6, #4] @ unaligned
- mov r1, r6
- str r0, [r6] @ unaligned
- str r2, [r6, #8] @ unaligned
- str r3, [r6, #12] @ unaligned
- bhi .L89
- vadd.i32 q13, q13, q15
- ldr r3, [r7, #88]
- vstr d26, [r3, #16]
- vstr d27, [r3, #24]
- b .L14
-.L16:
- subs r3, r2, #1
- ldr r2, [r7, #12]
- add r2, r2, r9
- mov r5, r2
- ldr r2, [r7, #88]
- add r2, r2, r3
- mov r3, r2
-.L24:
- ldrb r1, [r0], #1 @ zero_extendqisi2
- ldrb r2, [r3, #1]! @ zero_extendqisi2
- cmp r0, r5
- eor r2, r2, r1
- strb r2, [r4], #1
- bne .L24
- adds r7, r7, #164
- mov sp, r7
- @ sp needed
- vldm sp!, {d8-d15}
- pop {r4, r5, r6, r7, r8, r9, r10, fp, pc}
-.L26:
- ldr r3, [r7, #80]
- str r3, [r7, #16]
- b .L2
-.L89:
- mov r3, r5
- ldr r4, [r7, #84]
- ldr r0, [r3, #16]! @ unaligned
- add lr, r1, #16
- mov r5, r1
- vadd.i32 q13, q13, q15
- mov r6, r4
- cmp r9, #47
- ldr r1, [r3, #4] @ unaligned
- ldr r2, [r3, #8] @ unaligned
- ldr r3, [r3, #12] @ unaligned
- stmia r6!, {r0, r1, r2, r3}
- ldr r2, [r7, #88]
- vldr d18, [r2, #80]
- vldr d19, [r2, #88]
- veor q13, q9, q13
- vstr d26, [r2, #80]
- vstr d27, [r2, #88]
- ldmia r4!, {r0, r1, r2, r3}
- str r0, [r5, #16] @ unaligned
- str r1, [lr, #4] @ unaligned
- str r2, [lr, #8] @ unaligned
- str r3, [lr, #12] @ unaligned
- bhi .L90
- vadd.i32 q8, q14, q8
- ldr r3, [r7, #88]
- vstr d16, [r3, #32]
- vstr d17, [r3, #40]
- b .L14
-.L90:
- ldr r3, [r7, #12]
- add lr, r5, #32
- ldr r4, [r7, #84]
- vadd.i32 q8, q14, q8
- ldr r5, [r7, #88]
- vadd.i32 q11, q11, q3
- ldr r0, [r3, #32]! @ unaligned
- mov r6, r4
- vstr d22, [r5, #48]
- vstr d23, [r5, #56]
- ldr r1, [r3, #4] @ unaligned
- ldr r2, [r3, #8] @ unaligned
- ldr r3, [r3, #12] @ unaligned
- stmia r4!, {r0, r1, r2, r3}
- vldr d18, [r5, #80]
- vldr d19, [r5, #88]
- veor q9, q9, q8
- ldr r4, [r7, #16]
- vstr d18, [r5, #80]
- vstr d19, [r5, #88]
- ldmia r6!, {r0, r1, r2, r3}
- str r0, [r4, #32] @ unaligned
- str r1, [lr, #4] @ unaligned
- str r2, [lr, #8] @ unaligned
- str r3, [lr, #12] @ unaligned
- b .L14
- .size CRYPTO_chacha_20_neon, .-CRYPTO_chacha_20_neon
- .section .rodata
- .align 2
-.LANCHOR0 = . + 0
-.LC0:
- .word 1634760805
- .word 857760878
- .word 2036477234
- .word 1797285236
- .ident "GCC: (Linaro GCC 2014.11) 4.9.3 20141031 (prerelease)"
- .section .note.GNU-stack,"",%progbits
-
-#endif /* __arm__ */
-#endif /* !OPENSSL_NO_ASM */
diff --git a/crypto/chacha/chacha_vec_arm_generate.go b/crypto/chacha/chacha_vec_arm_generate.go
deleted file mode 100644
index 82aa847f..00000000
--- a/crypto/chacha/chacha_vec_arm_generate.go
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright (c) 2014, Google Inc.
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-// This package generates chacha_vec_arm.S from chacha_vec.c. Install the
-// arm-linux-gnueabihf-gcc compiler as described in BUILDING.md. Then:
-// `(cd crypto/chacha && go run chacha_vec_arm_generate.go)`.
-
-package main
-
-import (
- "bufio"
- "bytes"
- "os"
- "os/exec"
- "strings"
-)
-
-const defaultCompiler = "/opt/gcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc"
-
-func main() {
- compiler := defaultCompiler
- if len(os.Args) > 1 {
- compiler = os.Args[1]
- }
-
- args := []string{
- "-O3",
- "-mcpu=cortex-a8",
- "-mfpu=neon",
- "-fpic",
- "-DASM_GEN",
- "-I", "../../include",
- "-S", "chacha_vec.c",
- "-o", "-",
- }
-
- output, err := os.OpenFile("chacha_vec_arm.S", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
- if err != nil {
- panic(err)
- }
- defer output.Close()
-
- output.WriteString(preamble)
- output.WriteString(compiler)
- output.WriteString(" ")
- output.WriteString(strings.Join(args, " "))
- output.WriteString("\n\n#if !defined(OPENSSL_NO_ASM)\n")
- output.WriteString("#if defined(__arm__)\n\n")
-
- cmd := exec.Command(compiler, args...)
- cmd.Stderr = os.Stderr
- asm, err := cmd.StdoutPipe()
- if err != nil {
- panic(err)
- }
- if err := cmd.Start(); err != nil {
- panic(err)
- }
-
- attr28 := []byte(".eabi_attribute 28,")
- globalDirective := []byte(".global\t")
- newLine := []byte("\n")
- attr28Handled := false
-
- scanner := bufio.NewScanner(asm)
- for scanner.Scan() {
- line := scanner.Bytes()
-
- if bytes.Contains(line, attr28) {
- output.WriteString(attr28Block)
- attr28Handled = true
- continue
- }
-
- output.Write(line)
- output.Write(newLine)
-
- if i := bytes.Index(line, globalDirective); i >= 0 {
- output.Write(line[:i])
- output.WriteString(".hidden\t")
- output.Write(line[i+len(globalDirective):])
- output.Write(newLine)
- }
- }
-
- if err := scanner.Err(); err != nil {
- panic(err)
- }
-
- if !attr28Handled {
- panic("EABI attribute 28 not seen in processing")
- }
-
- if err := cmd.Wait(); err != nil {
- panic(err)
- }
-
- output.WriteString(trailer)
-}
-
-const preamble = `# Copyright (c) 2014, Google Inc.
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-# This file contains a pre-compiled version of chacha_vec.c for ARM. This is
-# needed to support switching on NEON code at runtime. If the whole of OpenSSL
-# were to be compiled with the needed flags to build chacha_vec.c, then it
-# wouldn't be possible to run on non-NEON systems.
-#
-# This file was generated by chacha_vec_arm_generate.go using the following
-# compiler command:
-#
-# `
-
-const attr28Block = `
-# EABI attribute 28 sets whether VFP register arguments were used to build this
-# file. If object files are inconsistent on this point, the linker will refuse
-# to link them. Thus we report whatever the compiler expects since we don't use
-# VFP arguments.
-
-#if defined(__ARM_PCS_VFP)
- .eabi_attribute 28, 1
-#else
- .eabi_attribute 28, 0
-#endif
-
-`
-
-const trailer = `
-#endif /* __arm__ */
-#endif /* !OPENSSL_NO_ASM */
-`
diff --git a/crypto/cipher/aead.c b/crypto/cipher/aead.c
index b1db83d2..57eecc1b 100644
--- a/crypto/cipher/aead.c
+++ b/crypto/cipher/aead.c
@@ -20,6 +20,7 @@
#include <openssl/err.h>
#include "internal.h"
+#include "../internal.h"
size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; }
@@ -80,21 +81,15 @@ void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) {
ctx->aead = NULL;
}
-/* check_alias returns 0 if |out| points within the buffer determined by |in|
- * and |in_len| and 1 otherwise.
- *
- * When processing, there's only an issue if |out| points within in[:in_len]
- * and isn't equal to |in|. If that's the case then writing the output will
- * stomp input that hasn't been read yet.
- *
- * This function checks for that case. */
-static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out) {
- if (out <= in) {
- return 1;
- } else if (in + in_len <= out) {
+/* check_alias returns 1 if |out| is compatible with |in| and 0 otherwise. If
+ * |in| and |out| alias, we require that |in| == |out|. */
+static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out,
+ size_t out_len) {
+ if (!buffers_alias(in, in_len, out, out_len)) {
return 1;
}
- return 0;
+
+ return in == out;
}
int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
@@ -108,7 +103,7 @@ int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
goto error;
}
- if (!check_alias(in, in_len, out)) {
+ if (!check_alias(in, in_len, out, max_out_len)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
goto error;
}
@@ -130,7 +125,7 @@ int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
size_t max_out_len, const uint8_t *nonce,
size_t nonce_len, const uint8_t *in, size_t in_len,
const uint8_t *ad, size_t ad_len) {
- if (!check_alias(in, in_len, out)) {
+ if (!check_alias(in, in_len, out, max_out_len)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
goto error;
}
diff --git a/crypto/cipher/aead_test.cc b/crypto/cipher/aead_test.cc
index 79d7110d..8bad93f5 100644
--- a/crypto/cipher/aead_test.cc
+++ b/crypto/cipher/aead_test.cc
@@ -192,37 +192,139 @@ static int TestCleanupAfterInitFailure(const EVP_AEAD *aead) {
return 1;
}
-struct AEADName {
+static bool TestWithAliasedBuffers(const EVP_AEAD *aead) {
+ const size_t key_len = EVP_AEAD_key_length(aead);
+ const size_t nonce_len = EVP_AEAD_nonce_length(aead);
+ const size_t max_overhead = EVP_AEAD_max_overhead(aead);
+
+ std::vector<uint8_t> key(key_len, 'a');
+ ScopedEVP_AEAD_CTX ctx;
+ if (!EVP_AEAD_CTX_init(ctx.get(), aead, key.data(), key_len,
+ EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) {
+ return false;
+ }
+
+ static const uint8_t kPlaintext[260] =
+ "testing123456testing123456testing123456testing123456testing123456testing"
+ "123456testing123456testing123456testing123456testing123456testing123456t"
+ "esting123456testing123456testing123456testing123456testing123456testing1"
+ "23456testing123456testing123456testing12345";
+ const std::vector<size_t> offsets = {
+ 0, 1, 2, 8, 15, 16, 17, 31, 32, 33, 63,
+ 64, 65, 95, 96, 97, 127, 128, 129, 255, 256, 257,
+ };
+
+ std::vector<uint8_t> nonce(nonce_len, 'b');
+ std::vector<uint8_t> valid_encryption(sizeof(kPlaintext) + max_overhead);
+ size_t valid_encryption_len;
+ if (!EVP_AEAD_CTX_seal(
+ ctx.get(), valid_encryption.data(), &valid_encryption_len,
+ sizeof(kPlaintext) + max_overhead, nonce.data(), nonce_len,
+ kPlaintext, sizeof(kPlaintext), nullptr, 0)) {
+ fprintf(stderr, "EVP_AEAD_CTX_seal failed with disjoint buffers.\n");
+ return false;
+ }
+
+ // Test with out != in which we expect to fail.
+ std::vector<uint8_t> buffer(2 + valid_encryption_len);
+ uint8_t *in = buffer.data() + 1;
+ uint8_t *out1 = buffer.data();
+ uint8_t *out2 = buffer.data() + 2;
+
+ memcpy(in, kPlaintext, sizeof(kPlaintext));
+ size_t out_len;
+ if (EVP_AEAD_CTX_seal(ctx.get(), out1, &out_len,
+ sizeof(kPlaintext) + max_overhead, nonce.data(),
+ nonce_len, in, sizeof(kPlaintext), nullptr, 0) ||
+ EVP_AEAD_CTX_seal(ctx.get(), out2, &out_len,
+ sizeof(kPlaintext) + max_overhead, nonce.data(),
+ nonce_len, in, sizeof(kPlaintext), nullptr, 0)) {
+ fprintf(stderr, "EVP_AEAD_CTX_seal unexpectedly succeeded.\n");
+ return false;
+ }
+ ERR_clear_error();
+
+ memcpy(in, valid_encryption.data(), valid_encryption_len);
+ if (EVP_AEAD_CTX_open(ctx.get(), out1, &out_len, valid_encryption_len,
+ nonce.data(), nonce_len, in, valid_encryption_len,
+ nullptr, 0) ||
+ EVP_AEAD_CTX_open(ctx.get(), out2, &out_len, valid_encryption_len,
+ nonce.data(), nonce_len, in, valid_encryption_len,
+ nullptr, 0)) {
+ fprintf(stderr, "EVP_AEAD_CTX_open unexpectedly succeeded.\n");
+ return false;
+ }
+ ERR_clear_error();
+
+ // Test with out == in, which we expect to work.
+ memcpy(in, kPlaintext, sizeof(kPlaintext));
+
+ if (!EVP_AEAD_CTX_seal(ctx.get(), in, &out_len,
+ sizeof(kPlaintext) + max_overhead, nonce.data(),
+ nonce_len, in, sizeof(kPlaintext), nullptr, 0)) {
+ fprintf(stderr, "EVP_AEAD_CTX_seal failed in-place.\n");
+ return false;
+ }
+
+ if (out_len != valid_encryption_len ||
+ memcmp(in, valid_encryption.data(), out_len) != 0) {
+ fprintf(stderr, "EVP_AEAD_CTX_seal produced bad output in-place.\n");
+ return false;
+ }
+
+ memcpy(in, valid_encryption.data(), valid_encryption_len);
+ if (!EVP_AEAD_CTX_open(ctx.get(), in, &out_len, valid_encryption_len,
+ nonce.data(), nonce_len, in, valid_encryption_len,
+ nullptr, 0)) {
+ fprintf(stderr, "EVP_AEAD_CTX_open failed in-place.\n");
+ return false;
+ }
+
+ if (out_len != sizeof(kPlaintext) ||
+ memcmp(in, kPlaintext, out_len) != 0) {
+ fprintf(stderr, "EVP_AEAD_CTX_open produced bad output in-place.\n");
+ return false;
+ }
+
+ return true;
+}
+
+struct KnownAEAD {
const char name[40];
const EVP_AEAD *(*func)(void);
+ // limited_implementation indicates that tests that assume a generic AEAD
+ // interface should not be performed. For example, the key-wrap AEADs only
+ // handle inputs that are a multiple of eight bytes in length and the
+ // SSLv3/TLS AEADs have the concept of “direction”.
+ bool limited_implementation;
};
-static const struct AEADName kAEADs[] = {
- { "aes-128-gcm", EVP_aead_aes_128_gcm },
- { "aes-256-gcm", EVP_aead_aes_256_gcm },
- { "chacha20-poly1305", EVP_aead_chacha20_poly1305 },
- { "chacha20-poly1305-old", EVP_aead_chacha20_poly1305_old },
- { "rc4-md5-tls", EVP_aead_rc4_md5_tls },
- { "rc4-sha1-tls", EVP_aead_rc4_sha1_tls },
- { "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls },
- { "aes-128-cbc-sha1-tls-implicit-iv", EVP_aead_aes_128_cbc_sha1_tls_implicit_iv },
- { "aes-128-cbc-sha256-tls", EVP_aead_aes_128_cbc_sha256_tls },
- { "aes-256-cbc-sha1-tls", EVP_aead_aes_256_cbc_sha1_tls },
- { "aes-256-cbc-sha1-tls-implicit-iv", EVP_aead_aes_256_cbc_sha1_tls_implicit_iv },
- { "aes-256-cbc-sha256-tls", EVP_aead_aes_256_cbc_sha256_tls },
- { "aes-256-cbc-sha384-tls", EVP_aead_aes_256_cbc_sha384_tls },
- { "des-ede3-cbc-sha1-tls", EVP_aead_des_ede3_cbc_sha1_tls },
- { "des-ede3-cbc-sha1-tls-implicit-iv", EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv },
- { "rc4-md5-ssl3", EVP_aead_rc4_md5_ssl3 },
- { "rc4-sha1-ssl3", EVP_aead_rc4_sha1_ssl3 },
- { "aes-128-cbc-sha1-ssl3", EVP_aead_aes_128_cbc_sha1_ssl3 },
- { "aes-256-cbc-sha1-ssl3", EVP_aead_aes_256_cbc_sha1_ssl3 },
- { "des-ede3-cbc-sha1-ssl3", EVP_aead_des_ede3_cbc_sha1_ssl3 },
- { "aes-128-key-wrap", EVP_aead_aes_128_key_wrap },
- { "aes-256-key-wrap", EVP_aead_aes_256_key_wrap },
- { "aes-128-ctr-hmac-sha256", EVP_aead_aes_128_ctr_hmac_sha256 },
- { "aes-256-ctr-hmac-sha256", EVP_aead_aes_256_ctr_hmac_sha256 },
- { "", NULL },
+static const struct KnownAEAD kAEADs[] = {
+ { "aes-128-gcm", EVP_aead_aes_128_gcm, false },
+ { "aes-256-gcm", EVP_aead_aes_256_gcm, false },
+ { "chacha20-poly1305", EVP_aead_chacha20_poly1305, false },
+ { "chacha20-poly1305-old", EVP_aead_chacha20_poly1305_old, false },
+ { "rc4-md5-tls", EVP_aead_rc4_md5_tls, true },
+ { "rc4-sha1-tls", EVP_aead_rc4_sha1_tls, true },
+ { "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls, true },
+ { "aes-128-cbc-sha1-tls-implicit-iv", EVP_aead_aes_128_cbc_sha1_tls_implicit_iv, true },
+ { "aes-128-cbc-sha256-tls", EVP_aead_aes_128_cbc_sha256_tls, true },
+ { "aes-256-cbc-sha1-tls", EVP_aead_aes_256_cbc_sha1_tls, true },
+ { "aes-256-cbc-sha1-tls-implicit-iv", EVP_aead_aes_256_cbc_sha1_tls_implicit_iv, true },
+ { "aes-256-cbc-sha256-tls", EVP_aead_aes_256_cbc_sha256_tls, true },
+ { "aes-256-cbc-sha384-tls", EVP_aead_aes_256_cbc_sha384_tls, true },
+ { "des-ede3-cbc-sha1-tls", EVP_aead_des_ede3_cbc_sha1_tls, true },
+ { "des-ede3-cbc-sha1-tls-implicit-iv", EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv, true },
+ { "rc4-md5-ssl3", EVP_aead_rc4_md5_ssl3, true },
+ { "rc4-sha1-ssl3", EVP_aead_rc4_sha1_ssl3, true },
+ { "aes-128-cbc-sha1-ssl3", EVP_aead_aes_128_cbc_sha1_ssl3, true },
+ { "aes-256-cbc-sha1-ssl3", EVP_aead_aes_256_cbc_sha1_ssl3, true },
+ { "des-ede3-cbc-sha1-ssl3", EVP_aead_des_ede3_cbc_sha1_ssl3, true },
+ { "aes-128-key-wrap", EVP_aead_aes_128_key_wrap, true },
+ { "aes-256-key-wrap", EVP_aead_aes_256_key_wrap, true },
+ { "aes-128-ctr-hmac-sha256", EVP_aead_aes_128_ctr_hmac_sha256, false },
+ { "aes-256-ctr-hmac-sha256", EVP_aead_aes_256_ctr_hmac_sha256, false },
+ { "", NULL, false },
};
int main(int argc, char **argv) {
@@ -233,22 +335,28 @@ int main(int argc, char **argv) {
return 1;
}
- const EVP_AEAD *aead;
+ const struct KnownAEAD *known_aead;
for (unsigned i = 0;; i++) {
- const struct AEADName &aead_name = kAEADs[i];
- if (aead_name.func == NULL) {
+ known_aead = &kAEADs[i];
+ if (known_aead->func == NULL) {
fprintf(stderr, "Unknown AEAD: %s\n", argv[1]);
return 2;
}
- if (strcmp(aead_name.name, argv[1]) == 0) {
- aead = aead_name.func();
+ if (strcmp(known_aead->name, argv[1]) == 0) {
break;
}
}
+ const EVP_AEAD *const aead = known_aead->func();
+
if (!TestCleanupAfterInitFailure(aead)) {
return 1;
}
+ if (!known_aead->limited_implementation && !TestWithAliasedBuffers(aead)) {
+ fprintf(stderr, "Aliased buffers test failed for %s.\n", known_aead->name);
+ return 1;
+ }
+
return FileTestMain(TestAEAD, const_cast<EVP_AEAD*>(aead), argv[2]);
}
diff --git a/crypto/cipher/cipher.c b/crypto/cipher/cipher.c
index 44018675..f61c59f4 100644
--- a/crypto/cipher/cipher.c
+++ b/crypto/cipher/cipher.c
@@ -61,7 +61,7 @@
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include "internal.h"
@@ -284,7 +284,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
bl = ctx->cipher->block_size;
assert(bl <= (int)sizeof(ctx->buf));
if (i != 0) {
- if (i + in_len < bl) {
+ if (bl - i > in_len) {
memcpy(&ctx->buf[i], in, in_len);
ctx->buf_len += in_len;
*out_len = 0;
diff --git a/crypto/cipher/cipher_test.cc b/crypto/cipher/cipher_test.cc
index 7b4944cb..fa384c69 100644
--- a/crypto/cipher/cipher_test.cc
+++ b/crypto/cipher/cipher_test.cc
@@ -109,7 +109,7 @@ static const EVP_CIPHER *GetCipher(const std::string &name) {
static bool TestOperation(FileTest *t,
const EVP_CIPHER *cipher,
bool encrypt,
- bool streaming,
+ size_t chunk_size,
const std::vector<uint8_t> &key,
const std::vector<uint8_t> &iv,
const std::vector<uint8_t> &plaintext,
@@ -170,16 +170,21 @@ static bool TestOperation(FileTest *t,
t->PrintLine("Operation failed.");
return false;
}
- if (streaming) {
- for (size_t i = 0; i < in->size(); i++) {
- uint8_t c = (*in)[i];
+ if (chunk_size != 0) {
+ for (size_t i = 0; i < in->size();) {
+ size_t todo = chunk_size;
+ if (i + todo > in->size()) {
+ todo = in->size() - i;
+ }
+
int len;
- if (!EVP_CipherUpdate(ctx.get(), result.data() + result_len1, &len, &c,
- 1)) {
+ if (!EVP_CipherUpdate(ctx.get(), result.data() + result_len1, &len,
+ in->data() + i, todo)) {
t->PrintLine("Operation failed.");
return false;
}
result_len1 += len;
+ i += todo;
}
} else if (!in->empty() &&
!EVP_CipherUpdate(ctx.get(), result.data(), &result_len1,
@@ -258,20 +263,20 @@ static bool TestCipher(FileTest *t, void *arg) {
}
}
- // By default, both directions are run, unless overridden by the operation.
- if (operation != kDecrypt) {
- if (!TestOperation(t, cipher, true /* encrypt */, false /* single-shot */,
- key, iv, plaintext, ciphertext, aad, tag) ||
- !TestOperation(t, cipher, true /* encrypt */, true /* streaming */, key,
- iv, plaintext, ciphertext, aad, tag)) {
+ const std::vector<size_t> chunk_sizes = {0, 1, 2, 5, 7, 8, 9, 15, 16,
+ 17, 31, 32, 33, 63, 64, 65, 512};
+
+ for (size_t chunk_size : chunk_sizes) {
+ // By default, both directions are run, unless overridden by the operation.
+ if (operation != kDecrypt &&
+ !TestOperation(t, cipher, true /* encrypt */, chunk_size, key, iv,
+ plaintext, ciphertext, aad, tag)) {
return false;
}
- }
- if (operation != kEncrypt) {
- if (!TestOperation(t, cipher, false /* decrypt */, false /* single-shot */,
- key, iv, plaintext, ciphertext, aad, tag) ||
- !TestOperation(t, cipher, false /* decrypt */, true /* streaming */,
- key, iv, plaintext, ciphertext, aad, tag)) {
+
+ if (operation != kEncrypt &&
+ !TestOperation(t, cipher, false /* decrypt */, chunk_size, key, iv,
+ plaintext, ciphertext, aad, tag)) {
return false;
}
}
diff --git a/crypto/cipher/e_aes.c b/crypto/cipher/e_aes.c
index f7b6fa31..24c4d8a3 100644
--- a/crypto/cipher/e_aes.c
+++ b/crypto/cipher/e_aes.c
@@ -54,7 +54,7 @@
#include <openssl/cpu.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
@@ -67,6 +67,8 @@
#endif
+OPENSSL_MSVC_PRAGMA(warning(disable: 4702)) /* Unreachable code. */
+
typedef struct {
union {
double align;
@@ -252,22 +254,6 @@ void aesni_ecb_encrypt(const uint8_t *in, uint8_t *out, size_t length,
void aesni_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
const AES_KEY *key, uint8_t *ivec, int enc);
-void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks,
- const void *key, const uint8_t *ivec);
-
-#if defined(OPENSSL_X86_64)
-size_t aesni_gcm_encrypt(const uint8_t *in, uint8_t *out, size_t len,
- const void *key, uint8_t ivec[16], uint64_t *Xi);
-#define AES_gcm_encrypt aesni_gcm_encrypt
-size_t aesni_gcm_decrypt(const uint8_t *in, uint8_t *out, size_t len,
- const void *key, uint8_t ivec[16], uint64_t *Xi);
-#define AES_gcm_decrypt aesni_gcm_decrypt
-void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *in,
- size_t len);
-#define AES_GCM_ASM(gctx) \
- (gctx->ctr == aesni_ctr32_encrypt_blocks && gctx->gcm.ghash == gcm_ghash_avx)
-#endif /* OPENSSL_X86_64 */
-
#else
/* On other platforms, aesni_capable() will always return false and so the
@@ -288,8 +274,7 @@ static void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out,
#endif
static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
- const uint8_t *iv, int enc)
- OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS {
+ const uint8_t *iv, int enc) {
int ret, mode;
EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
@@ -384,17 +369,15 @@ static int aes_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
static int aes_ctr_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
size_t len) {
- unsigned num = (unsigned)ctx->num;
EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
if (dat->stream.ctr) {
- CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks, ctx->iv, ctx->buf, &num,
- dat->stream.ctr);
+ CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks, ctx->iv, ctx->buf,
+ &ctx->num, dat->stream.ctr);
} else {
- CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, ctx->iv, ctx->buf, &num,
+ CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, ctx->iv, ctx->buf, &ctx->num,
dat->block);
}
- ctx->num = (int)num;
return 1;
}
@@ -410,8 +393,7 @@ static char aesni_capable(void);
static ctr128_f aes_ctr_set_key(AES_KEY *aes_key, GCM128_CONTEXT *gcm_ctx,
block128_f *out_block, const uint8_t *key,
- size_t key_len)
- OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS {
+ size_t key_len) {
if (aesni_capable()) {
aesni_set_encrypt_key(key, key_len * 8, aes_key);
if (gcm_ctx != NULL) {
@@ -651,57 +633,23 @@ static int aes_gcm_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
}
} else if (ctx->encrypt) {
if (gctx->ctr) {
- size_t bulk = 0;
-#if defined(AES_GCM_ASM)
- if (len >= 32 && AES_GCM_ASM(gctx)) {
- size_t res = (16 - gctx->gcm.mres) % 16;
-
- if (!CRYPTO_gcm128_encrypt(&gctx->gcm, &gctx->ks.ks, in, out, res)) {
- return -1;
- }
-
- bulk = AES_gcm_encrypt(in + res, out + res, len - res, &gctx->ks.ks,
- gctx->gcm.Yi.c, gctx->gcm.Xi.u);
- gctx->gcm.len.u[1] += bulk;
- bulk += res;
- }
-#endif
- if (!CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm, &gctx->ks.ks, in + bulk,
- out + bulk, len - bulk, gctx->ctr)) {
+ if (!CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm, &gctx->ks.ks, in, out, len,
+ gctx->ctr)) {
return -1;
}
} else {
- size_t bulk = 0;
- if (!CRYPTO_gcm128_encrypt(&gctx->gcm, &gctx->ks.ks, in + bulk,
- out + bulk, len - bulk)) {
+ if (!CRYPTO_gcm128_encrypt(&gctx->gcm, &gctx->ks.ks, in, out, len)) {
return -1;
}
}
} else {
if (gctx->ctr) {
- size_t bulk = 0;
-#if defined(AES_GCM_ASM)
- if (len >= 16 && AES_GCM_ASM(gctx)) {
- size_t res = (16 - gctx->gcm.mres) % 16;
-
- if (!CRYPTO_gcm128_decrypt(&gctx->gcm, &gctx->ks.ks, in, out, res)) {
- return -1;
- }
-
- bulk = AES_gcm_decrypt(in + res, out + res, len - res, &gctx->ks.ks,
- gctx->gcm.Yi.c, gctx->gcm.Xi.u);
- gctx->gcm.len.u[1] += bulk;
- bulk += res;
- }
-#endif
- if (!CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm, &gctx->ks.ks, in + bulk,
- out + bulk, len - bulk, gctx->ctr)) {
+ if (!CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm, &gctx->ks.ks, in, out, len,
+ gctx->ctr)) {
return -1;
}
} else {
- size_t bulk = 0;
- if (!CRYPTO_gcm128_decrypt(&gctx->gcm, &gctx->ks.ks, in + bulk,
- out + bulk, len - bulk)) {
+ if (!CRYPTO_gcm128_decrypt(&gctx->gcm, &gctx->ks.ks, in, out, len)) {
return -1;
}
}
diff --git a/crypto/cipher/e_chacha20poly1305.c b/crypto/cipher/e_chacha20poly1305.c
index de8c9b4b..852b2c64 100644
--- a/crypto/cipher/e_chacha20poly1305.c
+++ b/crypto/cipher/e_chacha20poly1305.c
@@ -117,7 +117,7 @@ static int seal_impl(aead_poly1305_update poly1305_update,
* 32-bits and this produces a warning because it's always false.
* Casting to uint64_t inside the conditional is not sufficient to stop
* the warning. */
- if (in_len_64 >= (1ull << 32) * 64 - 64) {
+ if (in_len_64 >= (UINT64_C(1) << 32) * 64 - 64) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
return 0;
}
@@ -162,7 +162,7 @@ static int open_impl(aead_poly1305_update poly1305_update,
* 32-bits and this produces a warning because it's always false.
* Casting to uint64_t inside the conditional is not sufficient to stop
* the warning. */
- if (in_len_64 >= (1ull << 32) * 64 - 64) {
+ if (in_len_64 >= (UINT64_C(1) << 32) * 64 - 64) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
return 0;
}
@@ -244,10 +244,6 @@ const EVP_AEAD *EVP_aead_chacha20_poly1305(void) {
return &aead_chacha20_poly1305;
}
-const EVP_AEAD *EVP_aead_chacha20_poly1305_rfc7539(void) {
- return EVP_aead_chacha20_poly1305();
-}
-
static void poly1305_update_old(poly1305_state *ctx, const uint8_t *ad,
size_t ad_len, const uint8_t *ciphertext,
size_t ciphertext_len) {
diff --git a/crypto/cipher/e_des.c b/crypto/cipher/e_des.c
index b1d312c3..2ba2bed3 100644
--- a/crypto/cipher/e_des.c
+++ b/crypto/cipher/e_des.c
@@ -56,7 +56,7 @@
#include <openssl/cipher.h>
#include <openssl/des.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include "internal.h"
diff --git a/crypto/cipher/e_null.c b/crypto/cipher/e_null.c
index cfe1d1b2..3d6a24c3 100644
--- a/crypto/cipher/e_null.c
+++ b/crypto/cipher/e_null.c
@@ -58,7 +58,7 @@
#include <string.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include "internal.h"
diff --git a/crypto/cipher/e_rc2.c b/crypto/cipher/e_rc2.c
index 8ca7bba6..67418d54 100644
--- a/crypto/cipher/e_rc2.c
+++ b/crypto/cipher/e_rc2.c
@@ -55,7 +55,7 @@
* [including the GNU Public Licence.] */
#include <openssl/cipher.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include "internal.h"
diff --git a/crypto/cipher/e_rc4.c b/crypto/cipher/e_rc4.c
index 3a2c166a..e7c2ccaf 100644
--- a/crypto/cipher/e_rc4.c
+++ b/crypto/cipher/e_rc4.c
@@ -58,7 +58,7 @@
#include <string.h>
#include <openssl/cipher.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/rc4.h>
diff --git a/crypto/cipher/test/aes_128_gcm_tests.txt b/crypto/cipher/test/aes_128_gcm_tests.txt
index 0e33c911..eac9aa92 100644
--- a/crypto/cipher/test/aes_128_gcm_tests.txt
+++ b/crypto/cipher/test/aes_128_gcm_tests.txt
@@ -1,4 +1,4 @@
-# The AES-128-GCM test cases from cipher_test.txt have been merged into this
+# The AES-128-GCM test cases from cipher_tests.txt have been merged into this
# file.
KEY: d480429666d48b400633921c5407d1d1
diff --git a/crypto/cipher/test/aes_256_gcm_tests.txt b/crypto/cipher/test/aes_256_gcm_tests.txt
index dbcee814..30fd422d 100644
--- a/crypto/cipher/test/aes_256_gcm_tests.txt
+++ b/crypto/cipher/test/aes_256_gcm_tests.txt
@@ -1,4 +1,4 @@
-# The AES-256-GCM test cases from cipher_test.txt have been merged into this
+# The AES-256-GCM test cases from cipher_tests.txt have been merged into this
# file.
KEY: e5ac4a32c67e425ac4b143c83c6f161312a97d88d634afdf9f4da5bd35223f01
diff --git a/crypto/cipher/test/cipher_test.txt b/crypto/cipher/test/cipher_test.txt
deleted file mode 100644
index 21fffdb1..00000000
--- a/crypto/cipher/test/cipher_test.txt
+++ /dev/null
@@ -1,597 +0,0 @@
-# RC4 tests (from rc4test)
-Cipher = RC4
-Key = 0123456789abcdef0123456789abcdef
-Plaintext = 0123456789abcdef
-Ciphertext = 75b7878099e0c596
-
-Cipher = RC4
-Key = 0123456789abcdef0123456789abcdef
-Plaintext = 0000000000000000
-Ciphertext = 7494c2e7104b0879
-
-Cipher = RC4
-Key = 00000000000000000000000000000000
-Plaintext = 0000000000000000
-Ciphertext = de188941a3375d3a
-
-Cipher = RC4
-Key = ef012345ef012345ef012345ef012345
-Plaintext = 0000000000000000000000000000000000000000
-Ciphertext = d6a141a7ec3c38dfbd615a1162e1c7ba36b67858
-
-Cipher = RC4
-Key = 0123456789abcdef0123456789abcdef
-Plaintext = 123456789ABCDEF0123456789ABCDEF0123456789ABCDEF012345678
-Ciphertext = 66a0949f8af7d6891f7f832ba833c00c892ebe30143ce28740011ecf
-
-Cipher = RC4
-Key = ef012345ef012345ef012345ef012345
-Plaintext = 00000000000000000000
-Ciphertext = d6a141a7ec3c38dfbd61
-
-
-# DES EDE3 CBC tests (from destest)
-Cipher = DES-EDE3-CBC
-Key = 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210
-IV = fedcba9876543210
-Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000
-Ciphertext = 3FE301C962AC01D02213763C1CBD4CDC799657C064ECF5D41C673812CFDE9675
-
-
-# DES EDE CBC tests
-Cipher = DES-EDE-CBC
-Key = 0123456789abcdeff1e0d3c2b5a49786
-IV = fedcba9876543210
-Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000
-Ciphertext = 7948C0DA4FE91CD815DCA96DBC9B60A857EB954F4DEB08EB98722642AE69257B
-
-
-# DES EDE tests
-Cipher = DES-EDE
-Key = 0123456789abcdeff1e0d3c2b5a49786
-IV = fedcba9876543210
-Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000
-Ciphertext = 22E889402E28422F8167AD279D90A566DA75B734E12C671FC2669AECB3E4FE8F
-
-
-# AES 128 ECB tests (from FIPS-197 test vectors, encrypt)
-Cipher = AES-128-ECB
-Key = 000102030405060708090A0B0C0D0E0F
-Operation = ENCRYPT
-Plaintext = 00112233445566778899AABBCCDDEEFF
-Ciphertext = 69C4E0D86A7B0430D8CDB78070B4C55A
-
-
-# AES 256 ECB tests (from FIPS-197 test vectors, encrypt)
-Cipher = AES-256-ECB
-Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
-Operation = ENCRYPT
-Plaintext = 00112233445566778899AABBCCDDEEFF
-Ciphertext = 8EA2B7CA516745BFEAFC49904B496089
-
-
-# AES tests from NIST document SP800-38A
-# For all ECB encrypts and decrypts, the transformed sequence is
-# AES-bits-ECB:key::plaintext:ciphertext:encdec
-# ECB-AES128.Encrypt and ECB-AES128.Decrypt
-Cipher = AES-128-ECB
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-Plaintext = 6BC1BEE22E409F96E93D7E117393172A
-Ciphertext = 3AD77BB40D7A3660A89ECAF32466EF97
-
-Cipher = AES-128-ECB
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
-Ciphertext = F5D3D58503B9699DE785895A96FDBAAF
-
-Cipher = AES-128-ECB
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
-Ciphertext = 43B1CD7F598ECE23881B00E3ED030688
-
-Cipher = AES-128-ECB
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
-Ciphertext = 7B0C785E27E8AD3F8223207104725DD4
-
-
-# ECB-AES256.Encrypt and ECB-AES256.Decrypt
-Cipher = AES-256-ECB
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-Plaintext = 6BC1BEE22E409F96E93D7E117393172A
-Ciphertext = F3EED1BDB5D2A03C064B5A7E3DB181F8
-
-Cipher = AES-256-ECB
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
-Ciphertext = 591CCB10D410ED26DC5BA74A31362870
-
-Cipher = AES-256-ECB
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
-Ciphertext = B6ED21B99CA6F4F9F153E7B1BEAFED1D
-
-Cipher = AES-256-ECB
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
-Ciphertext = 23304B7A39F9F3FF067D8D8F9E24ECC7
-
-
-# For all CBC encrypts and decrypts, the transformed sequence is
-# AES-bits-CBC:key:IV/ciphertext':plaintext:ciphertext:encdec
-# CBC-AES128.Encrypt and CBC-AES128.Decrypt
-Cipher = AES-128-CBC
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-IV = 000102030405060708090A0B0C0D0E0F
-Plaintext = 6BC1BEE22E409F96E93D7E117393172A
-Ciphertext = 7649ABAC8119B246CEE98E9B12E9197D
-
-Cipher = AES-128-CBC
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-IV = 7649ABAC8119B246CEE98E9B12E9197D
-Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
-Ciphertext = 5086CB9B507219EE95DB113A917678B2
-
-Cipher = AES-128-CBC
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-IV = 5086CB9B507219EE95DB113A917678B2
-Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
-Ciphertext = 73BED6B8E3C1743B7116E69E22229516
-
-Cipher = AES-128-CBC
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-IV = 73BED6B8E3C1743B7116E69E22229516
-Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
-Ciphertext = 3FF1CAA1681FAC09120ECA307586E1A7
-
-
-# CBC-AES256.Encrypt and CBC-AES256.Decrypt
-Cipher = AES-256-CBC
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-IV = 000102030405060708090A0B0C0D0E0F
-Plaintext = 6BC1BEE22E409F96E93D7E117393172A
-Ciphertext = F58C4C04D6E5F1BA779EABFB5F7BFBD6
-
-Cipher = AES-256-CBC
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-IV = F58C4C04D6E5F1BA779EABFB5F7BFBD6
-Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
-Ciphertext = 9CFC4E967EDB808D679F777BC6702C7D
-
-Cipher = AES-256-CBC
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-IV = 9CFC4E967EDB808D679F777BC6702C7D
-Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
-Ciphertext = 39F23369A9D9BACFA530E26304231461
-
-Cipher = AES-256-CBC
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-IV = 39F23369A9D9BACFA530E26304231461
-Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
-Ciphertext = B2EB05E2C39BE9FCDA6C19078C6A9D1B
-
-
-# AES Counter test vectors from RFC3686
-Cipher = AES-128-CTR
-Key = AE6852F8121067CC4BF7A5765577F39E
-IV = 00000030000000000000000000000001
-Operation = ENCRYPT
-Plaintext = 53696E676C6520626C6F636B206D7367
-Ciphertext = E4095D4FB7A7B3792D6175A3261311B8
-
-Cipher = AES-128-CTR
-Key = 7E24067817FAE0D743D6CE1F32539163
-IV = 006CB6DBC0543B59DA48D90B00000001
-Operation = ENCRYPT
-Plaintext = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
-Ciphertext = 5104A106168A72D9790D41EE8EDAD388EB2E1EFC46DA57C8FCE630DF9141BE28
-
-Cipher = AES-128-CTR
-Key = 7691BE035E5020A8AC6E618529F9A0DC
-IV = 00E0017B27777F3F4A1786F000000001
-Operation = ENCRYPT
-Plaintext = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223
-Ciphertext = C1CF48A89F2FFDD9CF4652E9EFDB72D74540A42BDE6D7836D59A5CEAAEF3105325B2072F
-
-Cipher = AES-256-CTR
-Key = 776BEFF2851DB06F4C8A0542C8696F6C6A81AF1EEC96B4D37FC1D689E6C1C104
-IV = 00000060DB5672C97AA8F0B200000001
-Operation = ENCRYPT
-Plaintext = 53696E676C6520626C6F636B206D7367
-Ciphertext = 145AD01DBF824EC7560863DC71E3E0C0
-
-Cipher = AES-256-CTR
-Key = F6D66D6BD52D59BB0796365879EFF886C66DD51A5B6A99744B50590C87A23884
-IV = 00FAAC24C1585EF15A43D87500000001
-Operation = ENCRYPT
-Plaintext = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
-Ciphertext = F05E231B3894612C49EE000B804EB2A9B8306B508F839D6A5530831D9344AF1C
-
-Cipher = AES-256-CTR
-Key = FF7A617CE69148E4F1726E2F43581DE2AA62D9F805532EDFF1EED687FB54153D
-IV = 001CC5B751A51D70A1C1114800000001
-Operation = ENCRYPT
-Plaintext = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223
-Ciphertext = EB6C52821D0BBBF7CE7594462ACA4FAAB407DF866569FD07F48CC0B583D6071F1EC0E6B8
-
-
-# AES GCM test vectors from http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
-Cipher = AES-128-GCM
-Key = 00000000000000000000000000000000
-IV = 000000000000000000000000
-Plaintext =
-Ciphertext =
-AAD =
-Tag = 58e2fccefa7e3061367f1d57a4e7455a
-
-Cipher = AES-128-GCM
-Key = 00000000000000000000000000000000
-IV = 000000000000000000000000
-Plaintext = 00000000000000000000000000000000
-Ciphertext = 0388dace60b6a392f328c2b971b2fe78
-AAD =
-Tag = ab6e47d42cec13bdf53a67b21257bddf
-
-Cipher = AES-128-GCM
-Key = feffe9928665731c6d6a8f9467308308
-IV = cafebabefacedbaddecaf888
-Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
-Ciphertext = 42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985
-AAD =
-Tag = 4d5c2af327cd64a62cf35abd2ba6fab4
-
-Cipher = AES-128-GCM
-Key = feffe9928665731c6d6a8f9467308308
-IV = cafebabefacedbaddecaf888
-Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
-Ciphertext = 42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091
-AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
-Tag = 5bc94fbc3221a5db94fae95ae7121a47
-
-Cipher = AES-128-GCM
-Key = feffe9928665731c6d6a8f9467308308
-IV = cafebabefacedbad
-Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
-Ciphertext = 61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598
-AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
-Tag = 3612d2e79e3b0785561be14aaca2fccb
-
-Cipher = AES-128-GCM
-Key = feffe9928665731c6d6a8f9467308308
-IV = 9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b
-Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
-Ciphertext = 8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5
-AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
-Tag = 619cc5aefffe0bfa462af43c1699d050
-
-Cipher = AES-256-GCM
-Key = 0000000000000000000000000000000000000000000000000000000000000000
-IV = 000000000000000000000000
-Plaintext =
-Ciphertext =
-AAD =
-Tag = 530f8afbc74536b9a963b4f1c4cb738b
-
-Cipher = AES-256-GCM
-Key = 0000000000000000000000000000000000000000000000000000000000000000
-IV = 000000000000000000000000
-Plaintext = 00000000000000000000000000000000
-Ciphertext = cea7403d4d606b6e074ec5d3baf39d18
-AAD =
-Tag = d0d1c8a799996bf0265b98b5d48ab919
-
-Cipher = AES-256-GCM
-Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
-IV = cafebabefacedbaddecaf888
-Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
-Ciphertext = 522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad
-AAD =
-Tag = b094dac5d93471bdec1a502270e3cc6c
-
-Cipher = AES-256-GCM
-Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
-IV = cafebabefacedbaddecaf888
-Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
-Ciphertext = 522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662
-AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
-Tag = 76fc6ece0f4e1768cddf8853bb2d551b
-
-Cipher = AES-256-GCM
-Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
-IV = cafebabefacedbad
-Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
-Ciphertext = c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f
-AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
-Tag = 3a337dbf46a792c45e454913fe2ea8f2
-
-Cipher = AES-256-GCM
-Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
-IV = 9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b
-Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
-Ciphertext = 5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f
-AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
-Tag = a44a8266ee1c8eb0c8b5d4cf5ae9f19a
-
-# local add-ons, primarily streaming ghash tests
-# 128 bytes aad
-Cipher = AES-128-GCM
-Key = 00000000000000000000000000000000
-IV = 000000000000000000000000
-Plaintext =
-Ciphertext =
-AAD = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad
-Tag = 5fea793a2d6f974d37e68e0cb8ff9492
-
-# 48 bytes plaintext
-Cipher = AES-128-GCM
-Key = 00000000000000000000000000000000
-IV = 000000000000000000000000
-Plaintext = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-Ciphertext = 0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0
-AAD =
-Tag = 9dd0a376b08e40eb00c35f29f9ea61a4
-
-# 80 bytes plaintext
-Cipher = AES-128-GCM
-Key = 00000000000000000000000000000000
-IV = 000000000000000000000000
-Plaintext = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-Ciphertext = 0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d5270291
-AAD =
-Tag = 98885a3a22bd4742fe7b72172193b163
-
-# 128 bytes plaintext
-Cipher = AES-128-GCM
-Key = 00000000000000000000000000000000
-IV = 000000000000000000000000
-Plaintext = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-Ciphertext = 0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40
-AAD =
-Tag = cac45f60e31efd3b5a43b98a22ce1aa1
-
-# 192 bytes plaintext, iv is chosen so that initial counter LSB is 0xFF
-Cipher = AES-128-GCM
-Key = 00000000000000000000000000000000
-IV = ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-Plaintext = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-Ciphertext = 56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48cf7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e501511221376a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b1070bef1ab5e3606
-AAD =
-Tag = 566f8ef683078bfdeeffa869d751a017
-
-# 288 bytes plaintext, iv is chosen so that initial counter LSB is 0xFF
-Cipher = AES-128-GCM
-Key = 00000000000000000000000000000000
-IV = ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-Plaintext = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-Ciphertext = 56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48cf7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e501511221376a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b1070bef1ab5e3606872ca10dee15b3249b1a1b958f23134c4bccb7d03200bce420a2f8eb66dcf3644d1423c1b5699003c13ecef4bf38a3b60eedc34033bac1902783dc6d89e2e774188a439c7ebcc0672dbda4ddcfb2794613b0be41315ef778708a70ee7d75165c
-AAD =
-Tag = 8b307f6b33286d0ab026a9ed3fe1e85f
-
-# 80 bytes plaintext, submitted by Intel
-Cipher = AES-128-GCM
-Key = 843ffcf5d2b72694d19ed01d01249412
-IV = dbcca32ebf9b804617c3aa9e
-Plaintext = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f
-Ciphertext = 6268c6fa2a80b2d137467f092f657ac04d89be2beaa623d61b5a868c8f03ff95d3dcee23ad2f1ab3a6c80eaf4b140eb05de3457f0fbc111a6b43d0763aa422a3013cf1dc37fe417d1fbfc449b75d4cc5
-AAD = 00000000000000000000000000000000101112131415161718191a1b1c1d1e1f
-Tag = 3b629ccfbc1119b7319e1dce2cd6fd6d
-
-Cipher = AES-128-GCM
-Key = 31323334353637383930313233343536
-IV = 31323334353637383930313233343536
-Plaintext = 48656c6c6f2c20576f726c64
-Ciphertext = cec189d0e8419b90fb16d555
-Tag = 32893832a8d609224d77c2e56a922282
-AAD =
-
-# OFB tests from OpenSSL upstream.
-
-# OFB-AES128.Encrypt
-Cipher = AES-128-OFB
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-IV = 000102030405060708090A0B0C0D0E0F
-Operation = ENCRYPT
-Plaintext = 6BC1BEE22E409F96E93D7E117393172A
-Ciphertext = 3B3FD92EB72DAD20333449F8E83CFB4A
-
-Cipher = AES-128-OFB
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-IV = 50FE67CC996D32B6DA0937E99BAFEC60
-Operation = ENCRYPT
-Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
-Ciphertext = 7789508D16918F03F53C52DAC54ED825
-
-Cipher = AES-128-OFB
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-IV = D9A4DADA0892239F6B8B3D7680E15674
-Operation = ENCRYPT
-Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
-Ciphertext = 9740051E9C5FECF64344F7A82260EDCC
-
-Cipher = AES-128-OFB
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-IV = A78819583F0308E7A6BF36B1386ABF23
-Operation = ENCRYPT
-Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
-Ciphertext = 304C6528F659C77866A510D9C1D6AE5E
-
-# OFB-AES128.Decrypt
-Cipher = AES-128-OFB
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-IV = 000102030405060708090A0B0C0D0E0F
-Operation = DECRYPT
-Plaintext = 6BC1BEE22E409F96E93D7E117393172A
-Ciphertext = 3B3FD92EB72DAD20333449F8E83CFB4A
-
-Cipher = AES-128-OFB
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-IV = 50FE67CC996D32B6DA0937E99BAFEC60
-Operation = DECRYPT
-Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
-Ciphertext = 7789508D16918F03F53C52DAC54ED825
-
-Cipher = AES-128-OFB
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-IV = D9A4DADA0892239F6B8B3D7680E15674
-Operation = DECRYPT
-Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
-Ciphertext = 9740051E9C5FECF64344F7A82260EDCC
-
-Cipher = AES-128-OFB
-Key = 2B7E151628AED2A6ABF7158809CF4F3C
-IV = A78819583F0308E7A6BF36B1386ABF23
-Operation = DECRYPT
-Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
-Ciphertext = 304C6528F659C77866A510D9C1D6AE5E
-
-# OFB-AES256.Encrypt
-Cipher = AES-256-OFB
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-IV = 000102030405060708090A0B0C0D0E0F
-Operation = ENCRYPT
-Plaintext = 6BC1BEE22E409F96E93D7E117393172A
-Ciphertext = DC7E84BFDA79164B7ECD8486985D3860
-
-Cipher = AES-256-OFB
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-IV = B7BF3A5DF43989DD97F0FA97EBCE2F4A
-Operation = ENCRYPT
-Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
-Ciphertext = 4FEBDC6740D20B3AC88F6AD82A4FB08D
-
-Cipher = AES-256-OFB
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-IV = E1C656305ED1A7A6563805746FE03EDC
-Operation = ENCRYPT
-Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
-Ciphertext = 71AB47A086E86EEDF39D1C5BBA97C408
-
-Cipher = AES-256-OFB
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-IV = 41635BE625B48AFC1666DD42A09D96E7
-Operation = ENCRYPT
-Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
-Ciphertext = 0126141D67F37BE8538F5A8BE740E484
-
-
-# OFB-AES256.Decrypt
-Cipher = AES-256-OFB
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-IV = 000102030405060708090A0B0C0D0E0F
-Operation = DECRYPT
-Plaintext = 6BC1BEE22E409F96E93D7E117393172A
-Ciphertext = DC7E84BFDA79164B7ECD8486985D3860
-
-Cipher = AES-256-OFB
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-IV = B7BF3A5DF43989DD97F0FA97EBCE2F4A
-Operation = DECRYPT
-Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
-Ciphertext = 4FEBDC6740D20B3AC88F6AD82A4FB08D
-
-Cipher = AES-256-OFB
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-IV = E1C656305ED1A7A6563805746FE03EDC
-Operation = DECRYPT
-Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
-Ciphertext = 71AB47A086E86EEDF39D1C5BBA97C408
-
-Cipher = AES-256-OFB
-Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
-IV = 41635BE625B48AFC1666DD42A09D96E7
-Operation = DECRYPT
-Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
-Ciphertext = 0126141D67F37BE8538F5A8BE740E484
-
-
-# AES-192 CBC-mode test from upstream OpenSSL.
-Cipher = AES-192-CBC
-Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
-IV = 000102030405060708090A0B0C0D0E0F
-Plaintext = 6BC1BEE22E409F96E93D7E117393172A
-Ciphertext = 4F021DB243BC633D7178183A9FA071E8
-
-Cipher = AES-192-CBC
-Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
-IV = 4F021DB243BC633D7178183A9FA071E8
-Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
-Ciphertext = B4D9ADA9AD7DEDF4E5E738763F69145A
-
-Cipher = AES-192-CBC
-Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
-IV = B4D9ADA9AD7DEDF4E5E738763F69145A
-Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
-Ciphertext = 571B242012FB7AE07FA9BAAC3DF102E0
-
-Cipher = AES-192-CBC
-Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
-IV = 571B242012FB7AE07FA9BAAC3DF102E0
-Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
-Ciphertext = 08B0E27988598881D920A9E64F5615CD
-
-
-# AES-192-ECB tests from FIPS-197
-Cipher = AES-192-ECB
-Key = 000102030405060708090A0B0C0D0E0F1011121314151617
-Operation = ENCRYPT
-Plaintext = 00112233445566778899AABBCCDDEEFF
-Ciphertext = DDA97CA4864CDFE06EAF70A0EC0D7191
-
-
-# AES-192-ECB tests from NIST document SP800-38A
-Cipher = AES-192-ECB
-Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
-Plaintext = 6BC1BEE22E409F96E93D7E117393172A
-Ciphertext = BD334F1D6E45F25FF712A214571FA5CC
-
-Cipher = AES-192-ECB
-Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
-Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
-Ciphertext = 974104846D0AD3AD7734ECB3ECEE4EEF
-
-Cipher = AES-192-ECB
-Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
-Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
-Ciphertext = EF7AFD2270E2E60ADCE0BA2FACE6444E
-
-Cipher = AES-192-ECB
-Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
-Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
-Ciphertext = 9A4B41BA738D6C72FB16691603C18E0E
-
-# DES ECB tests
-
-Cipher = DES-ECB
-Key = 0000000000000000
-Plaintext = 0000000000000000
-Ciphertext = 8CA64DE9C1B123A7
-
-Cipher = DES-ECB
-Key = FFFFFFFFFFFFFFFF
-Plaintext = FFFFFFFFFFFFFFFF
-Ciphertext = 7359B2163E4EDC58
-
-Cipher = DES-ECB
-Key = 3000000000000000
-Plaintext = 1000000000000001
-Ciphertext = 958E6E627A05557B
-
-Cipher = DES-ECB
-Key = 1111111111111111
-Plaintext = 1111111111111111
-Ciphertext = F40379AB9E0EC533
-
-Cipher = DES-ECB
-Key = 0123456789ABCDEF
-Plaintext = 1111111111111111
-Ciphertext = 17668DFC7292532D
-
-Cipher = DES-ECB
-Key = 1111111111111111
-Plaintext = 0123456789ABCDEF
-Ciphertext = 8A5AE1F81AB8F2DD
-
-Cipher = DES-ECB
-Key = FEDCBA9876543210
-Plaintext = 0123456789ABCDEF
-Ciphertext = ED39D950FA74BCC4
diff --git a/crypto/cipher/test/cipher_tests.txt b/crypto/cipher/test/cipher_tests.txt
new file mode 100644
index 00000000..0a940f14
--- /dev/null
+++ b/crypto/cipher/test/cipher_tests.txt
@@ -0,0 +1,613 @@
+# RC4 tests (from rc4test)
+Cipher = RC4
+Key = 0123456789abcdef0123456789abcdef
+Plaintext = 0123456789abcdef
+Ciphertext = 75b7878099e0c596
+
+Cipher = RC4
+Key = 0123456789abcdef0123456789abcdef
+Plaintext = 0000000000000000
+Ciphertext = 7494c2e7104b0879
+
+Cipher = RC4
+Key = 00000000000000000000000000000000
+Plaintext = 0000000000000000
+Ciphertext = de188941a3375d3a
+
+Cipher = RC4
+Key = ef012345ef012345ef012345ef012345
+Plaintext = 0000000000000000000000000000000000000000
+Ciphertext = d6a141a7ec3c38dfbd615a1162e1c7ba36b67858
+
+Cipher = RC4
+Key = 0123456789abcdef0123456789abcdef
+Plaintext = 123456789ABCDEF0123456789ABCDEF0123456789ABCDEF012345678
+Ciphertext = 66a0949f8af7d6891f7f832ba833c00c892ebe30143ce28740011ecf
+
+Cipher = RC4
+Key = ef012345ef012345ef012345ef012345
+Plaintext = 00000000000000000000
+Ciphertext = d6a141a7ec3c38dfbd61
+
+
+# DES EDE3 CBC tests (from destest)
+Cipher = DES-EDE3-CBC
+Key = 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210
+IV = fedcba9876543210
+Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000
+Ciphertext = 3FE301C962AC01D02213763C1CBD4CDC799657C064ECF5D41C673812CFDE9675
+
+
+# DES EDE CBC tests
+Cipher = DES-EDE-CBC
+Key = 0123456789abcdeff1e0d3c2b5a49786
+IV = fedcba9876543210
+Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000
+Ciphertext = 7948C0DA4FE91CD815DCA96DBC9B60A857EB954F4DEB08EB98722642AE69257B
+
+
+# DES EDE tests
+Cipher = DES-EDE
+Key = 0123456789abcdeff1e0d3c2b5a49786
+IV = fedcba9876543210
+Plaintext = 37363534333231204E6F77206973207468652074696D6520666F722000000000
+Ciphertext = 22E889402E28422F8167AD279D90A566DA75B734E12C671FC2669AECB3E4FE8F
+
+
+# AES 128 ECB tests (from FIPS-197 test vectors, encrypt)
+Cipher = AES-128-ECB
+Key = 000102030405060708090A0B0C0D0E0F
+Operation = ENCRYPT
+Plaintext = 00112233445566778899AABBCCDDEEFF
+Ciphertext = 69C4E0D86A7B0430D8CDB78070B4C55A
+
+
+# AES 256 ECB tests (from FIPS-197 test vectors, encrypt)
+Cipher = AES-256-ECB
+Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
+Operation = ENCRYPT
+Plaintext = 00112233445566778899AABBCCDDEEFF
+Ciphertext = 8EA2B7CA516745BFEAFC49904B496089
+
+
+# AES tests from NIST document SP800-38A
+# For all ECB encrypts and decrypts, the transformed sequence is
+# AES-bits-ECB:key::plaintext:ciphertext:encdec
+# ECB-AES128.Encrypt and ECB-AES128.Decrypt
+Cipher = AES-128-ECB
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+Plaintext = 6BC1BEE22E409F96E93D7E117393172A
+Ciphertext = 3AD77BB40D7A3660A89ECAF32466EF97
+
+Cipher = AES-128-ECB
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
+Ciphertext = F5D3D58503B9699DE785895A96FDBAAF
+
+Cipher = AES-128-ECB
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
+Ciphertext = 43B1CD7F598ECE23881B00E3ED030688
+
+Cipher = AES-128-ECB
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
+Ciphertext = 7B0C785E27E8AD3F8223207104725DD4
+
+
+# ECB-AES256.Encrypt and ECB-AES256.Decrypt
+Cipher = AES-256-ECB
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+Plaintext = 6BC1BEE22E409F96E93D7E117393172A
+Ciphertext = F3EED1BDB5D2A03C064B5A7E3DB181F8
+
+Cipher = AES-256-ECB
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
+Ciphertext = 591CCB10D410ED26DC5BA74A31362870
+
+Cipher = AES-256-ECB
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
+Ciphertext = B6ED21B99CA6F4F9F153E7B1BEAFED1D
+
+Cipher = AES-256-ECB
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
+Ciphertext = 23304B7A39F9F3FF067D8D8F9E24ECC7
+
+
+# For all CBC encrypts and decrypts, the transformed sequence is
+# AES-bits-CBC:key:IV/ciphertext':plaintext:ciphertext:encdec
+# CBC-AES128.Encrypt and CBC-AES128.Decrypt
+Cipher = AES-128-CBC
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 6BC1BEE22E409F96E93D7E117393172A
+Ciphertext = 7649ABAC8119B246CEE98E9B12E9197D
+
+Cipher = AES-128-CBC
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+IV = 7649ABAC8119B246CEE98E9B12E9197D
+Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
+Ciphertext = 5086CB9B507219EE95DB113A917678B2
+
+Cipher = AES-128-CBC
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+IV = 5086CB9B507219EE95DB113A917678B2
+Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
+Ciphertext = 73BED6B8E3C1743B7116E69E22229516
+
+Cipher = AES-128-CBC
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+IV = 73BED6B8E3C1743B7116E69E22229516
+Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
+Ciphertext = 3FF1CAA1681FAC09120ECA307586E1A7
+
+
+# CBC-AES256.Encrypt and CBC-AES256.Decrypt
+Cipher = AES-256-CBC
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 6BC1BEE22E409F96E93D7E117393172A
+Ciphertext = F58C4C04D6E5F1BA779EABFB5F7BFBD6
+
+Cipher = AES-256-CBC
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+IV = F58C4C04D6E5F1BA779EABFB5F7BFBD6
+Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
+Ciphertext = 9CFC4E967EDB808D679F777BC6702C7D
+
+Cipher = AES-256-CBC
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+IV = 9CFC4E967EDB808D679F777BC6702C7D
+Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
+Ciphertext = 39F23369A9D9BACFA530E26304231461
+
+Cipher = AES-256-CBC
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+IV = 39F23369A9D9BACFA530E26304231461
+Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
+Ciphertext = B2EB05E2C39BE9FCDA6C19078C6A9D1B
+
+
+# AES Counter test vectors from RFC3686
+Cipher = AES-128-CTR
+Key = AE6852F8121067CC4BF7A5765577F39E
+IV = 00000030000000000000000000000001
+Operation = ENCRYPT
+Plaintext = 53696E676C6520626C6F636B206D7367
+Ciphertext = E4095D4FB7A7B3792D6175A3261311B8
+
+Cipher = AES-128-CTR
+Key = 7E24067817FAE0D743D6CE1F32539163
+IV = 006CB6DBC0543B59DA48D90B00000001
+Operation = ENCRYPT
+Plaintext = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
+Ciphertext = 5104A106168A72D9790D41EE8EDAD388EB2E1EFC46DA57C8FCE630DF9141BE28
+
+Cipher = AES-128-CTR
+Key = 7691BE035E5020A8AC6E618529F9A0DC
+IV = 00E0017B27777F3F4A1786F000000001
+Operation = ENCRYPT
+Plaintext = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223
+Ciphertext = C1CF48A89F2FFDD9CF4652E9EFDB72D74540A42BDE6D7836D59A5CEAAEF3105325B2072F
+
+Cipher = AES-256-CTR
+Key = 776BEFF2851DB06F4C8A0542C8696F6C6A81AF1EEC96B4D37FC1D689E6C1C104
+IV = 00000060DB5672C97AA8F0B200000001
+Operation = ENCRYPT
+Plaintext = 53696E676C6520626C6F636B206D7367
+Ciphertext = 145AD01DBF824EC7560863DC71E3E0C0
+
+Cipher = AES-256-CTR
+Key = F6D66D6BD52D59BB0796365879EFF886C66DD51A5B6A99744B50590C87A23884
+IV = 00FAAC24C1585EF15A43D87500000001
+Operation = ENCRYPT
+Plaintext = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
+Ciphertext = F05E231B3894612C49EE000B804EB2A9B8306B508F839D6A5530831D9344AF1C
+
+Cipher = AES-256-CTR
+Key = FF7A617CE69148E4F1726E2F43581DE2AA62D9F805532EDFF1EED687FB54153D
+IV = 001CC5B751A51D70A1C1114800000001
+Operation = ENCRYPT
+Plaintext = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223
+Ciphertext = EB6C52821D0BBBF7CE7594462ACA4FAAB407DF866569FD07F48CC0B583D6071F1EC0E6B8
+
+
+# AES GCM test vectors from http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
+Cipher = AES-128-GCM
+Key = 00000000000000000000000000000000
+IV = 000000000000000000000000
+Plaintext =
+Ciphertext =
+AAD =
+Tag = 58e2fccefa7e3061367f1d57a4e7455a
+
+Cipher = AES-128-GCM
+Key = 00000000000000000000000000000000
+IV = 000000000000000000000000
+Plaintext = 00000000000000000000000000000000
+Ciphertext = 0388dace60b6a392f328c2b971b2fe78
+AAD =
+Tag = ab6e47d42cec13bdf53a67b21257bddf
+
+Cipher = AES-128-GCM
+Key = feffe9928665731c6d6a8f9467308308
+IV = cafebabefacedbaddecaf888
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
+Ciphertext = 42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985
+AAD =
+Tag = 4d5c2af327cd64a62cf35abd2ba6fab4
+
+Cipher = AES-128-GCM
+Key = feffe9928665731c6d6a8f9467308308
+IV = cafebabefacedbaddecaf888
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+Ciphertext = 42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091
+AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Tag = 5bc94fbc3221a5db94fae95ae7121a47
+
+Cipher = AES-128-GCM
+Key = feffe9928665731c6d6a8f9467308308
+IV = cafebabefacedbad
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+Ciphertext = 61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598
+AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Tag = 3612d2e79e3b0785561be14aaca2fccb
+
+Cipher = AES-128-GCM
+Key = feffe9928665731c6d6a8f9467308308
+IV = 9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+Ciphertext = 8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5
+AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Tag = 619cc5aefffe0bfa462af43c1699d050
+
+Cipher = AES-128-GCM
+Key = 3de7b368783bd7287f2b9b731814c876
+IV = 90dedcfff100eb1f1db9d935
+Plaintext = 8d766795cadc0961c0f448c62df3827eef3a8664599b3adbaab0cfd63875bceb8f992b4f7447dca10ddd716aa0bc4fe925e1aa3e3fd1d5c430c650fe3546d6b9a24d576a857c5f04e8c0a3b149df277aa19cfa64ee235891d3b8ec0e840d268b1e70dd8a4bf97628a0c7aea38aa21eeb8fb1a8437f2abfee05e0d2c30659e312ec03d30da51b7c19073a2341c17df806e27e796d581143d39e4de8d3f8d46aa6d6fc1a98d94fa69b92dab751d930cc12de21fb1a7468af09e3c12ff6c3db3967d10cf140bc46f17a16e24b010b6cba5ebf777341c52042596ee53008389c48d9690ab9f5625795c3e588f72f7a1670b2b25a9f4eee1c8845ac90f1bf47ae4ea4b607a50aca88ed304cbb700d02d5486139b0bc81ec042e574abf986972fa008b83ef22dbfe720c2f2f6355c87c975932cec545ebed657e5e7570c503e9aa7f0b87d0b2648e421ed1d34749637c95d1e931af8925236387e50454f0ba2e22ed05f90450fad46f4eb7ddb08656511dd065c0f852a7e42f618a961a6c6bec42226c6b6043580b009ec9837cf99844cb74794a82c269ff648e0bae9ae50256a0ad98ad9f5a35057b3004ac96f469f9ee966dadc16dc47616586cf242706df96bb2f7ee43d3bd1c65d2eac7b82ef242e77ab509afb9639e5f3995380e926305729ca762c487f4411ec2a9c688b8347e5287216dbb38c3fe2281a89fcb47ee2ee7ddf79bfa3ab61cd56a00981019bbcea8aa0444eb75958e5fa56ea0036d2de4950a7db886f4a318b433bd41e00905ab158171e0ef13172293bdf70064b9dc7b243bf9dc927589bf9e99468d1cb330639dbff1850cc51929b8971b0b2ede9d06bc5f6ba39d4551b587f09bf6f8206e8f1524f55714612581d6aa45d8fb83425f84a736576deeecafdcbfbb8670d14cd2ab2a7f8b7f374c07881b7bac2605fd5ff7ff7cf43e30cf49910961a9079c0343b8601be8c3e9fe38f49fdab0b7e1a8c1536cf84e4d80d26ae5ec37570839b5cda02929221898d611525c3a88fc444167ffc532b256cdd0a8f31ff08097d75b629fab99c9e1062d1d9962b211e15ec8709934029c4934e64db8d7a2f32e23dc541be306e9a57a3419115994cbc3a8f8d5ea2a6f45b9ea9ac0e51ed0c6680fa029f4552a6c8665aab00ab77928342e7284c321e9500ad4774ef1fed0f596d5aea371fe1793271aef38cde55547f34701a525526e83a72673385a85f44db511bc87ce1f831fc6ccf8204ca4f4a20eac09897aae93684f14ede21bcaf40a09c08012b92600d6a839ebdf8bdca7b34192c6c50bad8796b3be3c375dbae6217815d2c75cc878d39b4e842d4eaa5f5df2242cf230e44a240e18e47827f089b18bf880fd41a2516eac8e6ba3fc2db64a4bc28789860d7b18d9edeae8b3059f4d945b15d0ee27b1f74842dd1df117fe83a8fdade23a47c93902eedc4d33f2dbfcd1996e6dc1458409fde2302830e8d44c58c5ae67486b9950dd938f14c38bc4c9484fdc4ded93a0f90875773453fc14d428cd6e7beb0c705d61229d2b3df09632ebb30b325fefe2aebbf2a7aa8e4ad46277ca4b8b078818b63d04e7652057f6cbbab7c43ac355537e0d3918b4a73c00dbe6b30a27ee7a6fa213d3347ae478e8edc323404b8322b9c7b0173ed61c38ed25f3576a675d527d22edd51d6dfa5767560d3a50a91226338e8c4e6436eedbcd3d2efe9dc1e686b15d2f57d553abcfda57dc316ca453a690f20148f0dfa20c1c4a58240aaf7195095fedfa56d839d0230d55ce9a8ca1b9d1acd6fe98d583148ba0f4a4e3413c76e6ec57ddb79428d3a90079f64d3321c791f60d501c3fd02c8403f0f5e6c6836bbc96430c1b48e83350c3a3cfd017f15bee3e4bb1295d821dc98b85ab3145555cce2c34a8142fe50f8db19918b514a165d12ff6301fb2296788760ac0b6d9e3a57770ad5111cde5d24b6321918cb0b0887a282b827a8749733171914b000e7d3c0edad1d42ca60da37f0698554bb2a1749f73b3120dbeaa32951f8217a781a200467d5b569d16f56fc9b7dff0ac524f03fee0617f4c692d94613b1e13b18075dc9f0d32811d4a8949a95f6b5fa46aeb83597adb409e68b2a0177c36dcc95dcb2e7dd4fb7337ff97c013364fe139e185014948fa698741d822044fa3f6978b16afd18138c845587c405ebf7a6cd1c28610ce67e992ed49e406658a0a202feed9709500d064b6f53eecfca57dd4b38363ce3aae9d59126d8ae7e140a373851188ae28c909181d0ac64770df70dd2475809350cb367825b59d521d5e457b4e36aea6dedd90a2266898b753b57fa359d43cd388e7d6c7ed90bc4c2af34ceafe88a3af6ac376fec35f1240f08af4f3eb30bc53dd68e5762e6d39e6b16f63003fbe0bee828d0d7adc58c41e857c2c44702215b202701fc696eae021af19c79e59c3e32627cd571f5db99b17f1772b5d746196befabb0b7446687827f3315b391d5dff069b1c39c00bb143218ef458e3b397e1c99640d57fc8db2e0083d3d22ed4111a8fc9e0e6f55fe6a56e946dbee43909bdd7d516fdf756ed8099ba80b1e17a5e279119345104379a36962ca9c8b2a53c414d79eb09fe79862ca749a9eabd9185ad1df57215945882f5894868a134bfc35c835e040e77ecf077d6a98a73ee022963d70b036be3fe5718280ae52c5d751211b22950c0597aaedd35af41f7dd5999e5f7ee34a37edcf97df54a46742b0252b196eaee454ff0c30685b15f8de087de208906be1d971f0fd89f7cdff2af0bdc96759d6889fba9ef092ad1c8deab0404562a7f3977d211c28dfd1573aebd5427a8773f03986101703fa19cd4ab96a381c76a747f63b63f7a9a3a08e251cdc593a024f63b443b76d17dd9e151809da3c582fbd334fa6dd0221b6d410c6a78ba95bb0154bb8999f619f2e084a6b9755ceee4ca3c7e0481a47776c8814f13054e627e37630d593bd09d5f10a049c66c9999f4b0b037e81ef70615d674c7c7975972994a053c069675fad3fae5ae3e779233b70254fb87f25d44c104afc3d5911b8b695173f9337130e39a02cf97356cb817f6cd23f55ef74dd06bd24ce5887a7001ef576262ffaa99f9bb5e3f55bda2aa0f199115909af48bb4d6b1a0a0847774515302cafebe75aad1f63362b1f38141e8721851c3ef1a247931b3b450581eb5d09027b9e3ba60ae9801d629b74991b7fd65520eac561d47115a85141d9a757bc75710bedff1630561ae05254ea541a7ff1846ed5e164834417556dd562c45543c88d8030bb56451fd5b3cbf10fb0164c5288789d2aac7e7a836e79bc3dd401a8e3e05aa6714ffb2dfddb3037c35fa1ebed62a073b2da42133f2620ae88de5e3f46cc69f2b9b3c9b88e39b8b108059ac6bd493be5f7a39f6b53ee825f4593b77ec9238f5ab804d533f48803e7d8187291ee25cfac4da5d8c9279517adfb09c422f6d704711726c73828a5082b4c7b3d85611b8f496d3e0f78c5c4f1dd1c722b1b11d55861f232beee6aaef8a00fd2eeeb45f182af191ca6de8eaa25ceda5451416fbf6d1abc0670b8c10e2815076f271044c690bdcb64856b91265bac202043a28f6bbeb807535aad4bd89e572a9427c826b170d3862f4cca70ddffb4769d6593a1cc6c42fd06cf68642835fe474a23e6f63df316f8361bab959b768d78e20c03c2a99913c162a9662bd9981eee55922f36792de0af68da04ab49dca72e3d9b0de79df828b433bcf6be073f851a36418c03a717d54d48c1014ccb793577c8393b7cb53cad6bc7060a54cc6363734f6ad388763519ca09b533078d3cfa61d7bdd4c4dd0ffe64d68d501b55903d3f4a1f310a3826ac2ca700de01d656188dcf577fd1b63e305614b8d13471f6f84a5d4b12c5e119870a63d1e3dbd39d3b5c26b09f9d80f8a59ce836b20bc933496923d278a022c00f3aac204d07d2e5075bbcef1e4820d633a3a2b35974f72a033484a91a1d6a9913239c93e5783b01833073c98f358e3465efd5087af37ad60b7285550e776d67ea7019e788776c5a456102358c32eb4e7c28096af88b9a20d8ce379ba3928a10ffd539c106f4927e7ac0f382c74017d6e4438fb128c660affd45e9bb68452de72b574eeffe3ce239d0718908c3800bc7e8ecd2fc7d9754171506017fd7868594c9373a96579fed475a28811649ce5dc8a3107bd0d8578748878ce4998684620931dc3981a2499568c2f61174c3b3fc46a7010468e8ff75c08cd43ac764d95e2ad1659f9db62e9554f811e0f43bb74779d923c8c243d12a5314d3c0c6ec84fe60e1d2b2e2b20d3e64054d62049ef9233ff55223a319c285e4e3f4c98dc95b2ca81230d7fed9bb99fd7d97430eb32c9c11647992bd85dcb47cfd58ea3e221d095bcf9374a6baa7c8333581f62b9e489282483023fdd18451f09bec764146b587209160b3d1d7a3d2e145fdb640c4bc382541e0d84255122d51a710887ebe1ccf29d41b4dd7fd7368d68ada250d3968d6f0971f0849c13c09abadb9db8b08960a18f84f0346ea0aa71227afa55b90cabc062d549b616400d36450b19adb67d7358e48c043fa1135abfca89374c906f8d1a6a845debf6b37f055d390b029c7f4524958bdf8d7e2755dde3b957f0926f9d3b8821ba96044d3cad2d637b973bfb657fcc06ff44c17965acf572ab7a0c87604c7dd1cfd136a0ad02b22e8ef320e101ea09772588e8c5b4d88f40fe1be18d27146a2b9559491949671700cebff9a709f297c2621ca9d5d1749623abc20a326ff5be55cb9435c03bf49b147b1e0a4a918bfdc3642df90b396a474f81d75c953d87b3f3b4e31fced630bd7c481c63acbb84dd31249101ac5277a36dcdfc80d8d9a2e928e9b2d65bb257bce97ccda83b187da8a7886dc96eab93d0864d88c358105f9cfe1ad0f0a8508b5b3985ff95de652e684da970b57669aa3fdfbe590a631522abe8246393639709a9a6cd549e78e3c2d1acf84643e9f554c5e076f75a5c1dce1be20a66722d0b896837b7036509ab8d473d5d2b7a8374d6a575f69d54afe3e7e18f4faf4e917be8a74e55c271b96d966e0c0b883f84b3ef2e4f278daeda2efd3ce770801d2c4bda5eb9b646deeab9fa55324e917e63e4eb6aeb4176cb4e43af3db61aea1546fbf16e76a12fcdbe726b565710e3f9866551023e5fbac0038678717e6ab4d3e92dcc53049e8cb65c00216d31a8869ff4d3539313fe2fd7ce0f53b255e3659e7dfc5f92b7627dd9ba42972f0ba72b888932d870ab97226040c4c0f4826be131fe1d2cdc21005ec2addd7796f0927501251ab26b0e5f3f9d2a1cb346a774e18bc233cc89aa69f5f70e3d5c17098eed350ec419c82837153b5c7f5813bf5918defc8df143063f3fe45125deded2b15892d5cebce589b60f2ada0f9d608983e8d107d8e6482b5f542c6650b014445e8c055aac142f16cfc59229fc9626f7aaa40cefacef777e494e13dfa93d27c201788ca9f60e572af8d65ffb513473dade5fe494cbf7377bd1ed03db2571d65af3be4b0bf27c1f069797bfb67ef0bd8a88c6286af6712c106df9c418d88054e3b46c88296a2e63894d6bee0dda8833c373d6a1b27637e1510fea3eb2fb34ae27354571369653a282a8d19f2c34f9e5ec34555b4ed24327dc5d246df13736bd41021697104f80c85bd0ae920e9aeb4e628fb8aec269d55858df149af298b06d61250b043c8a14a15f0646d0aaa18109d031c449e66dd7336044dbdec912b1bb615fae2a3df480bd64cbed74be65c8f1acac247e80bbaeb6f9dab38c6addf4f3b094d5934ef5c9749053b9159e280034e601731a12d6688ff27ee3581ae289de424d16676fb750d2ccd5b3f964dd77bdefc15bb204e2350632822384cc194cf9130f1ee81bfc3887d3366ec0b48cbbe0fe674281ae7445f03791887873659825680448f162452cef57d783821a73047078a8cf94c416850092ac772ef0b2e48517ef101ee0681b5259aa27fd56edf3c01e6dba6298ccc91b09bb304b637eccf8c673b816e74bd7f8ceffa6b17ab03df7ee9ca4098d24d044015a07df782a309cb6761528272632a6e1323c4e18284b463dfcabed708e4fc95cef133865cdbec8bfdde100621c65a92762cc3141ff37b66dea8fa6e3aad61dcbf3b512467c4773d36e58989e12a636389c1678c191137a5f7f59668c8a527dddcdd0c3fbb14cf48b8f3ea306850a5eda76c57aad06312d7bbfc18969d7b611f512358a7bdf959cc2f41de1c408133ef02b1fb2cdf8efe9973c27536434e56fc1bb4880db7fe901087b53ef3c0de18aafa47c25f1cd62c362f2e5da41c2dbff0e13adaba26c1e0829f027dc0320442e851eaed9507b70ac17180725349f6ea7b59bf39c095a9d10790e87221c7c2d24b8bca184ee95a3ef7449aad6c1d905f688498ae7a0cd1b01f76dabc342fb2be0295ca1484bece3c9b8a1b91e53de2d2587f3607a7f348f5cbefaa7a6dcf61bbbcae9444e2d25a77b016cbd1508c8cd319e9812b43b0bbca52df155d418dacb6ab1360a9e605fb53c6e20588a10bef42d884989e836b2ff16fbcdd2c1704f75dc8c1ac2cc6aeb92726f5d46e4784c70e1e249c102be6da506e5e3c2cef6a8bc4a60dac7adf3cacca8679f8f792ddc27613e44a70fd849b7617e042da46d65a3e6cf425f59b83cbae5b6e911142abd13a0a8cdf06d041435ee20e2ca417e905d2dc49c15b863ae5920ff7f9380a86bb0c86b69a000c157cd35245bf71f9dfdefbd1760af90ec3e554ebc511aebf650633221ca9157226f613f41406872765f8d7b916ff3877266f017b8d840dca0697ec3dffce7912ea9eafb62cc2f2d0a112c9bc0727444b47b62766bddf5b5f26d391f653b6894b069069979d0cf8cc7fc4143626a8420bc0a3866db3860096cc128d620ceff059d1614487004adbdf6b0c4428ac8897dcf16e6b11a692a6b465a92b40010f3480b444d4d2e24b0af8467666905c2a6233bdd6502521b621d3cdd4a5e1f268d65bf6a1879608ffd3abf635c5f0948f3cec7e087485c72b00258ba69783cfe7d611bc41c27814ef5674185791dbe626e1f276cf2c399a4eb264f19c77ee95d94252f546528f629188318e9ede65a927aafd2f2af56ff32c0ef39862d2f92268bc9400afa8ddeff591f3ef99681263a33b873bd9e01a59c8b281da30875245cbffee5268563c7f6f20b9e22d998934131dd219624d3cef6df2f3d2d6401833f72c619d6f763837141dbf93179d0f01375581ebe227185166aa7988eb9fd453d510ca6616cc013d551d23a33a4241e85aac3201284344977d496d768f5d920c5670b1d8bb608efc1b99abd261afb0a4ebe191605cc5c2e20523a13b3b94dd1fb24a27009d9a5b6329336f3516a327642386ba64c8769da1324a8a3d1f304cf0700df2b3e38215a954523e1d40ae96d0046e2929a815bf70785e94bc9b89246ab6aded60d65170eeb49b0ee0a57ee2e57db92409105c25f2d0c1a17b5556d06511bd0991a426258372c7f2b402dd533a75aa175524eb5d6b9575300b81fdb2258bd74429add8aa477bd1182db57107d411d16147defc3582861c68f5ce82e0a0316edd5d0f3cf36825a2c79a33e376cce2e63274b3b41bcbdd755845ad9ed2a3bdacb6fa3fa9484b7b60edeb1d9ef84772e78e39adca14c9fa0bb3ad1f1c17fb9449270e9b4c97b5b320839947fc73853fc58304ee9c9e86f3775f5469554d5006eb7ce9d02d5f900c771806c275ee7022e2b55d111338dd93ad51d14008df4c13d8c03fd9bb3689607e5cbdd499c3a372b487af74cb140f6300cd2dc2acda07277ea3dab57ecf09f1a8f2d6abf7c44fcdaa6dcb1f6e791164004b20b3b4c860f409c1483c7044b6fa445f7224606894e386ba08057a387b48920d4de203b1acc4dbe2b0b4cbdc3f7d7bbb097abbf81e01db09e120eab83def925a059cdb513efe6bc93f0579ebf75638df3c3d7f9eba3c36a169e9d88495c452888853640d93ee70f254f86e2d2d3fbb5e8883b36fbd2da105cf3a75cfe998068203186bb37f1d1ebead8ce1f9383b816f1da2fd0a9e01377b6ebfed4f05bec08b4ff9b90e385736fd13a3af7980c21b0dab58decea8e9545af5d0fb11bb51aeda2c8616960e8f6f84e6c2fc4f50d7e413afe030f75475509fbcf49cbe14445d267994fd3f38f41a1339f2895c0b2969a9bf9c59b85e629486c7bb5107c7a6b069793be7690f7a7c96c93b09a9d610594a156ab27a32d5557a5b1ec8920761cd2f559ad808dff3da64717ea5f10fba87b8ff2712ce322eb3c288939e0007f779a3920f45fdd533369f6f85a8cce21f91552fe03702ef81a926af0e402b418fbb25a6a3dad0ec18ec663126b3f48c341e2725abfeae865352d5ad275a9e3ca20393c64d118968023daac84bdc724a3c522d97a5878ed788cf8e44f80f8803d57584d8c8688cff24dd8c0e881b62d16ea30104d62007a4bec051da7fdc95d1df8556ebdf607383a0825ae503e24661ceb8ba773b793360c3f4ed3b761bd372570cb17e7c2030f07b0b45a7974e45ee6fcf5bd7ae9e9abde5421b42cff6af0c6eb7fc73f4deb67bb4e0b3dc9b4008da30c67071243cda649091a14b89bdacf2ae98dd230e932d9b277d6968c65e0006a8ff63f283f2cd9c21615dfd82e0b24af6ff559c97922a3d112ff0ef4af9d6583bec1f84d1aa8bbae705b9bcf458f5d93059b90fc2217ab27d0072a38aec3229d13266beb3015ac2389a06dec3120c6c04e540886091597919da293a4a8c0812d6cd336d5c5faeb64162ec0459e252d219bed78c4b6bb61c1213939bb3cca12a625ce5a45001d7408f6d40fa9466377caa43afe961b5c1602679220258fae72a8de2ac69c0dc97c90c270e306dbd8eb681ba9c092896b19a8d42665b94ff4d5b8b188f19f7c44abc8f88d4ad7b5df1cce3465de377072c70dd20dbd6779336f05ce328ad741d1e4606dce7065347df111c7d3282c8a3fa4a9458561c04d1056cd53ec5a8ddd6bd4434ac910c69cea0443fd09ee32d1256da44ab7896867a0c97fe4faa4a53b6db5cbfe3812a6667f04cd318f3da127a0dd46170cfbaadfcca863e0d4240ebec1cb2a5952881fe89804892d36dc5bd6484cc78db41bed868ed1b321a680a293bc29c420cffb5305d15fba05c76c2138b986f799b6a3d061658e498204c2b641f2f2ba73d633538eef6b5a01117951eedb7611742c120ff24261bea605e94d21e452ddb9ad27af08ed972b7d5e1eae010ec5d83e4505f6a2b7d9a0bb32a1fbba32a2a8c7823e736a69f516b781fb5354be4b0a67343c009a09b8f656c34ab895f9213531fdeee911d677d1cbc5e72c0fd1ad1f3b4b8bc735e14c3f75f1828ea28c90cda40e0cbdc40dec37031ff3d50305d5a8bba1d53d2f176895e53faa3067129a5c97505799967e55e4e9d87faf5920d71055009fd060ad06691b78583f63881b566d4a06b639c55796b23531ea79c6de24092c0e6fb4d3dc739f6d82ee3ee39f229de4c844aba36432d6119be0d2f02e5f72ef1d95fb2494522a7221e18e92cf22e00010ffd93b89fe60b6895a37fca91aa2fefa8debdae3147fe4f01a6adbfa0a59a5203516b2cc7de5faf821a2e72d43beafa30ac379791ad1e5da3286abecfc7a546b80191b7b892cdd01c25e95506471f5eb74568257439aea03300e80699909cc06db2fd607f3279651f7392f80bf4fc61d66f0dfed7b7db09744139d7374d3cdd18d153dede2a65f26130506acc51d5c721a7989485a145dac9565ef6d3cc938c5a51f31ccc88bb0739920ef8f0a01145f4ddccc74790a22a3099a4b57e31b3a01b4118c9e6c393c1304cc51ca1784db5633eb96ccdc88f8b732815b92c9072dbeb61a2cc1e6b2e7098d883e6174f5af7bd4f129389250926e041ba94d1ac543aab6525f151294060791fd26b668d09302c3482c78e5f3271c0150c437b4e78b1cff6f2b8660dc310965f2df14a1f2ad45cd2759433c4f3952402fefd79fff00dd309c3f09a58600223441c11693cdeeaf0a6100d38d612a759a8e01f753982803af30c7470f7bfd1ccf2c08aa0b187382d25868a9fdf729da10bb0aa0e1cd9c6e695eb2c80c6b6ce62737c3e655246edbce5b8f7ae21c473762db0969dc216a93d4db239f67dea74a1de21d50336793d1ae45e931d975bc706ea718a2ab10d66a59d9d23f76969d870ac279611246ed3aab0f79e11611b312624d78b88a9d1a49dc68d6968f7428c33f0a7a65675826422f7ac058101d2f85663de331345b3a25cf76b7c8fe0988a13278be9599b8e4708526b44a70bc31ac5c278ab739e3e6f0927b72507f34b0034e7fdf43364c466bb75b559e03d4d18c864714eb6061f83a6331b3f59dd62f39bfc2529d5cc68bb6ce63db1075105cbd7d7c4d4ab68c9e65a32092e34e76c3178382a965f49386bd4aae307128242a2ffe3022fd7dc1a824b330b9f032d55573c2f004a6905178a2479ba8a2d5b3140ed5f3e10d986265d8b4cf262295658f301b4d36281611d9c61624928da9abc51ff9a6eb481310511772fcb1c1786203d25295e4a319b9c6d65ccc966b4c5795e6e30b2b3ae8246c38b4a911d1904145de63dbd4470fac47f8ee3eeb3f58b5e665c26a316362382ccc6bf8db7699fa3334cb2ce61c746a7d3af24d8030df6759835f5890b7dd1de538cac1dfe843ad06eba2e887f08d9a49b39246fb26eff5cacc937d63c8d0136f7a8ed2af4cf473f3f0d9064f97fb4fe9938d631f7cea3c617c38771553eddd606ab80bf792f34b44111933796fe1fb8bb104223a4de9e16e17321ea7f8de3306e75a2bc79aa5e9c0ec8dde9b3dd1f2ae42a6a278410afa8fb62c16282f1e3dc1e2f8c28d4538a75b5da7645101253dd43aaa150b273f73e505d490490314606264c737bb344b616a80a4931825043a740ea4f75847e98cc99c6880d3085787903e54c63e90b60f03192234ab20cb41c70c6e82b00e0575a1bb0b0f435831c9ceb9dacd1fab8a7328eb3e28533d5bfbeace430e21758cac204631bf033752f947f78ac2bbd9423c2baf4dea22fcc65c96c332ece9abb20fed504643e82f3ba0fff213635910789a2fe1f2cedef68799fcf4a86d63ab0ccd395d6d4f393f7ee8905eb77df32d97592fb34ac86dcf20cbe5afbf9e9cff37bc34d75af046a09a1781cbf51ee2e0b0f40096d85413a30de974c4d1d16ec06c0fad00716c4e10f8dae46ef3cf27ccde74502b657d3dd26b5481d9787f5c6034083ff88807896da55fd2c951a28f15c8c9e6c86ab50c369e5ba4f6311de505c07c7b85573b5a539785820c672557cee4b58dcda948fb51c95674c23f1275b423ee5bf3a646df19bb5dfa22747857fb5c605669f334d116710bd9f1495e242bf47d6b607c1c9d9c706ee770808484ba552c978ef64daabb642a7caddf5a55facba474b8a63577ac817dc57e48ab072bc6a2cc5f5ae96edc45af41c896cecd8acfc36604db3b7fed9d2d17d429f94bd2542b194a3d3405f46c1021ecf6bb907fdfb4b53fe445d5adb18501aa772c9ba75619214384260306ab68a5ab59161b
+Ciphertext = 66c03198b3422cf3fd8291080f6fb3ebd9ad863e41cdff169becde726946a342ffa0ee547a27bae28cc782d95a90b0a618f717e3beb577354bd91e00a7a57485588265ad2dd0ab946926fea7c754c42751ec7247ee84c17262c0ed092186ec57d6044f0ac9deb21da6714ec7452e441e687e138ff144ea95636286263685419afd35f002830765d810b6f60e8dee0e6879995e9272c798b067d5f99f49e460b86d67c641f48240b61a16dc7cc27b048e8b8e8e80016470ecd2fc4225e29bb127ab48dfe7e7d5a65542176dd7ad40c07ac8b92891d595bbd7afb63fb6f9e1c2aa2fc659aa101f9b6a5c346625acec86fccf17f0d45809f3b9ee81572e5627f1afeed4ba96c6d3ed7e9232358dec01a1231ae7b94ad4675239f3b456adccec439b3cdd45504c5475bbc77dfd242e5e9671d103ba71a4601a7322e0e295357f335fa8d5651d528dda66575d106308338993e615b1c5bd7e95bf3f755ff726b4ac6dd5a43ef061ac9783f8f2804c68f66486f5844969103a36278ee0d10798bf8a802d3fee3a31294bf00ee74f087749ab3325c027d42b55b197469a5312bdc5c9b316b20093154e66605941d58f4db8d46a815c06f209c1dce2363771b5a794dd8d17e93a2fa7b194c6a0b79793c06f002638e5e3052365221232cc4b30adf161cc6e7865cf02911e2ac9b0a75f000e7ef3aa4f3c7438433513da7246d421f208b179763651f18e22a793961e5976a74744696912f22915244fcfbefdc472baee0be1e591d6503f2d9511ee1eededd9f5547c95eb94de134d0c2186109935207a23b2b8420a5858d831ed78202be855cc6b98d6663c1c52e1a0022ed7ebe0eea6b107da4cf50c1c7fced9744a914a66d4604a081587ce4b7e0f96ed408b8a9a2964314b1334a123d5184889958e6467a6d16e7615e5364e09aab75994e2758345511113321a3436db79351c63a282095ec6b99b6d775a5c09ea3f3225716e39e14df260bdefb2ecfe9a65c73ab4b3712ec842e43ccdfb535e3685fa39b4912719e67bbe195e5f0fe6c3aaada2d81b669c4565921f6c183d708b50c3f7172ba841815e9351fe5fbfe2fb1fabeb7cec9bd1dcf2d6332372f1b972b5144aa7ed6c5a985132f9a54469097e2e981b9e75a7df48fa79d0736c6f8a201c7c7d0ac8ac6512a7089514bf58442dbae0529135a7f2455e0ee5716c6610bd7600b3159197bcb20ca055695a36597bf7d3b18ecd08031b4ce3a643951e231c7ad15481e32ed7a3edd2b379c8e96d3288d5b93b562972a04f1b7e0abcc5090cb8655422cf5e9dac0b49678138faec81c78f113255eaa6110e95406a7e7417a6e221a8ec7fb9d55643bd589ace2da70fcb41722e66e0efce932cd7a34218375b6dfa3df1747953b24a41f94e50b84bad4d130d5dab4194665338e06f102f46badc5dad7aa06edb01f8a31244dceebe5e2006d6ab4a31582ff46731b19071c08ad1db79ba018687f3e6afbe703b1de26c11bc8b62fd6b2fa3219fa7190379504820abc97ff6c034f7850e2c7fd335462725db6748fe45920c213c539356b691f22eb490faca24e99f0a044a9f727d0786566ad00635983692ef324bbf1f80c42b269e9d5a8df3249873c51521c81400c729ed7a5e73995928abe94d189cddf2774f1735bc2060bb2240e558699c365dee45fa68801e6a1745e03736ced1b89fc2755565e3b36c2102594d43c451122d94f4a263664bd26b2fb5bc7700319f6b08796864f92d0fdb41710910bbc13aa9cc7baac3b48a24e4f3573f315448c317c149ddb433d9ddd2a2f0cfc81c22d3dab31f184975355b41e4b36fd8f22e8efa01d61a5cbb0e4fcdd273cdf68ac73fee745faff44d44d93c5a111aefe4a5ca8e8e7c075ffdb738cc5b6466dff78ddd837c72c54941707b04d60bc126a3a2fae9540ec2e4672ae13de0d927a7bd363f8abb5a56364d6d564df90a46df9fd59e2c54d5bcb8280415257a6976d8fb24c33330af32600cd1559e0eb05d55b34be456d434bca98252fa531486ce2a24c8bdea1d57d93a550ec586920903a39ca61cbfbce79b8f3a5b1653794872b2c614458177e748f8dfd43840e5bb0d608c26389347673fd0b005f60f52c56731ee5faec6c8d0617fb53d5f2415c2e7906ea0e6d0066354b213b3e94f4dfc311e4ec6afa7e8d1c69a63cccf8326741456a5e0bd0a359b7a37c117f7892969ad7b70cba9bea0a975ada7cf67e0d7255be8d2c6e7b8788b9ff14c5d1449d6173e07b5f9d94560d46f474ab2a67056fe9f4a9fd617a617d23143adb4e7ea35f2d5cc1398fb9ed43ddcd10f28debb27eb13533110005e6c78ca4a874db68c65081ecb8bff1b64eb1e2d7b76a1da3b375dce8a92d32a6277ed847879345717b9649f27e846a701549311c7e69a96d61df616157a114bdf1663ad93a26c28e1a62ee4a7c72bccb9785639eaf1e569decf777bb0548ad9ee36788cfa1150eee3ca3c96f09052ba2300cfb7526b9424b6f7418c27a1e9bc13e4d9868e5c330c051c3885e44714bddf7cb090fbd0f36b826aacbe191dc8c35c219e19fe736198c29dc4fa1a98b5fb1805dc29ecd02f74d4510a3928448b5ee61b5991e46644850a4885bb1ee272883faf27962430de1922d0883e7e80215cf5fe7e8f3fd0e2a49bd50727af793cb7e5b40860e80a1fbb9d5b5696bdf2f741909ab5a713de47716332df6c4f78288edcd6ea130d895fdb2f29f94635bbf2061de55f1801bd6a24294aa199d78021a1ba771c651de4bc08f032fe6ad7a5caf6a6afc6de649b901f783a0ee0fea9b803beeb0f431400d0707f159d7dc29c0c334a918fa08a653137a4a8bc86066c8800e1d171f1dbddf1fab8a3eff6b5023da96f002e7e217e826fa378b15dc8a376db30228f5d6b629f331a162d63e53e5b5bd7ff9ec098b4314285908281930ff0a8aa86a6d89411e6b5bc6b9c9e931623ccca6741fd6d36311e6a8e323a37ad40b7a2797b84694e736d9c135e52d149c760e727598726378cd674b0f4df1c361de0a12a2b8232e611d789bfbea699e8e77b99f3449609caff3d6ef7233df8cfc624376c905eea46c6f77c0b01d288868a19db77e227dbb5bfea5cc3f49d219c7477f7f2b3447b0b8efe08eab8f69579d727555e547c13ec7ae13b83386f2adf634140c311b6e2759cfb9c8aca1c32bb7c002d0f46ecc526916589a29e328ded9679c2163838f071b5b85b35e5e7d99c3c45d25bb9d37d7bafb8350ad4695a6e0cb7ea7d93868c30bb54e301e21147696b7dda156226a5ef8c62121e6b2cad0c4e192116192012468eaad46bea69a140aa3cb9056dec87c911636a1e55695b9e5a27c63cd8c03f31570d4b7507d13731ea31f082b33c6db8dd6e22282f9790be41350a96abfc4dc3de78e0a698930f540dbda3fee923a463a4c4a66bf00bb2cdd6d22b62a47af96b78b1f0f0a174e4ec5b785b3820f47d3c8cc1691d4751ce4e4ab78a4551956158a36717dc35488e890d0631241906db565603205e054815aaaaf17945c3372dfc7193369871e2e88fb84c15a2b9071101e1208177fc18397e6af17b5843e1fa75392d8d3ed214975d50f2b19c24e83f010f8c394ec1edbb1cb912e61627d2760b0e630b986bba2ae113b8f3b51ba00ddc495520274a85e6f6fa7573ac4ec6e2a86a1da9199ceb007aa6f132e5ab8ab8fdca7c829f452ff17524fec475b8f485b29fc6f0d972eea4ce98e242b5d58f6ddc1b3a71256de1c584c9914a3cf1e469f0033165d934fae68a7559011dac7a4e0c72e3b398fab8f8cc2fb67963b0f9220f410e5ba13026a27288a1d49edfaa51e8f220503fb5ec476147cbea975994fffde3ddc51bb189c470078978d238f5287fb2629d23989875d74b006a4122f6a342c996d4a244e8c5e4b804a44c301ac4d6054181a07964b279e0a44c158364395a2ead40053d2f3350ea0529a57552ed835513f533ee0c4b94ef674f31851616a4fa2d0302d13cd4aabf5f96ce28219c0b5bc0e5410fe0fa387ba1009a6f2280f9e7bbe20c33be5eb411a5f6327714b3443b4152cbc54c4012473237dd98b0490fc4228ded74afc81be2a58a22e03ca987faef5310e474f4f5a183f6b7ebede5a8df8a0f94a87a41852826b29466fd761f40b416ad0f263dd34e5497867766a361af1654c3fcd6ee7e6bb3f72d64cc980f04305b63bd574f116d1aa35b4bd642cab0cde6a29139aaa163805c6c40384313d4ec6027c891023083988c1b0d2edbdd9b1afe102fbda285a6f897efff72a0d7fc19a3cb6756cfaa2371e13be3cd167cddb90d525cba7da69608b9995cef92a6424a14df6b860ef0f09830fd7189497a432347680de0f463c0aff82df8098cc4f7753f7680c8c7374d01046b05c63be73f3a1623be778fdb0bdb90d4fb4b458af2890d15f108b0927304c91c8d62cb148c35cc93797db3ef9bba1014d89859a91da0c0a971f330600d71565d30e9c9ea8c07e7f629e1a6d578da04d37e597261cae8ab7d9a952bbf71573f1bf70e064f36c032cc624e3c980e5ea46d36232d61a57fa598347b7fb6b28401e34628b051d6ca3dea190d1d3c343fcc83175f70f77a8fc5e8791b9788989df1e37cc4881648f4fc673772003079adae55c83cf02a894b98561e4a6e4416bea3df18d6f702ad5c4f40faedec6b53cfdb5b3a52d7d43b97ee23ccfa2d30c7264ec555b15f1d9e7e19cd9890a7e8e01ff21d3b8b451e50932f189a420d18e7c7e2f103332c78c84600e5e8fdedd84f055a8b39be9a52782d47c6205c0de41644b09c0931f2da269a7e58e669f3b61ebda28ab8e3f9b83ff3d2bce37864af494860b2f01b000abeb737fbeaf8f9fa6378366606dcd0fc33031b94f9a7a0e562c08ea720a671ff92520047f69b138b4e032c3828874ec4c29e49aab302089956566372b20c0216b601c3958ed9691bbd89f1df45c6613d469e3b9758a70c860fddf768b10a6bf70237a454a2c0b70dd5d02da612a91fc5731513012a4a6fbc16d01550bdfdccaeca22bba104ccf6aeb19f21d4cdd3da231af8ec5bf2a726ee9cc7c85b8ed46d2f6fa4f1b010b2561fb69690d5a9df76d729450a6e139962bdaa2bec0254c5a252b97e7ce7eab1817f454c6121130952b8c40628065dc9b77b0f953552f5aa3ff983b6a51a51dd87c2b51a18e14adb8c80e002d0b47c61cb357babbbe3ed51d371941a8f111837ecf0e45020cb941de170c4a1b5e61bb928b1b11a8d902febd2ba016771f171b8a7ae825fcc4642d95649d53675d0027822e4ff79ffd302bfab1a0ff26f3648c7ab00c10f8d95f21e40ca2b40691bd4be79bb9ccc0bf760a05be4728bbc0a64e585207d1d09393a80d5f574442d6a933966777ab05f699c4e84aabbf753059287e7261d972745906a4fd8967bfc80ae9b6ec2ee1b22a81775f4f24999987365ae2dfb6739902ed51b9a4394fdf29f216c34567102d9db301661b09b728a79e377cf4bdfcf5c83b110a2e267abf6d40947e643ae2ff0c244af168c9f33e7685474ac30611ef95f218e0dd280899a92a41e7a759d03ce3709c2a140ebd35e199f1dbb96f7351cbe1f3de8da8c49758a49b9e724ebd3220ed6f51112944f70c0d1e9178f68a2c9476a913de00abbd1f5bcffa646f926da77a9e9fbdf81cdeaf7f9b13e843afefbca81c93614f8f1675325965b5836b8a77620a5ff162e25366718d8da7781e1a7e01fe2e9e56cf958c6273473abf5c2c8c7fb209307544e1c0726d5571e521621b18b6da3064b473423536b1b76ed75b21b4ee205d7ab5f081bada63062706bd155672dccf84614210d72660095437c6bc2213d9c904a4ba1bfda14d350fa3dce7141e817a50859b1a74aa64560b2ebc67add9f945b6e85577589817078c8ae54a9fc311593d2cbdb6692b089ee6264cebcc7719753f80e30dbe48b64fcfd1037fb9ddab69a5ff9e5898bd8aa947d9ad827c26df67c6786edcacb3478a20bded1ad8c48018ae0d439bb5afad5d39bb8fbaf22d72ffd759c4fa2e94a5a89f41358ebdc4c3aea5110f1965a049fdadff9cf703eabe9628e2680fa4e70320d304ecaed13f513f27220db1916ca1500f1c2e091671fb71329dec0bd6e310c83e67af61b8ab60ee1a8d559a508d174648b1bca451ef0ab0ee2ef74f4fcfaad1cc5ea6cadb8f1bffcb1f2c05122011ebbf6abc16838e452fc47653821589da4cb5bbac10deeea3ba0e0a6241338e64cc78d7a923d018e8b5b51c4442070e5b0e6f1e8c2b83791e930899c5897a602c401c1b85827962ff56d19c06f5af033059bc7fb1bd29b65f66aa5b4397834e846935e523b16438a42c1f990ebe4f83182163ca5fc60a4c6d77fc182e81fcda943a962e9e7f00f6399728b48bbe38d8178fae3582c8d9998e49df5f28e32d541636df3cdc8ac00df45db12da2e5e76f366c1ea8667ba5f3542d21f58ead7c55d06a4b35251b8f77dd34d3de262947379107a06d2f4891ffa0ad3a3e5bb2bbbb978af4953310d4cbe5525ab344ebb98ed24d003600de8f3af36ff3d0a7efeada963845d573685bec2221403b994f97b1e714fd7dccc300b62c2a516e9c6780983062eddde0178e93fcbb2ed4f06f60767356a11d22ca37078fda1ddb3cb907d1020f62ba85d09044574ba28aa3df36988eb8a41e4305e5b0687abe43a90e4f68f0374b6b05049aff5b065d7688cbbfb0e96ab03df38903bfa1c269f43a114085eb4596aec87ced88701b42f0b7426389727308bf10aee9d8f15ebdc411ce1e764a290a12faa2d7c1126dc7b5076f219b826ac8d380b69af7f95d69fc3929a97f5c7da1db6270e9ee1f2a5f7fa3a1b6bfcca00463655121f681d3a627d03efdf0b5fd045fb153bc4488a9a8b7264373c710ebfdb1c267fdca37723b21d5c3eaef48e784bd76e27c133cbc24d114f610c79f2a1f2c30d87ddba395887030b65097ca5566eb0361e70615b46d4b86c2759f1cc2efa3915b4cebdf51a745fb3c6cec69a1fda2ec5e884dce228e30af362815d2d8b59a14f89606bc77439042109369a9648db7d71024ed6df06c8ebd22e8623f48feea77f48b5e88827fafa84b0564151a5997b7f29c4d3d18068e34f2690a293d54003d0ea8f3bab9387ca72212cedb5f4602ad047dbffae2ab3a4cd2865bf896cd96f78b90e4017eb7e3c7092320c0a37f81dd65a5c4817a4e7053e6d2bcb23b11e09f681587f3a9361e974ad54b88c72c296629b1ab754d25be15e87c414cff975fafb3d7cb68167b21f1889685a48966705222b525fa47143b00041df94817c275d93c2550fdd82471cb3cc1b5644338060b767e807bca902c180b3e535c77be2651b3962287b6d1f6403033de4e0aa3a20615ab59d290f4b167325959c1524ef216dda2ffce86b50cb6b56b62a20a043d9d78c704479c22340151df5a1907670f8d4f8c90d93f7b5d94d04a4d383914867aa3c0e5ac85fc299a4d2801a3f80f4b0f046fb62c1c8c539a83b21c7549df0afe200537b52c80ebdbad8a438e430cf876cbbfee9ceb1bc5270577c27d53b40ac153cab377a565b1a9fbdee8bf8e94839c0fc04f7f664383bc90d56ccd1cc01b465c250b158b5e6f321c20db245602d10aab80c553d52f17282b095b5e2234c6c689a84b096112100359816cef7e92029fdfc048058f847cd2f2369ceec9fd171a0487bd7acfed6b0319832df6d59affbfd460ce8d12e4171da0f094e872a2888fe74925c5ef0621c4edad337f7006086748913b24d4d48ce36e662fefbe672b6d476456b1fbac6d80030ab93da93acb4a7e10f955547e7e20a0abcdbf909f05a2ee2e0b7485fa16be652b9d9fbfbf01f082488a81022bdb69af9e6fbe753e9eb92a1762afbb4df49f83ffc0cf03db563aa96fc5ba1af6d4d7eede6067749e8ecec79b63e09742e29e99e1c960dfb0688b0222c49ed919379ac66e3fa1c72645122d1664721e78fefdd1224c0b886f6e214e37d268ca9acab76ab3adc9f5549e5dcdbb3d31ac34ac472894d004eed71f88ca2377fcfa48d3ae43805dc612891dadd06c263ed8617194f890bcbb964f010d277ddce1f6682e661577ecd51a4d5421f00935a5b24fef0ea1809fa5c4fe9cf8c453046f61136ec8872915d2462157d73a205d56d77bb83cf16b88cadf6430c0e5397fae1f91a6a11b177bf04b065a2e55df81d5c086ec8dc8a0a660eed37d41fe4d8b3e3f22238e2a63b6e4feee1fe9a140ed37b2be4193f75c2d038aac7f6b7dad2a3b37e5b9b660615ec1db77a9b7ab416f43e66c872b71cb67c9245c757dc87723ab3b9544fdd8a16c9486e8ec3c4a44cefd98535d6e5683426c1cc8c888b8e0c2e7528bd7eb89b80d9e00969efd2f0a0fb09845426edf0d1d9a0809648e7e46ea0a8c9988bf9df475be12a72c7326c1f2bf01afafb190cf6f649133c7dc14ecf9b8c971135bd303c8894bac637e08257d45e1b68edf550d896c41682c002396e8f1eb7c1e2f4e0ed9b8b7010fc7847e6fb1c5907c17b2d2b7cd24c96f47406bd04cfcb2099d82dc2902d6f91e2f8f3a05bc62019af536309e7847fc06c10dbf7272a1509079fd16bb16a85ae2e078f97f9ce66bba66d6329c7ee70f9688f6d91aa38b25c7f4884658a72ad8cbf96d7d7a9652673273ee1b3d4d17780dfe9ca865416e318bdcbe9efd8e071fcb15ceb0743df5af4f7d598b31e38677e65af61c1109fdbb11fb11e3952e6c3ae8abc3f894ccdf205ae55dafce1dd05dca6b899877f57d712223dde4e7fdec7e0ed4f0a29ad359e318eb36ddb42fb205adca400f5b2615947c4f0ede95788093a1152d88acbbbb272750823151e245354e658452a95f21fef05bbfd98a10c1c975ad1a08c59fa3efa9fc73588407a83d0b26a53f1b4115f83780bc70ee2619d7374ca45b9e200055df1b93977e17aca89a009110a6e74caec7f86114f91975bc6e8bcdc7267ed2920cf12cd7137840628e1b8a0ea181dfef18dc5f74e752f842ea91bdce4b420ee709bca72c4514e92bcff55902e5529d77fd95f5837c8f4fffce80c813630550a0dde24092a25f65eba90790a06f4d4c3e739aaa8194a147fb32e81c71d3e8def79251c33637661b0a621a2a6b302dea00d34a9dbe9b621c1dabd0464e85241aa6712d90b4287cb23c17bf1e4d0e6dbed372e6b49c4a843305b3b0e5cab0b0964a93ad0bbc99ee711afa7f2d0a296a375fdb3176c65a957ddd9b88e9d57df736acdeb02a71b924cc2e972f51ba68a597215678573bede9ca5b3a0a2461b2d3b9ea57a5af8c91d40779bf917ded32f14a66d96e28e1415fea1e9306654c6b84d8a64243a5271c1f11590423c718961aecf5f659b49f67efa78e02ef2524d0966ebcc446d73d49ab7ec31f0c009069d14ccd63f926169291b83a3e37610054b0b964741e2ed8771d20bfa225eac0280b4d5af0c09d3218bd497a035536f5af0816884d606f1a872b8161a266466b56e0be8b80a7bde65ac706eea8cacf1749e5e71ff9fa3e69ce878427a0728d44e666eff977026abfe18cf3ad156a943b917e72ad65725a9a8d60b7b5740494fa63143a7f2a94fe6d8b319be55d6fe1a988244deb798f345f30dcafdb6af9e9cee9e35733274bdf3896750897371563ed2516c4ca6c3c3c994b48cc94b67e8129d234a0e19dabe39e500214c0ed5f0e5d61b2f58d7355d147102d93b2689bc5185dd4c0a18efd11a307b887d4d0fa84fd992731b3a80dbd027dd36cd6933766c537e8e9e27d35d5187e8276b0f59fbe7b6d629d3416b782e7981d85e1e890853c3aa94a93c1667a55044ae42badefab979fe7d525c6a180307c5ee3a9c3933038028c3e1d15d1e78fbf53b6ea61ac5e02db0161719398a31570c55f73cb47ddec8f99e3e14af5adb8d5cd179f4204d080331e75bd391b19d38eb81f148c36af3e8a3ebe76209bb75c9741a89b5d0708bb0fbb0945fc6fcd6ce142d19faf0947c338dbc8d976963281866b5216421c00cbd77c0907d1e16f5e925319cf6c62f8c6e8eff0c2f831c504e7a1c0df09a54e2af708ceef39ed7d0f63d83429e9b0920c03cf85c2244f2fbac3958847113bed577dbde8992cd91be5833c75faedd5e2005d4f7b66fab8fa9305927406f863d1795dfe04028940b765bd79de6972dc7094fe1c2503a73d7b50208835216c23aab3e47094587549fdd74bb50ae21cd1354daab632fd0907e63f4c2b2d39d7fdc4fc216bfa742b4608238623cb7fa01bd851c1e7ad5ef5215173a71f363fbb7dae8092486f4a1549e32ae53b14c1343ff7fb5e2b1487d9c594a1b56e22625d275e41535534d225b7b2c9deeb0d30dba7188cf75d680d4545ed05044a0661c690a37fa14a73ba8c68357e2c948e290b5d9a4b51822824614ef2938d19ea4b650041f59f3b548f0a305b86f55e69760f37f09dfdad62651aa5fd84eef28a4431136b34a49c9bf1f2891364f86b0aae70b0414e821e3db1533b0f1db5fd232308bf118f858aab5ae974c10583f61b283a3870eb82aaa8ea3c4e2ee3c3a3d7169aa8e975ddee7f620f6c5bcf3eaaef0101b62cd54495cb8809052c9e3151690cff7c1efcc4f63b22472111a7c5d9d7d2a2be951510f60dec8c426f14700c8630f8a14dfd359addf5d9b7ae031a745ecb4e17321b385799c90f924c4780287ac187530a40b064064b9036cc46e3f87c4d23aeeed1bc22a5411c7c503594d5d1261eb9fc4da242493beee9f671485a978a32e965faf9b0e2c13f78e31e1630b72d35b4be691e90b3798e18223c1b514b39a8e1eeb7897c22fdee1e33fc76e2b2f9298ad4fd89f44163aaab23d754d98c7890e58708b81b3832aee31aeca85e76416133710aeba0e5d9f17695e607d09ae3f94be191553bc39c6df03cefb4ee05516fc02d66c9866e4eb0d89a662e309379a347159db2e070abceee226f2b8b62847ef7c51d69c5f12eb567fa13af4b4f90b3f3d9d4b6a3f68bc4dd77075081e2e99833c18b154d0d6ac360141de2a25af61d551f10a34e03e1419a37409b4c177c51a8d248157b411868eb607c34d2daaa453a0954fade5eac45d5f21f50efba8bbc9c87ff0435c70f064b42cb2d158384fe0a4d9c90030ace7723af0a6c8faecd8f97f9850e2a489a94ebcc655301e2e14711de9eb08726638a9ddb57160c5545c152a26860a17dd18172bfac138a300f60431fc49eff18c93f71400e887f878f4dd637cf5df8c1e2b12c0f87e31ba2754ac1748479eda0c4184b528554106128320dcce349939e5e6cd3434f86dc7adfee28c008a21ddf9d0dbc87ceb14cc3afbef1e06fb3f9908a4b14f5e6c43b23ba783b75a6cbfa2ebac6533661b8c1143a34e8e2a9723389c4b7087dc07701c53b169894551084aedbb423bcce2f470881fdc7240c26b3b76fd6cfeebf8eb2828b4741e5e8698b19fa0a44703cb4e4c8ed6a7e4d6063f5fab724e08a159f4f04a2f351dcfb6335ae6697dbeca25c76b55e6ec9045eaaa8706902df492b8c8cfbf68c4cc1be5d1e5a173262e38bde051656ea85ffe35d97f1b25f6a47381bc327a946f7cbf6210adfd957b2921
+AAD = 85ddde4720659e80e25168585a354eb1e021c0b5d2ee289f2314dd5aae52bdf1fd44755bb56a6e659111a1d4b4da73315bde01c7d2c15a4f7114aefd68c141049fac27acfdca24e65c51fb1c27d307cd948e13af2963166bbc9411401d124f1ddf20f890db5611385257f52aa05c09b467e3ae886decf5744ec3749e5879f2a60017f601bbee11a66604d5f3d521d2c48cea1794f77366f29c7bd12a8aa51d34a4f3fb52809561b527016bc6badf9d136156c330e1d69d1aab98c7caa9cb46e782a898b4c66e4ee3e2445fbfacaadf9a8f73c4cbcb2a1ceb604ba5637b51337fcbe0fc366da98e805ceeb29feaf05420113b16e1005079c0e88af33f5970b3d7a8b51d0d9f5120a0795063db508171b75ed07705ac6d6bfe4ecc59243091d48865536515e036860affa880bfc91aae2fd1700de15994792aefc4a176e5d49d0f9135c7d670f3cb8798bfbe83fe73de7427e0f3e6a2df561cfa15ffe6ae80d5016096c8875b0beac8cee8fb530fb421b9a8ada4d551a528d0a0b521086f5a2db371a3bf12a2ef861f831fcb44cb2baede907a9306d3e5a3af796e0a50ba2c8dd61fb03727df5f0654d837dabee2fd90eecb7b2e8f303b0d57f97dc6a52d8281574d8457c89c6a9f5d80e0bd86c90ed39b1db4253affee614e8cf1ff05166c66e7d2a2aa2fe8a81c4741339683debe189c126e7f553a5f2dc16fc16672f74aebf94c7e3041c758fbc6d0c7f71c192cfd0fb2ec52d0a0705b05815d567f3d19f9b5d553a2adce9a79159b0e38980851bf64e97f896c028a6df8363cf1f13f4654265a7b0c0b24198efcf4418c32772bafd3980dbc689fab12e85b3ef4a491e2e5ffaa2fadaaf3deb392105a42380797d3b41ef61303a6016b269ec9a9f6e3f26070ff33cb467435ecb325dc7e18728a5c2e882e720c8f876fef10f5bffd5a925cdc9689d934272019e90e3a3bbf63a295f207faa5c014e1517c7d5c18c3ed70e92304d51944dcd3604c999d4aa8d8dbf2a4c69cbbc08635c968a20dcb80f438d43c57851c4cafec0b9568dd6c19932fd3f1294afd16f019f20e40ec87f6f5dffc7717470614b2de6e9000969e6b7e561cf91c06dd379a09c6c25c7841330dc78fc5be1d9b86581a81f55c0289531128638441fc98a1ad9472d74e2be2f874aff2fcf9c941502f59f716185a4c39289ca368c6dbf5257b5dc5e57a420792c26e602e4ecbc4f17c8787004eb88ea091d6b6ddc3c85dc110b5d1f46f6e1d872723176f4c73664ecb4219258fedce19ae22360354fa4894fe51d69434c2e58e1ec665b5cc33bb295053c591b474b6ae178c8834667bef971604279440170ebf3e739a4ff19704e5886767f81edce95a3dd93d1147995e7eb6c794b7be136658ed23cec7c374705ec0d8479dfb44cc7213076668e5fbe6a508537a9157815c6e5187b89f
+Tag = 469e3ef168a64945f76d7a2013f27b68
+
+Cipher = AES-256-GCM
+Key = 0000000000000000000000000000000000000000000000000000000000000000
+IV = 000000000000000000000000
+Plaintext =
+Ciphertext =
+AAD =
+Tag = 530f8afbc74536b9a963b4f1c4cb738b
+
+Cipher = AES-256-GCM
+Key = 0000000000000000000000000000000000000000000000000000000000000000
+IV = 000000000000000000000000
+Plaintext = 00000000000000000000000000000000
+Ciphertext = cea7403d4d606b6e074ec5d3baf39d18
+AAD =
+Tag = d0d1c8a799996bf0265b98b5d48ab919
+
+Cipher = AES-256-GCM
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+IV = cafebabefacedbaddecaf888
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
+Ciphertext = 522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad
+AAD =
+Tag = b094dac5d93471bdec1a502270e3cc6c
+
+Cipher = AES-256-GCM
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+IV = cafebabefacedbaddecaf888
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+Ciphertext = 522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662
+AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Tag = 76fc6ece0f4e1768cddf8853bb2d551b
+
+Cipher = AES-256-GCM
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+IV = cafebabefacedbad
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+Ciphertext = c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f
+AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Tag = 3a337dbf46a792c45e454913fe2ea8f2
+
+Cipher = AES-256-GCM
+Key = feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308
+IV = 9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b
+Plaintext = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39
+Ciphertext = 5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f
+AAD = feedfacedeadbeeffeedfacedeadbeefabaddad2
+Tag = a44a8266ee1c8eb0c8b5d4cf5ae9f19a
+
+# local add-ons, primarily streaming ghash tests
+# 128 bytes aad
+Cipher = AES-128-GCM
+Key = 00000000000000000000000000000000
+IV = 000000000000000000000000
+Plaintext =
+Ciphertext =
+AAD = d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad
+Tag = 5fea793a2d6f974d37e68e0cb8ff9492
+
+# 48 bytes plaintext
+Cipher = AES-128-GCM
+Key = 00000000000000000000000000000000
+IV = 000000000000000000000000
+Plaintext = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Ciphertext = 0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0
+AAD =
+Tag = 9dd0a376b08e40eb00c35f29f9ea61a4
+
+# 80 bytes plaintext
+Cipher = AES-128-GCM
+Key = 00000000000000000000000000000000
+IV = 000000000000000000000000
+Plaintext = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Ciphertext = 0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d5270291
+AAD =
+Tag = 98885a3a22bd4742fe7b72172193b163
+
+# 128 bytes plaintext
+Cipher = AES-128-GCM
+Key = 00000000000000000000000000000000
+IV = 000000000000000000000000
+Plaintext = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Ciphertext = 0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40
+AAD =
+Tag = cac45f60e31efd3b5a43b98a22ce1aa1
+
+# 192 bytes plaintext, iv is chosen so that initial counter LSB is 0xFF
+Cipher = AES-128-GCM
+Key = 00000000000000000000000000000000
+IV = ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Plaintext = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Ciphertext = 56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48cf7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e501511221376a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b1070bef1ab5e3606
+AAD =
+Tag = 566f8ef683078bfdeeffa869d751a017
+
+# 288 bytes plaintext, iv is chosen so that initial counter LSB is 0xFF
+Cipher = AES-128-GCM
+Key = 00000000000000000000000000000000
+IV = ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Plaintext = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Ciphertext = 56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48cf7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e501511221376a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b1070bef1ab5e3606872ca10dee15b3249b1a1b958f23134c4bccb7d03200bce420a2f8eb66dcf3644d1423c1b5699003c13ecef4bf38a3b60eedc34033bac1902783dc6d89e2e774188a439c7ebcc0672dbda4ddcfb2794613b0be41315ef778708a70ee7d75165c
+AAD =
+Tag = 8b307f6b33286d0ab026a9ed3fe1e85f
+
+# 80 bytes plaintext, submitted by Intel
+Cipher = AES-128-GCM
+Key = 843ffcf5d2b72694d19ed01d01249412
+IV = dbcca32ebf9b804617c3aa9e
+Plaintext = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f
+Ciphertext = 6268c6fa2a80b2d137467f092f657ac04d89be2beaa623d61b5a868c8f03ff95d3dcee23ad2f1ab3a6c80eaf4b140eb05de3457f0fbc111a6b43d0763aa422a3013cf1dc37fe417d1fbfc449b75d4cc5
+AAD = 00000000000000000000000000000000101112131415161718191a1b1c1d1e1f
+Tag = 3b629ccfbc1119b7319e1dce2cd6fd6d
+
+Cipher = AES-128-GCM
+Key = 31323334353637383930313233343536
+IV = 31323334353637383930313233343536
+Plaintext = 48656c6c6f2c20576f726c64
+Ciphertext = cec189d0e8419b90fb16d555
+Tag = 32893832a8d609224d77c2e56a922282
+AAD =
+
+Cipher = AES-256-GCM
+Key = 53a6f0d9b8a81818f2fd7525acd65acbaac82684cda4fd357b1ceb6146b31ee4
+IV = 05d8a92b5a510c3a3dacbbc0
+Plaintext = ac0ae17d3d0ee5935e18675c36d9e43967f6da38dddec14c7ec574ff8473e11ae5019e638232323c175b7672a7462df6709f5014bbe12a1370a1ffb570177927106f995dc8f35bd6e6228de7c16acb71e583c87477dcc7b17a908ce01543496c2cab8a14a21c43b18fab52d8a882dd1d999b4275db34c7f32bcba624d128580d7566a2da4bcfcc4136d58816c437d21e90456fc86381b946b8955f0448e83564165a629cb2edb978e5941010ee9153b054ee429b315058334ad7899aacedbc0bf423de69f57c633b56033c6531dde29258694045c46a797987471ae6af8fee8ad0c1be4149605064aaebafd1c5592e61beca9b5c7771410a276c3ae517490735ddd6af499ff705b9fa68d50650e60c19f5ae2c88dbb6d612afc7be28a5f55556a2163b6f66609f7d9ba7e97c074ea39a618727421fbfbb6453ffeefa643decf11404764515d28fce8ba66b8c85d077c47a54125a38bcb6b0adf6d248ba0a9ea129c887c66ef537c45e9fd3c17ce352e3936cf139e13a5946a7dc9dcb6423ca6a051bf560cfc572ef366940e71c81aa302cb9701f9a5206e9eacfe9835bdacb6425d058022a27fe73e5edeeba98c7a3edb761578ab2ad5a442c2dc1cb3c143c6f18dbe525fedd2a9cee0ada3b2c116465c5cca9a7e5d4374b29aa4ad8adaff8d6b0d1ac3990685240ce022faaa07241f9ff445566b9e0463350792cadcafd5fdf5c37706c0025b3c627185b356d39dcb2244b15566e6e3f8942f730fd6d855daa1456fe294f9156c4b5131e5bde7f2d938ceb6c7f5deb0f847a98b7fd11a3f5d0163eef9bbeb83cfc96dd8eedd447901ff4d3a35c0ea1f691b01385eb39fd265f756bbd77bb61b1741db0502947b4b985382a08a5916da809a8afd3fb1d78d9e16f8e37f51aba100d031d9da8613e9cd2cc621025b47150b3e76775ab23412d74334bcd79746cf601407481310a923047ac68a4e6a7f7b96bcd85bb6f24e38f03c80ad41a0a581b4246ea4715ee561cdc5384a51a6fc9ed8569ba6b12bcd95e6202ecf834dd9062ec539cc8cc4ed64ab9ff85998da0e63161e7391b14de47dfde41523b6c614618bf2fd1edd68a5de1c03c4181569b6c361d955c637abbf4efdb5dbf2f0dd2544329c44b77081a48f53231fa9d4cf6f2186427e469d0cfbcd698f7e7cf773240dd2b807a2fe699f0ceb4a2339e9cde01114b2aa5c3591a82a3a27b308e1e7f092af8ad97bbe7b28d78ecd80c0c0a28372193d66bdbadc0b58e4d5408acace53bd5e12101fcb25754f8c545340fbbd1328287044a29d18f40a24b4084febebe228b67cefd970df6d44ffdc033a50534e5977bda660c589c6e3c3a28b4c500b29ff4a1c3eaefb068784a29914ecab7868a43999833b0b37ae79afe58875a0425262e0ec7e10ee8a6bc1c97d332bc2a6195de239a166486a3c1ad8de3a026e5b1757f9a778a511024a260c9809ae3b22d78f18ac483281a796b1ccbfe7a9b9f357d12d340e20bdf2037e8bb91ef858cdf2eb9d7161a756d8c244c55524f8f5be2e4f18641bc4c2409c14816846c4655be716276d8356e516640da49e8412fcfc7ac0e084a079129b23e54952d8030e1f8ceaafcd322dfb4bd189bb5d940ac83231de0585783387d0642a245183f7a251779bdb12c63e9edbf3d0c94281140598fea9e73e951ce650c984cfb1398f8813abf8f8827af5eb64a65dfd1305bccc45086438ac439a9265790fb225c509ce3c9d39e25d2276d7f3c06d7cc28d33b2c21bb38b50dca5b10afc09da83ba12ee878e0f6054e8d3e78d731671de4f9d5a7b97298b01f37c7e78e5fcf5188554bcf5d42559d3b15153bb3cd5a0d1cc4a96d02ae8b1b115d1ff617b6ad894ce0585f46a2a5f4cc1b83065c1d7b5d2f25f3f4bf9966b4c7d7156931861d5edd199c126f1ee4ff6345023419d0a4c87f3388fcfbecbb6c1e2f4745922b88085d21d4551e4c127eb423db87a51c9f9a140f8a7415dbd70c4b0173e687a40f895404f2203e14ccd61e0e5b0d5aa3fbd1c8affb5807d787d840916ece24c56c50d3d9ed9f19d73f2c80c461b5b3c07dedcdb41402c3826a958d74be48382dc741dcf3e0eb8955397da33941fc47288147736d778914a57effbafccd4cf293e6ed1c7d19b55433bc0363e41546b3638a4c630eb35dc6a074f90185cb9daaa6eab54825a4daf76f49ad918e90e5777a826d6d5d52f32f7ceaf818f87251ab4d1b5406ae94e41cc97fe022b144f26335829d9c81725b3daead621a0df71313d18214ff8dc687a7ab86b8eec3070ee1ca9f62005a0cc15ca6e2f4fd893de8fd91f6210f6c96a576024678535c962a2dab06f56be377dfa74bca089adb7327abd05c3ad7646b5e9e6fc2f29916b34c8642f3c0caedb53b8f30c2a77d1757103b7ed156cdc703911366b02cde87ce7343886987f7a8c028921a7b87c5c0aca7ada34970a6d0d32eb1b177ed8e64c1fc6839b9d08acec19560bf4a815ca6187635f0cabb8bf062e8216d3b09b7abd99e956734129e16a7c4f3beb850fe2b1548729355f9015c9bba336d3e26a27b3d75d75722f7a8170d15ebf77f325c97778a5a9d7c76d3e101eeae354e54e6fa60b58cbdd900751854ede326b58fa5caca073c630f3719d6f52afe675f10d464e8b58e5fde75a4f225063ca48d76efd1b645e4bc89d98215beae765601f635a3bc8cfc08d74722f3d95ccb4cb4e3ea977d0c534a4abb866fb9a31771222cfd998231c30bd16b6844ef71038b67d72c910cca40db7260dff0b74162449a9e2cf15d7dfbfb3a685080e6c83ff4341c95819c0317502ed49af7ae688b52c9866518f74d69b4144500ab9d5a0829b9287d5fb67b78801119ddae7a76e80be8c4dbcec7866ffa7d081406e51cf617be061530b539cca7e1ef9118cc06e8eb2a01425b45947a1d2332e360acd0654bba8f1fa43ece68467690d36f6802a32f03f9ea056e57fd548dd4a3225ad5006c6c931aef1990639498dc88a23895ff1f75520a8009dbde4debc20ecc546e378eb7ed5ea3740d2244036588471d96e4751390b6b76b39816d853944cb5677b493b36de9736ba0fa404ad4b3a7d7c54d0c15072c040064b871401b25b88559d059a9519c7e2446b0d110a4aba9c12555e5f620680d1fea2359bc85cd15b5c0bfd6b3715d647514118cd60483dbc9c83e285192108f4ea6bcbee1f0935044610c68d052ccaba23258d09465d5521e2664d59358621ebbb8f28a4627362c8397f0a9852e5d8daf53a961d4ee66299e2b54d8adf5134ceedef57011f810aea76262422236c3e1a478a759584c7880fb3f32389c4bd4b637caad7b2bd6fd295aefb150754799434e99e0fd45c1cc4698ab14d1f63eeb06e53797cbdddd45e7f87e85b45a3dd0df6335c3b1addee87ba953bde29ed98042d745c1465a967ef922993798966e1c8b96ad6f68404136be0caa2264e24d8d93aa1b99da9316c7780904753d4e0b45cf282b43a0c91bc9ff83cb25cacea2ea72563b2e759b69cabbb6a50d6a0a5ba545622e5ce576cc301ba35afadbfd1e26668782e1d741feed8aae894b564a425141442fb8470b325cf7c8e1552973463bf4e67a2ad58d15417e418bb91d2df4b1310a0a70ac744bbb4245efd2ae642609079a44cbf6be19809a5ff7ad6847432368c9749cfb336ddcc0e6f52a699b910cd24671f38af5dc39268a3c87771f07d53bf220b7c2d5058cc7b0bcd492abfedf9bb295ec304107130f0e98dacaac6dab998b511f176d48daeb81db53643ad194690b6e28c5ed2927e09a1e959c494b90db401681f67bf1e23fe9ef4c903f666ef39332a91a25c63efe9bc518e9aff61842007dda72dcc0264aa47543c0a8b1f0d25749ddfbed487282241140d4c64def1831c4d75ca975fdb03258ddd013445e08bfb479a516b011fe3a12e4bfca439407c0022889e46914cd41a4d92a25eaa57a55bc7337e5fbbd11584dca34adb5643105c8171e53cf04b1412c3107e72330ebf1b52f524b4e72570cfdc0ab179991f3782d05091ea57b1a233048bf062e88939cfeefb61e8beaa90395faf61c4d974b23723a4a5cd39d70f92620f8f4f27bc99ca67bed7fb6e594913991ca3025480ad791bc94a0def36fca491a206440ec31e32bb85850c3606c875708309be63c2b4f5c477521aa08e1d059cedaafe4fbef5523b79f88b57d0c81bbdd09202095f10f13e2609e833ff41b862b2214c22e8f2b04a363b38d26bf95c07b184b9f909ad3a92122e158d3566d2204b22d4f2f3ce11a65544ccecb01a4a5ef62bc969fddcb648224a5c7bd94f8da9a7d4df393d880f537a377888874c19dad357a0564d303a5c1485c1451ea55d68779dc0c11c7c38025660684ba3f70cbbab00d15b34c0f2342207ad548eacb32ebad95292e85211a8669b586d05b0d0b9f278a35ea4d78e97fd5dafca6b72d8e1fbf3e704a60a8ec60befe2e3e4d3d37f9d33a0feb88add59f0171ddeba0b79a52feb9a1f4a7a6ee7c6927bd10968fba788a807409346a0fccd4f7daac3c8591fc689aed881829d479e8d360cdb5819d5eac718a6f860f2d9ef6a0d36ef6e10efbb37819bb7b03ab7649173447b2cd47f3433a2422b1611dff91cee0b10c6d060d4e84a9e3f4dc194514cb67f1e3985be05c845fc92b41955d0f61aeba6268789998bbf341a8b37af48f07b13a676a11d27330529cabcd52365842be559857cbc2a63a4ea1c77fa8619040e79705c5b51f473e13b73fc09c28598e070dbbb63ce884c2843ec365d4c5bebbf815ee3314dde0bab6b0a71a398e2d9ee8ba2f832863fae7eb0c18adcdd17f1dee0df29a8409acabf516c8e6dfea5a264c1c6657f774c86a14cf96eecac18a41b1650a9e652c6c9264b03aa2fd30e333a9f24cd6b0313358e3c00943a1de63ca970b7da2cb8a0fd1109cefbf12176f5dfb59457480428b194e88449bffd8b8d87d05d30f9ffe9ac3a7442b0df3418acf9165b14242489a54b6b47ea543fed5de74a00f61ab2af553b60d8d21c76c42052c72e4841bd94cf88185c39287c04d05f6336ae581cf7528a59b2874795caca79f5600ac64ad5820a91c711ae5a1c3762028242c5c8a9aae89177ec4db5785cd07402d45805a2e2e970059e4e6483074df1bcc01f57470fb66f45ab475ebb5343b727168e355a6c25d42384e39802d7b4a8c54ac94d82de12f8de13630ec8c19f008f98c505dbbfb21b363472e23d0147d1ac555f0981e2bfd07c62d097acf930094dcf239a40699421b207ac2575b7edf9b1d772ab066362820c182c2c5097a47d1dd25ca9e0dd9c3ae94e9a8f0dece74cdeeec3a17803d5e11f037820ea20364234079286a7c291f3424292b0eec3e956513cc6b078a76a3b8ab42c5fb5efdcea1d438f7ae08507275b48f9588a15be763ad094885269efa7330f6fc9d4746997c98d9f5feeb6dff2734d75afc6a11196b35bb9fd0c0af428cacef0df2c5ad4e5fb4559f0f93af2fafad6fb77f453238f409ec71a912350d7b62952e4858927f620d31569242615345265ff1cbbd7fdfaff35a45732628da663bfff3d3af3d7b537337754554458a2d1af0e16aa8ad9436096f42e243109cad32fac1adc58d714cd3d0d8483c783006991f3da263ef5ae1ff2ea06584e45849d64a07170675c29f0b2abcf1eedbb63b6f5d9dba600996c7d5edce9ac69448d05c0704fb9f84e831b60c376b8a5d33ea22030e2dd3dd421d8e0a810a77c085a3861fcba214a8baf592d624d673fb34f906581d923d80b06186db8ce5fbef2bb750166f7556adfe93d4951a825d55b0bf92c9f25776df784f6aec808ae221cc98d05ce988fe6a13ff96083dba15500e149409b54345274e3633fa8f6685d6fed40c20a5c5705f8b37099a5949846ca15def5a6a427eb4eec72747f116366adcb9b74d3de0b125bdee23ca98ee6312f41fa3d9bba43a8d343552c969c41f766ab4341a42ec4cd6f4d1d4c4b1f16979e5389fea36a150580418d95520506fe0cb1a1d861e09d21c57d88c46e10a3c5ad1aedc8f2743f5c06f10d6da9b2bb3ec783c6f5788ce9400795022cdcec197f9dd3ee4cd26531e7f057b6d9418a0c52ecdb35a24a2a079b3d396017feca8b31aa55e3d5ef79c9ea9ccc7e3d0b47f28f273276666fa1763b3a452672fedc94557d984c3353344a8bc9fc833dee685e33d63540d0801d8068cf66cc48ddcb0d42cec881eae36fc2614f96ad67fceb5c98ec33fbade0e3049178d503c13c2d5d71f32f4582d1cb0f47a2ace578b903796768a906998bed2995798251d7eb92faacc19255bf12c0024a94971c185841113faa288beb7e58d4a98289630fb3d230f936eb1b9d9c7b94b5ac9d3a211c0b454a26e29bdffb522548a65e8dde3730918fdf0575245e71ba013ce08f6e698342a61a81b1355d2483e97c06462cae1cdc7787f4bcee4396a08dac9c14981f2a8f4614a31b019c83782d5d8370acf9db467d9d95e8efbe44274fefde5860c2333cf81593a2ada9f5bb6c2362ba97fd7c3e5bc836c327c66b57c0f023efc0c0ff6feae0e625df2f4e21057060170c844c86412700d7d337b1f7835a0dafee5206cbd76104c5a36623c7783213f8dd457b5e69a86b74030a27b3c30074242b1d97e65a233885a681ec5a8532bce9dca1998dc32c6b40dd997b99a6ed6288e0b9b09447e356bc5345b2133571e65d47db2c736a391970879103d4137cab6c0724b8e67064167cd5521f32135fb6ca43c1e118adcded8227c9dbfdc18cdce154108eba5d8c60e5362e8fffc5c9ae6ac2572188617e4ce0f432e2476c74a4227af64b58e0ebafaf0b1ce01723ecd36a2a4167b7991e28b6a9e81992fcaf7b4b906d0361add02104db83914f28baea26b50561faa46293ba5247e8263ac0347509c36405747866d2fa2beef44f366108f6a4047e282a477c28654511075ddfaad9b9844e18e67320a831e647d923b2720d65ddd9ece165c222231d3c3e7f0001d15e3c690e9831ceb369a8edf183133814bfd20dd25d50973bda58ad03c4cbda8008556fc653ef401ff76ee858c1f79a0b09b4232768e72dd06e42078923d5647cb310bb644feb24d6b7e9d1167c3676cd96f79965a066aca314089db60bdc40c2be4b69c569ec76b3bb74a43fe731bc869c9222ab5404304a513d4f7d2ec5af278f7c3d664fcde579bba7bd472bdc00a1eb4c46ff69fb7e45e5712919e8656a8887afa28cadd66461fc57f53d574c92105818a89f210d7e8aee6de2e78228b2cb03b850a6e77627f70f51bb919bddf61837a978dd4cec2db138c657214ac07b67134bd53b071e2bffa3608a0b0bac88b0ddcfc1ba4dea17191c9ad76ab8de72118893256a7e13e15a3bf98bb5757a78c58328cc4b380f3786f22c6be81884d213ec3cc2784583a47a4003a59ebea08bd06e290a892c937448e664dac672942b068b839593c442f6e1d22875e01859cd24c17d108696a3196ea4794ddfdf25721d3dd3e754d1ea884e5086479819452991403a39014297fcc734e56f8daae4d49d5c47016fc3ead550783df895542229ff3b034b5b722ae2a2b04ba70e42c174e9ddb89ffa60024aa16f297ac9383b2ccad53de4bbe4ea2fa3fe3d059d16b4b4fe9959ba3c4e58922e7fa2673f50be5b636ee7c79b445471ddf5b851ec3ac505980bb184c8fe44c7776ae9aab4e66ce31fe1bc00efced390a82f96b4866e31ba3ff832a25b1e1d00ec44bf525ae523b7102ba60c1d3a2e2bed004524afc90a064b325a258eb36315b1496c748f5407e922914787acb8b47bdc495e521518e0637eac4b1b4fe1adede145181ec7ef038d48c473d6f296b349d7cf874d329c71f272883eb7e77ff303957e159fd417d5055d82687448950dd149e1074a1785518ebaf7ac167e07f1f559893a20d133b59aa294efebdae1e19a30ec9a3e257203eb9a854096395825ef4d1e4ecf1f8daeadfa049ea6c435c50d67fd21c6f6b11a8be46502f0dda1715f5349df5330454316498660b7996432e679c73f1af33e529ac669496bde538890cc093122842e3e2e4bff937708dd4b1b1d3fc066a63824266461e4af9245032d690aac0ea5636c29606473820ee57b112e2bd68c0ce1936b7e76a7873cad678b26b560d7bb10a7dcad3f69bbf226faf2f572c105741a121fa1c55ff30b2d0b7339ed9aa4c9a3671e6e4b572800afcbc8764b16f0a61c4c1ff24c3b64992cd84f39d1a4d5532a7dbd9f7bc847258a33c509a945e53236cbc46b61fc6fad662c523eef0c1eaa4bc0a49610c8d09659e7bdfa858d2494dc3da0a54fcce229951d366fd17f4120f27ac77e5e6b777693641a853eacec09cc4dc08ff6ba22295acec61c5e6215eaf2a3a012461eaade8faa9cba630c5ce2bee6f1a4676d54b4a38b7b5cfb6c98106a4882ed88153a4f0bad3e0f3d04dc1ae5318e3b8f4ab1d122a548eed47f70edad1a164a9c5c3eb10fdecb24b0b68005b2e958980481834c4f673478d3f47d07836d3c1c513dd920042381f70f1a68671acee2fdd453a7552eba497af27127999a13a33104f0086390e01635d1a0b79d92dd43211c74047804e82d9ab26f97ee88e664871dab52a2a79443e39f06a6e8ac9d5e986252529b389d9ed0b2f55fb16ca65f6e90cc9a149065f499630f973996c1e2b6c53f2ab391b7d78cc6926b1684d066a3a74b86b3b633baaf3730acd28deaf18fb926e1ec9c1f8a2345103cc4cbec05345db57c5adcf062412f289607f5fa41194f69bc2f426a30c7a6f8d1027ee8dc96c9957e90fbd9b16475b82dfd8698195159bd7b4860004beb1fa85e6843eca1acbbb0b8c7ec0b865ed108e297a2d5f915304167e18d01e51497e6e3ea76ae99bcb849f7595fa74c2a6263e2bef65f1063bce05483980ed51eac5289307117f17e99d761337e9b1fb625a1b900e6179f3b02de57a0b5f52352298c8a2d2c816182ec169d2b9c0490097ad98e2edc99c6df683a4b5b6eb73ccee0aaf07e8cf8f2f632381ac407c5c578bc1c5a8d0915dc231b01b92dbd25c2bfd412995780582793736572f1e23ef690bfe6872c2572285cd737a4be91f4dcafef09232de77b315d73f5beb23d03625e031d2438081222b063c343f52565ae314ac47a4fe518b45d0c12f2ceabc5e05c20f607b97035afbe0e29249e47961d9cf9b385c065966b0c7ea91cfa9ed1b55a58b9aaa9de080ca05c6405fdf15bcef74177226eb225a47d532bcbc82a5ffed7fd86c2609b146d86f566d0b84f638d46d6eb696bfbbc62c4fc981a94c1d6ccb9f3f7ed7976ea7e8ff1d2a2d79986fb27f1401f25d5a83f64844fa9e839fc8855007b417b261d325b6e7cb124b27ede8ad18d2b6da8bfc4d4f50c3960d5a1c82e4557b16d05471602d2a31462e4bac9535c9a57389ae0613a674815c2ec10c19f529c9274896dfe49ab06889da517d482145ed8f57ba4b7c0434ce24090ef2459682a4f6342ecc382b4cd3409c3415bcb7f1bbaadfb7ec308eea8b6cb2912469b707c99a55c1754db0650616754735b85a41433a30b28e3946754f90caeb03c7579fc9982e6ec5501d6f23e0f2b6392acc435907d79ea11eb6955723a81c4f02bfc78e2eeb1d0408f8f06b4d2f6d20d90f7698c4e58bcfa993884424f8fcb602ef35d23737fb6aff220927e28c19043ae708fd9755256a8a1660d9c5827bab1b836a10aa23aea9c92fa3b25428b3791c5d25f3f1b63befd5480ac4192c966350edceea8938ecc608e0f063d16d427049ad62625f5177470e7a0d811e8d4273aea8f7377d51db07fc34d9f18497a0c2b5c0bc5e8778e06bf7460f0487eed54d661d74346eeada9090957159b86f8b68183e33d0c3fc134d87e068badd8789d4c7adb829fe08e4558bada5ef3f526afb2c7b6184244af0d07aa5cb525c519ed32298bb6241d900ead0532b0b1fc77a6577963e7a44627ed326741af254ab957ca0298a74323d2ee4f1bca70e20ff796491424e108e03c20f2eed7374c0aa2474a91f3ced6f46165c886a510734d606ceaa08822bfced69def33cea3662512fb42ecefee341d1b499b826ad882542374b032e907a7e6a4dddc4620a5d1002b5aee25711fd2dd6e9d4e90ee350f2889d6c1f4328e4b711fc919ef3c655311637b83b4eff39c157e0510807ec61714b843bc9eb22a0f4dac7e5cc07b8e9ed587b701d9aca2a239e76ac9a16338b74d50578956e06b1ac35ee3b822ca779922d89de7d915afd7d80831e8534b8f8a2eaed252fd862abc99aadde62d4520d9a7c3c3da86081fc36927de60e3479096a2b5025b9a789da01da969cfb0ab2f252c82db9e6663dce3888146b365080f649cf94f991312817147d8f0d1774d8d44ba4afd846060df2de1d1043659c3b94b1eff51fff84e5a81a0c635aedcf677285e0d722e3335449fd0f49a41264fb963ea5bba31dae469c789047812071d8853291fd8003cc31a8968ce7acb68a6e0172ba6ee0e9dedbebeb62143047336c5a91c77085afb01fc075938b306d7e36383ecdfda55b9b5dfdab53aa34000289c398f617a146c4a06404737600484d8d4ea960061ec2cb575dc485f65f275540d0ce7550da08417632b6f0f7d044f6f719ff839aa3e5c9db94d45225a1cf0bdb0c5bffa781572ad605ad37aa988240858c9493dee9f00ed281e93532d89aba5e9e59ec430cdd5edfdfc2ef65e094eeab71cc40b59c997943a0e0dbbc80f1e11834bf3b53153ba1c1f0ccf63b3c802439b2ef1430be6994300d9b2efe4b84e25bd3bf8a566d4851e7fff57cada544d722438e8980a31563ef0558fdd8db9bdd6f1a3e34f06104b680f63c1f80a08ec6ed74bca69bb1023fe63d24c7e7a14ce85db6e21173f2ddf14f233f3787a37e4b347e4d64907fc0a23c3da017c81c27df9fafd4695886d0ddec8c47982912eceef886ab5680a130bfacbf3c67bb4f0cc118274bdfed43bbc2ba56f048d6a390e48932469b30ac84fdfc2e812f32d00a85349bb22f2d8091e64282fca1b40811db756059de5d03861d6a22cfc6289097d23c26c5e3f000f9b34a0e1b28a1269d8673d09107b29ccaa1adc8939bdca312c69ae4a238f45410d8f1b27392d594ceea2a6b42899ee5c5857965b29bea1bc413da618899b1894f2adff3b3a7b05a626e50e42379f5d0e0a148ded33d815f59d1401b197a85656466eaf88ed30d1ad4a87985570291efbb3a2c6f22c0b111e65c843ca3c6179e94335f0f91d4696e1a31107948a042f55f264c32a35e719668483957c9c8e13fd01e5f751870a509f5f06ba41ad63cbd5f706f25b1e598f6c9709ee6bab627211bc38494962e930779ed4ea2a8471d309c4c4f0603238959cb13476b673489696c87ad9da5fef0d6467145a77ae0b1089c8626988278a85be3292680d9d7e4c6866f19b78595d611f15f9a5e37b3d145d5aff4a5b58a3286bd25a862904817afe8e9b9105584af15f54554ca5e7dceaa0fbd1111aae126d74f68bb6f0ce98094dc9a59a31d9526729efa171beda9ac5b7db9118aa94b9b5ad58dc20ae1c328e31269244d636139
+Ciphertext = d248b9e47c303f735b0d29f6111a742d93509ae051466688d56b587104a74fab1b259da64475fc0d2c3e28d87ca4edfeaa5715c23dc0e5281eb0c0c14e22182bb02f9f7d3c24555cd6a3ff766c774e67730a920db5f85d47dc23bbbee460f0922cd7ddba81ccbe727b4b489e79a19db2d012dad2a732273dafabc0fbded3c47dbe5b6b585570c39eb62850dc47f4aa0c29bf5fadf334041fdd4658fa6cc29a81192a53dcf47c03ddca9d03b33b06e5b3808be77925b7e7d8cf51fa939e023161d969f92430917d73f3aa10b83d5b7402410280561a27c376ce0b5151a51be2ef4eb9057eed25a0715436233615dcad1559fdbd81042544441857cdf46d72f5f50ee552cfd3bf166c530e57fd97f34e2e71bff8a90b30b4c4cc3e843b0f06e4eb2ff82675e428f5303aa9141dbeb615cf6aca5540fd7cb756fe5f9b08a4abdc6eb90b2eaef51c21eb9ae79a0e44b0755b3ed48f5e6e57f3148ce02501528dd3dd2b0bbec2650710a183e38510990002ce6498dc5ce7bf33d699dd18b66c0f8031d958b11d678674c355a635f4b5e8d863785f5dc2f99eba9ce74595493c017697344b651dcc2a0b1d5386b73abd8bb2dc77a2d92173d3688d0d704da9e44a6385af9fb3a81db68822b1eac9ab284f0155c20f6bc34af85d8518d0dfd32fdaece1379abca339a00e1326b624b3e4050be5db8dced5e6c4b88b82b6ee2a48c373d236ea3565ecc072e953ffe01b624c6ecbf534678aad9c3f8a07d7dd7232134b6b397d0c96ab5f795f9e3af65b96e7a765283d8081dab9f953113abe06e8d150bf9a8416d8932fac17b032dc346be43736dbf066ed239328803510f6f62bc8abc92f6df9a82c02cbf85de91739bc8d7805d392341be99798079419540dc952fa0d3ceca4b806ab1db3b717f0d720038343465a8bc0da8e8964e58634e8a2d6c99230af2ac7c89acd3f86a22075dc40818028f3c632b36a39c0e064e3ca2a078c617a3e73aaea56ef11114f9efaac90a3ec8f8d9b18921a80d74b09ada83efee127f41179dc6c19c7965f3e7f43e22f636534b123e9246172f9920f253d2a2652a5e8c337ff93b2d479bef5e96e972a9b9cd8af057c750bd711010d59ce065ad50fdd487b5dde616301d0ae6373b6f9efae99d8972f242dd7a6bc61caee70201869be202fd384a992478dfc133b84171f013244c5d17585934aed3b43b818926246227d255bf832ff481f5f8d074ab159a11d6d17ed0ac50f727b870db966e0373bd3b1eecbf9ed66aa66caf33ac57cffe4ac6df3cf7b0e54ac54be4f3d50f61b33557c2990c908a710c85000ef6fa62716960daf918ae3d81ee60b3813e65673bd911ce468510bd230b9c2d215afe86ec12e49e0ae87e4235baf3df237188f5e0af2e61c22a4bf77190dd5dc804b4cc330b360c3dc093ef208c37d299ea0cd2ba906084011e16ac5f4fc9646538d5b538a99546d34a4599c8529c1524fc4b394d6a9cd762855905233ed92e72c8b538372ffe2f0df7085eb074616c7e695d7de40779e384d5fdb49fe02385424ea991dc05c6ae813f76c673eb45d6105bcdcfdbf04dcdd20caa6e30efcf3537bcf72947e1ac37d1e8c600ba9238569a4b3afa590d61acceb2572da85885146a142c8f8c60afe4d53ee4d61f33c47e5a99da9a346bcfbd013754ef39a4d7f16c4c5fbfa53d7f180c16e2b64f97dcfd65349939b5fc167c7a78926f638f1893fe9a81e897beea3258a4175d14f41dc123ddd846e45a87f35154db8a5ac27c7a0fc95d3b3113cfa9e7c828f83a1f0d91ab7789c33be5f55ecbb8eb0c81bcc0fccc880011b21000e2f10773388b198ce79c5d694472d3ef6b2e55c342b29c70e4f33fe59e2e0bd3f9ef617733dd3329a0e426338d9c007bcdd382522cb96e59b223825a39b01b52809f5e8518f64b81c99022d8215b5c435d87cc1a57bd440b31a19b197b277b2072968595ccd64c135ae1b218046e27a7f2685d013ce3173efd07586dc72a28ac4792e804d44f9efd785ef005213df928560a20daa4c24ab07f081479270a0dcee3c26331c48a164e4b9d79a7c30c77ab06b00e9b72c190d35fb873bc095d5e6231a89b52a0737a99532079bcc72ee221b48f0d0d9ba9105f981beb4225f6efc1230d6da10fd2b58a65112a98e4bbbe1accd6e8589eb6d9c771bb911cccf42aa6cbc68d1976f0da7eff1e70277e8c5f83734ec1efb2b00708fef08e986bd6519a0fa4b5772e585ac8e37fd2a2af07aa382579498b3b75863fe792461492b8e71c4a1a2f4421705696a96601317cfff1632784b5d75fc2036ed3fa650354620781b9fcfd53f1927223fa045edf4abe7b2144512f3e3aee99f7ac3e46028bc2427aeb18e9cb40db57b696ea884658abc9b7bae0d8117f93074a3ef903528f8b55c7687cf9f0119a1f246cc9e993219c6384359e7e5e639bb294b264048060224ae168d7b9f1f795c07eaafcddb10b61ac2be3ab3e1fddf75c1f47559f38d24f0c773d0e8bc5fa85d7d33e3aa8d0f15583b8c1e7aab6f5d0e085b7175678bf11cfee8eb069b78220377819e3f4d28eb833d3d21efff543d5c6357fffb4a8fdd6ce399fca42e2d71c53c50f6b20bcbaa1650b57ff483837c39a37d5e978393c332b43021508b8ef27773164d69d0af3c0dfdc125cf30a7c49a7d8e5320d68a35e80cdfd62a0b7ce6a412f08c8062e35265fad5d1f226d590e9b068d09e48772711d7dbd786a38c0325b3d5665c2ff45ad0a20c174dc5739896ac727b34f11c7af299d36d30c69bbdc35770138cf891cfdd8123489fdef2dfaffa9c2548ebd60b0f0bcedff44691979b4e92b364753120364dc2e3b895095da828e8659575a85cca587ba05ca625480f977a6fe10181ab6ce005defbcd8894f8c71811909cd6b56eb7ffe327f46793a9e98bd7fe8951400276bb9c7607f8ba1e633034b73d7f0d040197c3f346394eba68c8accccefe05f59cb7ea9ab1ae2e172d8f466ee21c6531cec2c9dfeebc477a6d98195c28bccc1d5e23ae50e3a1ddd7de189e36ffe0e387df7be43427b194b16e18b42eacd517bba78edc9f56a2c7e89e6f13513718869da7c8c529bc337217a69e14e35cf97ff7db2c23700347f0a33ad25a299fc52b35f63949735ad864aa127053797541864b07168f89ffb7ba5c9a8bfbcb4248383a95f45461a7aee9c658c5679205f47144ba4a06175e746037b8cb6556f06405e0d537d0f2bcd898dd5fb987d96dbce33001a50abff5b9cb0161dbfe30f5df5a161ddd8a750b0cb33898c110415881fc81239f2e25440bca41a5bc46fbd3787e6c8fe8a463415cd9a82be368a02566da740dca8e40e686e1213d9c15de2d3556a1e1180b298ba3074b4ab93e469dd9a39ac0c8a173b04a5ad913e72e4d7b5ff520f108e1a1747c11b6b2fcfaa89b3ef7e669f8ad9620364b4f4f0f9ab274e76bdd631df033357a24723653e427324d907a9eceb3c375c43ee36cdeb046a6374be19ab04922da93d4dc07c5914df06fee97dd813f5fd501ca75e3c5ad53574837f2e51ba6a257134e8ee0f4127c59840ba8b1bb13592dcbe47aea50e453c7837e91bb12ad1c74fd0f149479bc0334c511a822145690a3a408caa32671ed05c2dd219ea360c67727c1fe6a6cd842301761e94bedc73f93de7091b8b6d2783a788313b2fa12595904bf5d1167a5ddc4ee151b1522de60b7293b72a62c4d08b396ed682b6a6262a212ddc8c70dbec1a972cedc09f593e21d843279561884f9759a593da7b17a147db7559f19d5d6f43ea98012872f974306037dc0d344c55403b35a5903f766359341bee5bccb696fc0fd1c7aa8803e4c2f9e6e23d386d3a202027c5792e355592efab9330af330392a7c91e3cacc4e645359edafd78b77829374cd4b644817322b7650696fa763a0cc7143f9ec7e2f6ab3c9ec2443b0c0b0a31e9eeafb7bb8c375232357f08256959a10a6d4bc98d6cd9314a2ce7feaa8c0eb1eeb15047f715d6ae9ebd64238d648ed6bc50617a360d8ff9a01aa0ce0e29338d34bb9612751445372ac6d74837c7d2d67729760216ee33476cce1a154086ec31d986cc5a14e86561c6929554fb280646164bb03e8e52588a1b947960a77d61c2d2499212a742e1a5b78805b5b64fed141d3c4834301b8a8bef31ce65edb539fd9469b590a6980d0d1bd29e34a09f87438059a09b1ea234d1bb29882e67599fc1e417db9d86332077cfb05fe440ad1243e26a67a0ea30e63cdee8850a543d76e810140547412fb1400ac87a10e3bc77d3918750a5cc3e7a0efbd736c7ed4139cd5855ddba47143362bf40b91fcbf27222017c1552360466483e67ed125745724cc713c713dcf7ef6ea3081d65d8d78b903382717848bee7410431e1040ec92373f75a1bf229816f55dcfffb6e6da33ed8e1e8b05f9348cdcd6938f053eb9f93e0de639e922627bf61a6688f9649bb9cdfce6236a176db8b9b53ce4b5f9eb9c0680c92128bd327aa7f04a745025faaf117a18d5664027ab0e3f5898b834e1a75cd4b4087637733416f8bac1ccd67cb4457005945676d03f76fd0453fdb9968643fec98d28da7c8cd7070a803b14a2459f073ea075fd023a896d3306fdabc54416e95907103cd2fb642e301c71cc48e8eabedaae356582761a14e0b3b0ef1de06002c2acf594c85820ae3a094e5b4680566b592221543c1dc5192d6b208e86b5aca91d4e3454564eedb3b8208169ce97e1632b864f1d9d4c4c4c0fd4bcc5206e8f6d64c7cdf212d718cb5b7c7ee21593ada3f33f5952e12bba4f46cb99044978fe75349c6ca735db35891351d7e5f02a93354bc45a9ec756453f053cb87430b3e9211807f81ad99b6fceb8ef1b2d655910e1f5fd22f2ee90e42abab230f8f39a8345eed6ad294a0d32416a253f829093ecae209bc1dbfadae04a373080f9ea8394a28ddfe1134309bb53ae571d2019ff2bd4be94f8176d90987fcebad323f0b2921b85b2610852973f383a2ff4a5fa82a77b13cfd50a33f29164a9ff409422cc4cbd772132856cbd08470b220ace957a6b8e02c8003d750539a38a8df19a5b662907b72e3098d77c2fc3ece0693b47ff19ce911a93b6adce75653d48ace6af10b8f1141437f9206658707b16794e349db3f1a02606ea167d0213ce3644f64ced64de3799b1729210fc31ba1811b0c226306f2466b230ae35e6d8fa11c8f932e27da8cb1bd311919bf9178ef08bb7a2b4ca2d2e6e9585ee9f916991cfcd4862f5de9fbbc63bee6edbdcfcec9173a252eb59fc6d6e58258ca8b2a4475acfc1e09a0c9566d23d92e9ada97de51895bfb0867c42025c8d089c65bba67f4dd84d7c5155a930329345cdf3b1d6e910e730df273e183190beb900344bbce8c3bdb13a7e4ecbe967a61d47921aa55bac2bbb24e3e03d386ddbfafb3b32235b5ed922ed6ac2c89ded1316b69079b826507d708a6cca14ce2244a67be90fb91ddcb0c97432703729bceb432bc856f5eb9d2f169800a04283b080f0e053670a21468df9414fda9f4153eaf1669a19ede7925f832280800f0063ceee34b9d3b0f8da2012525fa7927e76bda71954714d5f51405b920391eca2ad71160acef4091878b907974573b4cf1b377baca0340ab0e4ec546fcaa6130603ad633c3ef980e88d8f44ec5de743cdc6cd9e0e4cbdb97a5c076be9ada8f26bc54d711facec16a2401292cc167bb98cdd320ec9321414bd97498f6d9b54dbb45ffe4b3e3f88260657ee23e19de48a93595c8e3a289a02d76a27ceead05d591633464709aca117c26aa49b64667f2a3b6371984f813d7098fae7a6ba1841775b52314a06c80b4c994ef8100e233ab3115ba2c39b97f2d5082a145720ad0b12b8a7cb275ba848b3fae14fc0c82bf0353195c056b302e508982f73a8519cca722892482b9d9e6a58bfb4d862fa393eabe6aedeae1be5ed772ea3c94a0df1d9684a131c35246c68b32e46aaf89f3649e58b2e99bd6bb3923d3ab43cbf73b6b3d19fe3b62bef178f46c79ba85e23ee4b25bc561e8fa97f51605bc0b210b02aa28242e81dae9489076d259f17d25b93b0e8a2010584d907314e3bd55482f0fa43d37ae9535629d28d6f837360bb35ec869d2a959789dc49b9c8c515942a1e03650566b736551a5180a60279bdb0ff9c387beebeb9e59ed930b3746464a010a6f7ef1de3c7d76fc6899b1e5ed98213813ffb333d969ad72fd8537ef4e12ca7b78d35c24f44ac82da4a7116492ca2efd86ee6a4474014e72a5cfeee7f729b77cfdd1a5d10a03f3cf28f1d314fca36d31ef2ecb3cfccecbcdfd22367b0a0e04435654286ae3d4fee13f56bb7cdab40b4e1dd01f9ef857f94a67c1e237e24819949935ff3bd73b0461ee9020fd0a2db2cc6312ace97e4a8a33c295271453a12822db8d1438f22ed0d466150990dcb39ed042424eef7a1210c83224c856923e3251484a81a15cddb4d7ada8bb7968dcc8f85e39ca99ece8ce2ed7753fcee6900cc9b7b5691f2d67ef9be13f70d195bbd0047908025df01b4f4d581fd59239836578627d9d585ebe9b053d807e9d3ba25405029a148938a746636decdade02b1afb5ccbf2f0e14a27c98a1e130d9208bbf7da4bb4e572927eb348568921d4a3309a2c24f367c935c2a8e1524c3024ff350ac7da8d2849586817bc9d46a08a21aef035a6151e608ed93b1556a484e455819f9ac2fb155020738962e7255a82a0854b31fe20cdd351c10a33eb693c9be1a51a932e04d0364ced41ee1bf800d0c12ab5eb37fe52563666e52827720e856d4f24eb06e0aba446910aabbe36513f2274362fedba4c19398433029495284ccb499bb559a9cdbc94a0d1b733136969a743945a04e1d2d4e77fed21550af35f22651c7de802eab7a3942d7ec55a3a5002bde8d5cccc1d4ac4bb7f4926615fcece543fe5d9092d2c4f50d94fd9868775a072f4a5bcf2e5fd10795f7f172a3341ce33505ba68e7ebedc9c1e9165864244ed31bbe5c308dceff858cc42010ad8c281a24689cf2dee8a549b1abab9981d70a912174944b403ce664d8608b2f723150f5c12164e4caf28676e7a25c3928ca2a4dbe96355ef8f282e57888d40715df07bd8b5895549ad957e758abf868def1c1f5e260d26498616e2ac962bcaa33b879874569f198a91ce4e50fc50da77fea1df9f9ea900c834dcdd462d338efcf8e612aedebf254fac596507d175d30a90543627cfcef6852c7cda8b430e255c4d6d417de31eb5dba123e3ce9e2269867d9a94fdcd8ccac40a9451953085109f5ae0c3e04daadb4a2a47b0e176917660eb3c9f1aae0ec6b00635fa387e056623947c0621f0a12e86fac1881ed1dc1b9f523388d6b6596a152b3e732c561972879dcd3f0232ef0773a4fb195a90c3186c4688ea58967ce7f18386b80bd38e90cfd4cb899337ab27cba8db6523e979b4c449645bb2f320ccd28578bc7ec38f47225273fa61a2e5df97c4d76c556fbe2b0fd30e615f5fc82c3de7194caed9f5946c151c22b7a0c48f4a7cf78aa153414f2913c5eb95e3dbcea7ca544272cd13a1c52fa87759aeb430aab144fab418c835344605df3a044825965ca15de6ba0e59b2080f5844b2d110d71587e19acf14264cec2de5b8c77d18893215d1c1da0a940e7c2ee429a99e2633c216aecb7675a2314a09044951ca5a8eac798f8878fb5ea65f4ddccac53ee0c786e597169079fb6e8ceb37a71580b0904a97450909ca454a690821e249aebb75449e582fe1b30f1fa9f6464bdef654daa5ede6d4f223f4589ea25a25f4672cfbe974d51008bce296628556f55d26646e40b59f40e3149273760b40806ace3b5171e0b79865c6adb53513da2f24c4115de243150cec76107b48ca8da19117f00b5870e67eb8357e43c1b7b593c9875795d46ede26a109e05406b69fda988947e49ab195f22454c3c743c2ec51b91370b4df8d38653b353e51bb83215d122bcfa591009c007bbb6124bc590fed3f9c5699180b3b1424ad02f7c90a149b77d22dea5c996aba675c2a1a20e206d9c25d9446247d495a26486c0d0bfb09d0b5a1a177a09fa749dc36cee73af0116a6b779c2b827512a04ff0f60b483edbcdb33d2a18339463c498ae67ffa9da0aa3f3beb6bc99212f9e6961afde89045520b1f3f2e2761666a333d76030f443f53322f099035584a60978ef8b49f46d7d4d8c5c758ea52a04b59c1a3a1c2f9df3f3b6f5c45cf4b3547043b18c1d615a2c965c3918d090cc72946e8fd0b938e60e03464f4bc71fb719a1d173b0931930e58bf7f6d4403971d36b40f83be6b57244a7029e1d41dc908764d57a5442557218b509faeda4e9fcf31debbc54ae671ef636871233f29e0013c0e33933543f4b59df1978ec89b109c3977b0cf938b7f6166d6c93be5e87684a703c8b7b5fe1a8bfe153a179b55575ff05e599b39e32ed10d958699a1ffe07136081f0719b18c69dc74f66f211103e9c544f3c81a88ba9f66a9bc7017d9ca9e2cd97634052694a598476b99daf1cdfb6122869375ca5873d32d5c1e07d9b5b380b4f09dbe04478cfb1a13853eafacfed70c8abcd444ed095f78d07c0e8b4093be95c3aa24b2e5b6bfe3a06e9d2d9fedfcfeac4cea2490627e6da6a5cca383351952f654ce2b0ad359c0f7f4ad3f8d1d4a030a947d4a2e417bb79102729115cc8b6558c3362b1d805fb48ce4858deff97677e60375ed13e150a12ee7dcc8ccc64d9710c7f516555c1f7a1a08f0d7c6fd21f864fcf28c8f748c40494e01fc32006f977a5100577f86a484d11b82c90cfe6b4d6b1902fef486cc6f3e033904e150e67283e49a5382961dabd244412ca9657b48796e476a82443167e277d5a65c0c563a6abca77d316e5d3ab639a1ecfb1110af2d29f146508bd9874486dbb56328d6f59479e2766692821660462aa60b6bc8a710707ceeb0ea6429e5113e03c9f41ce0d69c7589deb547527673e8a9f9a9a74e9e4bbcabf2e306b35504c1da99730ae86e94cd047b2e6ea5e97e63a492430d37ec446434fb3b066adde08b17d7d903ad194a4a863d6cfe181a45c8c97b5062bf7c4e44d69c0d1a7e1f5029b805b7c21d1b5e56e697999a32557870ebaae8d87dcb5ca5eea2c5547a16b3f30ef9df8df821028c106f86e091050ff8b6ea4171e59dc2592d405073bea53f8ea62edf112dfbc7ca69809db8005783d63557d3d90d123a944be395c1dc3b5e1476dff188346327769fea65f3cf9363e88ed67335870ec8ef13eb9d9ff5317c4e24dfce9d11699e5f47b4233cc8f9d1b915e716a5730a5898ee65d30b1628b484a5e82eda95a590964a8d8bc89dd3c5cf6c4f9137b8c6ee9d6a692e0c0d1d858dd5b3c12de48badade4d01bff312c56ce3ddb34b0fdde3b0c2706fc292b9fac7e1a0dcd0b6534c968117f7de15eba84d2754e4bcb8093a5440297605598659f686075e2b1b464b6b3ec68abb13cde263b1c607545c45746338b9b207b5c381da690f653b35e363e1249551ad938b9fd7b0a944151cda07127bf9ba76958e926472f4aa1de8512ce834cfcae5414b226f23acdb1fe5cf685d2201b78167ad35fc1da282744c2a43cc49d49242f968f7e06de14455e7ef5adedc5b33184346018114e2d1fc7a5349e378da9b2af5b328c213888652aca9f1145363809eca7c1fd8e64a5cc3255418736e048a731f3053db77971f67014e6121a8e464833e5dbd02ea6caf385e43e9f378bfba657986bf852b32adb55e35a2675bfc8d70d43a902032a61f59f57dad2dd7d7963322136233200cb9a90c952074e9ba0fc0654f1b6fd6f7f0eb77c0fa6d8143213ce6e8b0c178f73e17a7c64839f9bebca2fc955ea8ae406a13b80a9045fa8d129fd859faa46fd27c48bde7b890f98ee938c0d78889f84181ae2f5711304fe554d4251bbc6437ced59d577a2a1f26da736193c3674adb13cef9f4cb4aa6585c4d6874b0309ecde300493b1642c595746f09e03977c8902f3a4a877db1153b248f295a0ca2f1e437d15fcab8fd77c5f967304efb5c4920b990674ae61b954af40be17a8559dc377c591b68067fdcaf2d27bd9a22041b981a84be3de50d5962b58f8c4a22fa05192c5ac99a0a9423284fe62a3a59f085136cec72cda2a53af106a2eb5bda28b6e02c299118cd91714c2e7d045346c78d9ed1b41c73231a21e42c298949f70122277f4134ed5c56639edbf3c3e717310e3d1f03dc5a94e64c4ce148bc5c6bde64eb80b17d5979892786a31225eb89bf9f5a582bcf65b83ff7aa361ccd9238d144f6a22a3f77dd8a01382df4ee90a2057dd310a6b0c4b81dfc92a2cc0c606d3be8b18fbe64ddfdf2004eeabea892be2f914edd1edd8e8829dc7704d71bbaaf08c41824dd0f4b34c9eedead9e10e53bfc6fc0bd37417de0c5c71cff0754d672f29c262d8e27b524427e12bc4e4705ab311d3bedcb1ddd09a3ca0c268c05c64951b7d724a9dafe4d249aaabda91d68633aaab845bf78f9a22d467c7e0c5fc70fc9a318b01d7492efea7fffd329d70692e76647ae665c62b280da0d62f870a52e4dc4cd92c9150c96aab16f8c23475e3152d4debb41b6756f000c3d8aceef18b49e295be7a71da1eeadf4eb96509d45d7cc42af4b7013d8bb445f577e8d4cff92770b8ba0e451f3e24c6d981efdb68c7f2dfafee40b8a425955796e369f0d4da3e998c1626ae0fa583334475f1fdde68ca211c3f2e9afb003f553191702e11f8b731c89ea26059ea4466f2bd0a1a5601025ca9417006bca5c9a57dfdba44c603ef9ad38922623b40feda036d84425c47fa42973e348a180a7570e1215044c375313ab08d6f521052dda415707ebb74d6c4774e039bb04cadc2799224bde1802e2ee2a018032e3a341700c0fa2aa28bf93cc479231efe7da0e9f68e572415348c08cf648117e9b6d1267fef6617f5927252c86cc087775db3e30180feb5ce7e1ac9c3761161e07a4853aa6d97e525aa88302954cf9390fde81f8e11d97a11c79e3bad261364c18890dd1f8fc71127edefe3571518a42be611a46a0426a33221aa25a0ae6514daaf96038cb59aaba898de49e3b215a4464e0af614e638c2d9b6e676ec427fc906bc516331a18121f306a5246d179e2d3d0f38ab8393f7ea5a2d24585e7cca649637b9983924a15483c167e8780f8dd7aa1154cbf731745a8d8d54a8c4f8d854371bb8172303f9ba3c8c7cfe8c378ee56bc35c6376aafe907d3294ee9a8786281b7deff78ff125761f1a31d0e8fffe04a52a7574eeb8679670ca3bfb740167a559488d4337819613d32752d8a89013622f6a8d70f3c64b84a4215f4b7bb282a2d17c36a326167e3270757b8f1d9a0137bfc5ec278e8ca35a69e49779cfc25b95a89cc18732b5b9d1986b18878c57e118506909207207ad0b4edf32fb2b35b6e70546f45d0849bd139ffff9d8ae547787e7b51403b54f110e2ac65468cd0910d80a4e321deafd46e9af19609bee1efa41b762b8ace989dd681503539e7d9948664cf7a73ffac9ce2a34b514253c4f21bbccd38057a6d68732930dcdfc9a32219b53339d100db0037a8bbd101e71f5054f3
+AAD = 7b3b9c07148fcd897f657ecfcc87e530191536b8e77f9309e8d7323888b3b21477f2ab7c885c105d9c29ac96aed23b366f9fde4177401b7038c6770c7bd2ee8b4335105cc0eab9e367f0cea90d6f1ae3fa76cd21ceb9f3500ce7fb4b2a3f9e90f900a231ec693aeced7afb6821391d1f5b1b957895777aa7a2b71d9571c00336f26d54d756392cdb74bfb67d5a621d517db20441f74d0940180baf613b09452f64224f8af7bbc864ab4a8434ff624d0c0646ee07132fd376506951899bde975df8c836ab4ed9cc084f1f6d500ad56345d2f250a0d6991b9e458c62b6023191f341c8659e8a38c878cfac12b032674503df9c9bb01c4340c709eb6dd7c74907d769a317f4dd7317843c47bdb4c5e1f07f2380d464b0c47269389cc8a43a09adba86f6aa8f44c8fe514e73b5fe8d344769c1aa20a4538ecfbf47562ca79fa497b0f02f103f75522db9ead50d56dbe86997d6085f1b5aa7a4cab9e51a1247ce4f724a14983b6bafd17369fac973c6be268e20d800de870928e100990ebb0d3bedfceda36c64be3a729b603bce677a49e8caf282c9159b6e3e1e775129bd30dc3f5c9849535d86a27474be03bb5749b4c0115e2614f8feaa7405cc69b1de479b3b57e551f876a9c8c57ab9879cc68bb2ea110b2e77e59dd6a65eaa67cc4d4b2f4d6e646b2a298d3c80fb43969275d4414734e74726145dab06124c040656c39a94846e8fd58d326f4f9eafe5b95d85254765a21993f55070fcb9e85db5d42ab6b9464ce66de3f236dd2a0a26c4e5535dbdcd6eb350209a65aee785c6647ad4103d092a8ac932470880eb314f7c98cdff34fdf35ee2d36f09bd443b5defad7a5acb9df55965421fd043def6f4771e1bb27385b30ba22c0d8972aead6b654085a7dd3b60c4004a0dae22e25100e54e0badd0cadf909799329ddff699de8066dd6c3822d80c73c52d87e6fcbdb2dbbf852e37804b1256e23e76dbe43f30be4a577bc23c7941a3d708d1e1f579e9c6eebc219c74768168f6790a41f883790e08cd1e88ad09a544eb97b3d1d5af67eea666b9c027e5c7c976921189b955a9e605f6cc9c012c1c2e197c5b02504cb9ffbcb0f3ed778d540d5194fdf5d38dba6340c93da7c5501a082689616f337d8b59c2a92c25e777515726e1d7f6cc9552693cc7c30f1294b37f97d49814250d6c1e3eb335c5d214ef3641739d508b87106eaaf367902433a148ca962ec694409acb82d7749e1c88938ad382d0ca6e6cbe8255746832fe737c3e71dae8397f260c98d4a292a126ec21935c24096d2f91ae114194af659455d8a4206197495a28474dd2809debf5f550d77ffac2b0db521559910c352f23472d7aa9f4dbbdb158f40aa36912cbd918ae4c642e76d78d57ade1075c4fe1086ddee3d554353b4693bbcef1cfa87e49890838c36156af0edf384b0413d6d7aa
+Tag = 51cbcf4a2fd82f221de1bfebf86a8c24
+
+# OFB tests from OpenSSL upstream.
+
+# OFB-AES128.Encrypt
+Cipher = AES-128-OFB
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+IV = 000102030405060708090A0B0C0D0E0F
+Operation = ENCRYPT
+Plaintext = 6BC1BEE22E409F96E93D7E117393172A
+Ciphertext = 3B3FD92EB72DAD20333449F8E83CFB4A
+
+Cipher = AES-128-OFB
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+IV = 50FE67CC996D32B6DA0937E99BAFEC60
+Operation = ENCRYPT
+Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
+Ciphertext = 7789508D16918F03F53C52DAC54ED825
+
+Cipher = AES-128-OFB
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+IV = D9A4DADA0892239F6B8B3D7680E15674
+Operation = ENCRYPT
+Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
+Ciphertext = 9740051E9C5FECF64344F7A82260EDCC
+
+Cipher = AES-128-OFB
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+IV = A78819583F0308E7A6BF36B1386ABF23
+Operation = ENCRYPT
+Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
+Ciphertext = 304C6528F659C77866A510D9C1D6AE5E
+
+# OFB-AES128.Decrypt
+Cipher = AES-128-OFB
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+IV = 000102030405060708090A0B0C0D0E0F
+Operation = DECRYPT
+Plaintext = 6BC1BEE22E409F96E93D7E117393172A
+Ciphertext = 3B3FD92EB72DAD20333449F8E83CFB4A
+
+Cipher = AES-128-OFB
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+IV = 50FE67CC996D32B6DA0937E99BAFEC60
+Operation = DECRYPT
+Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
+Ciphertext = 7789508D16918F03F53C52DAC54ED825
+
+Cipher = AES-128-OFB
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+IV = D9A4DADA0892239F6B8B3D7680E15674
+Operation = DECRYPT
+Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
+Ciphertext = 9740051E9C5FECF64344F7A82260EDCC
+
+Cipher = AES-128-OFB
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+IV = A78819583F0308E7A6BF36B1386ABF23
+Operation = DECRYPT
+Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
+Ciphertext = 304C6528F659C77866A510D9C1D6AE5E
+
+# OFB-AES256.Encrypt
+Cipher = AES-256-OFB
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+IV = 000102030405060708090A0B0C0D0E0F
+Operation = ENCRYPT
+Plaintext = 6BC1BEE22E409F96E93D7E117393172A
+Ciphertext = DC7E84BFDA79164B7ECD8486985D3860
+
+Cipher = AES-256-OFB
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+IV = B7BF3A5DF43989DD97F0FA97EBCE2F4A
+Operation = ENCRYPT
+Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
+Ciphertext = 4FEBDC6740D20B3AC88F6AD82A4FB08D
+
+Cipher = AES-256-OFB
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+IV = E1C656305ED1A7A6563805746FE03EDC
+Operation = ENCRYPT
+Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
+Ciphertext = 71AB47A086E86EEDF39D1C5BBA97C408
+
+Cipher = AES-256-OFB
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+IV = 41635BE625B48AFC1666DD42A09D96E7
+Operation = ENCRYPT
+Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
+Ciphertext = 0126141D67F37BE8538F5A8BE740E484
+
+
+# OFB-AES256.Decrypt
+Cipher = AES-256-OFB
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+IV = 000102030405060708090A0B0C0D0E0F
+Operation = DECRYPT
+Plaintext = 6BC1BEE22E409F96E93D7E117393172A
+Ciphertext = DC7E84BFDA79164B7ECD8486985D3860
+
+Cipher = AES-256-OFB
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+IV = B7BF3A5DF43989DD97F0FA97EBCE2F4A
+Operation = DECRYPT
+Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
+Ciphertext = 4FEBDC6740D20B3AC88F6AD82A4FB08D
+
+Cipher = AES-256-OFB
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+IV = E1C656305ED1A7A6563805746FE03EDC
+Operation = DECRYPT
+Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
+Ciphertext = 71AB47A086E86EEDF39D1C5BBA97C408
+
+Cipher = AES-256-OFB
+Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
+IV = 41635BE625B48AFC1666DD42A09D96E7
+Operation = DECRYPT
+Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
+Ciphertext = 0126141D67F37BE8538F5A8BE740E484
+
+
+# AES-192 CBC-mode test from upstream OpenSSL.
+Cipher = AES-192-CBC
+Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 6BC1BEE22E409F96E93D7E117393172A
+Ciphertext = 4F021DB243BC633D7178183A9FA071E8
+
+Cipher = AES-192-CBC
+Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
+IV = 4F021DB243BC633D7178183A9FA071E8
+Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
+Ciphertext = B4D9ADA9AD7DEDF4E5E738763F69145A
+
+Cipher = AES-192-CBC
+Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
+IV = B4D9ADA9AD7DEDF4E5E738763F69145A
+Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
+Ciphertext = 571B242012FB7AE07FA9BAAC3DF102E0
+
+Cipher = AES-192-CBC
+Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
+IV = 571B242012FB7AE07FA9BAAC3DF102E0
+Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
+Ciphertext = 08B0E27988598881D920A9E64F5615CD
+
+
+# AES-192-ECB tests from FIPS-197
+Cipher = AES-192-ECB
+Key = 000102030405060708090A0B0C0D0E0F1011121314151617
+Operation = ENCRYPT
+Plaintext = 00112233445566778899AABBCCDDEEFF
+Ciphertext = DDA97CA4864CDFE06EAF70A0EC0D7191
+
+
+# AES-192-ECB tests from NIST document SP800-38A
+Cipher = AES-192-ECB
+Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
+Plaintext = 6BC1BEE22E409F96E93D7E117393172A
+Ciphertext = BD334F1D6E45F25FF712A214571FA5CC
+
+Cipher = AES-192-ECB
+Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
+Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
+Ciphertext = 974104846D0AD3AD7734ECB3ECEE4EEF
+
+Cipher = AES-192-ECB
+Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
+Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
+Ciphertext = EF7AFD2270E2E60ADCE0BA2FACE6444E
+
+Cipher = AES-192-ECB
+Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
+Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
+Ciphertext = 9A4B41BA738D6C72FB16691603C18E0E
+
+# DES ECB tests
+
+Cipher = DES-ECB
+Key = 0000000000000000
+Plaintext = 0000000000000000
+Ciphertext = 8CA64DE9C1B123A7
+
+Cipher = DES-ECB
+Key = FFFFFFFFFFFFFFFF
+Plaintext = FFFFFFFFFFFFFFFF
+Ciphertext = 7359B2163E4EDC58
+
+Cipher = DES-ECB
+Key = 3000000000000000
+Plaintext = 1000000000000001
+Ciphertext = 958E6E627A05557B
+
+Cipher = DES-ECB
+Key = 1111111111111111
+Plaintext = 1111111111111111
+Ciphertext = F40379AB9E0EC533
+
+Cipher = DES-ECB
+Key = 0123456789ABCDEF
+Plaintext = 1111111111111111
+Ciphertext = 17668DFC7292532D
+
+Cipher = DES-ECB
+Key = 1111111111111111
+Plaintext = 0123456789ABCDEF
+Ciphertext = 8A5AE1F81AB8F2DD
+
+Cipher = DES-ECB
+Key = FEDCBA9876543210
+Plaintext = 0123456789ABCDEF
+Ciphertext = ED39D950FA74BCC4
diff --git a/crypto/cipher/tls_cbc.c b/crypto/cipher/tls_cbc.c
index e6aaabc8..fbc93fa6 100644
--- a/crypto/cipher/tls_cbc.c
+++ b/crypto/cipher/tls_cbc.c
@@ -54,10 +54,11 @@
#include <string.h>
#include <openssl/digest.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/sha.h>
#include "../internal.h"
+#include "internal.h"
/* TODO(davidben): unsigned should be size_t. The various constant_time
@@ -176,6 +177,45 @@ void EVP_tls_cbc_copy_mac(uint8_t *out, unsigned md_size,
* + md_size = 256 + 48 (since SHA-384 is the largest hash) = 304. */
assert(rotate_offset <= 304);
+ /* Below is an SMT-LIB2 verification that the Barrett reductions below are
+ * correct within this range:
+ *
+ * (define-fun barrett (
+ * (x (_ BitVec 32))
+ * (mul (_ BitVec 32))
+ * (shift (_ BitVec 32))
+ * (divisor (_ BitVec 32)) ) (_ BitVec 32)
+ * (let ((q (bvsub x (bvmul divisor (bvlshr (bvmul x mul) shift))) ))
+ * (ite (bvuge q divisor)
+ * (bvsub q divisor)
+ * q)))
+ *
+ * (declare-fun x () (_ BitVec 32))
+ *
+ * (assert (or
+ * (let (
+ * (divisor (_ bv20 32))
+ * (mul (_ bv25 32))
+ * (shift (_ bv9 32))
+ * (limit (_ bv853 32)))
+ *
+ * (and (bvule x limit) (not (= (bvurem x divisor)
+ * (barrett x mul shift divisor)))))
+ *
+ * (let (
+ * (divisor (_ bv48 32))
+ * (mul (_ bv10 32))
+ * (shift (_ bv9 32))
+ * (limit (_ bv768 32)))
+ *
+ * (and (bvule x limit) (not (= (bvurem x divisor)
+ * (barrett x mul shift divisor)))))
+ * ))
+ *
+ * (check-sat)
+ * (get-model)
+ */
+
if (md_size == 16) {
rotate_offset &= 15;
} else if (md_size == 20) {
diff --git a/crypto/cmac/cmac_test.cc b/crypto/cmac/cmac_test.cc
index 53f45d15..2496f2a9 100644
--- a/crypto/cmac/cmac_test.cc
+++ b/crypto/cmac/cmac_test.cc
@@ -44,7 +44,7 @@ static int test(const char *name, const uint8_t *key, size_t key_len,
}
ScopedCMAC_CTX ctx(CMAC_CTX_new());
- if (!CMAC_Init(ctx.get(), key, key_len, EVP_aes_128_cbc(), NULL)) {
+ if (!ctx || !CMAC_Init(ctx.get(), key, key_len, EVP_aes_128_cbc(), NULL)) {
fprintf(stderr, "%s: CMAC_Init failed.\n", name);
return 0;
}
diff --git a/crypto/conf/conf.c b/crypto/conf/conf.c
index 6bdcc4dc..e4fc428b 100644
--- a/crypto/conf/conf.c
+++ b/crypto/conf/conf.c
@@ -65,6 +65,7 @@
#include <openssl/mem.h>
#include "conf_def.h"
+#include "internal.h"
static uint32_t conf_value_hash(const CONF_VALUE *v) {
@@ -152,7 +153,7 @@ void NCONF_free(CONF *conf) {
OPENSSL_free(conf);
}
-CONF_VALUE *NCONF_new_section(const CONF *conf, const char *section) {
+static CONF_VALUE *NCONF_new_section(const CONF *conf, const char *section) {
STACK_OF(CONF_VALUE) *sk = NULL;
int ok = 0;
CONF_VALUE *v = NULL, *old_value;
diff --git a/crypto/cpu-aarch64-linux.c b/crypto/cpu-aarch64-linux.c
new file mode 100644
index 00000000..1b0f3955
--- /dev/null
+++ b/crypto/cpu-aarch64-linux.c
@@ -0,0 +1,61 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/cpu.h>
+
+#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP)
+
+#include <sys/auxv.h>
+
+#include <openssl/arm_arch.h>
+
+#include "internal.h"
+
+
+extern uint32_t OPENSSL_armcap_P;
+
+void OPENSSL_cpuid_setup(void) {
+ unsigned long hwcap = getauxval(AT_HWCAP);
+
+ /* See /usr/include/asm/hwcap.h on an aarch64 installation for the source of
+ * these values. */
+ static const unsigned long kNEON = 1 << 1;
+ static const unsigned long kAES = 1 << 3;
+ static const unsigned long kPMULL = 1 << 4;
+ static const unsigned long kSHA1 = 1 << 5;
+ static const unsigned long kSHA256 = 1 << 6;
+
+ if ((hwcap & kNEON) == 0) {
+ /* Matching OpenSSL, if NEON is missing, don't report other features
+ * either. */
+ return;
+ }
+
+ OPENSSL_armcap_P |= ARMV7_NEON;
+
+ if (hwcap & kAES) {
+ OPENSSL_armcap_P |= ARMV8_AES;
+ }
+ if (hwcap & kPMULL) {
+ OPENSSL_armcap_P |= ARMV8_PMULL;
+ }
+ if (hwcap & kSHA1) {
+ OPENSSL_armcap_P |= ARMV8_SHA1;
+ }
+ if (hwcap & kSHA256) {
+ OPENSSL_armcap_P |= ARMV8_SHA256;
+ }
+}
+
+#endif /* OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP */
diff --git a/crypto/cpu-arm-asm.S b/crypto/cpu-arm-asm.S
deleted file mode 100644
index faf3ad89..00000000
--- a/crypto/cpu-arm-asm.S
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (c) 2014, Google Inc.
-#
-# Permission to use, copy, modify, and/or distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-#if !defined(OPENSSL_NO_ASM) && defined(__arm__)
-
-.syntax unified
-.cpu cortex-a8
-.fpu neon
-.text
-.thumb
-.align 2
-.global CRYPTO_arm_neon_probe
-.hidden CRYPTO_arm_neon_probe
-.type CRYPTO_arm_neon_probe, %function
-.thumb_func
-CRYPTO_arm_neon_probe:
- vorr q1, q1, q1
- bx lr
-.section .note.GNU-stack,"",%progbits
-
-#endif /* !OPENSSL_NO_ASM && __arm__ */
diff --git a/crypto/cpu-arm-linux.c b/crypto/cpu-arm-linux.c
new file mode 100644
index 00000000..73c38ecc
--- /dev/null
+++ b/crypto/cpu-arm-linux.c
@@ -0,0 +1,360 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/cpu.h>
+
+#if defined(OPENSSL_ARM) && !defined(OPENSSL_STATIC_ARMCAP)
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <openssl/arm_arch.h>
+#include <openssl/buf.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+#define AT_HWCAP 16
+#define AT_HWCAP2 26
+
+#define HWCAP_NEON (1 << 12)
+
+/* See /usr/include/asm/hwcap.h on an ARM installation for the source of
+ * these values. */
+#define HWCAP2_AES (1 << 0)
+#define HWCAP2_PMULL (1 << 1)
+#define HWCAP2_SHA1 (1 << 2)
+#define HWCAP2_SHA2 (1 << 3)
+
+/* |getauxval| is not available on Android until API level 20. Link it as a weak
+ * symbol and use other methods as fallback. */
+unsigned long getauxval(unsigned long type) __attribute__((weak));
+
+static int open_eintr(const char *path, int flags) {
+ int ret;
+ do {
+ ret = open(path, flags);
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+static ssize_t read_eintr(int fd, void *out, size_t len) {
+ ssize_t ret;
+ do {
+ ret = read(fd, out, len);
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+/* read_full reads exactly |len| bytes from |fd| to |out|. On error or end of
+ * file, it returns zero. */
+static int read_full(int fd, void *out, size_t len) {
+ char *outp = out;
+ while (len > 0) {
+ ssize_t ret = read_eintr(fd, outp, len);
+ if (ret <= 0) {
+ return 0;
+ }
+ outp += ret;
+ len -= ret;
+ }
+ return 1;
+}
+
+/* read_file opens |path| and reads until end-of-file. On success, it returns
+ * one and sets |*out_ptr| and |*out_len| to a newly-allocated buffer with the
+ * contents. Otherwise, it returns zero. */
+static int read_file(char **out_ptr, size_t *out_len, const char *path) {
+ int fd = open_eintr(path, O_RDONLY);
+ if (fd < 0) {
+ return 0;
+ }
+
+ static const size_t kReadSize = 1024;
+ int ret = 0;
+ size_t cap = kReadSize, len = 0;
+ char *buf = OPENSSL_malloc(cap);
+ if (buf == NULL) {
+ goto err;
+ }
+
+ for (;;) {
+ if (cap - len < kReadSize) {
+ size_t new_cap = cap * 2;
+ if (new_cap < cap) {
+ goto err;
+ }
+ char *new_buf = OPENSSL_realloc(buf, new_cap);
+ if (new_buf == NULL) {
+ goto err;
+ }
+ buf = new_buf;
+ cap = new_cap;
+ }
+
+ ssize_t bytes_read = read_eintr(fd, buf + len, kReadSize);
+ if (bytes_read < 0) {
+ goto err;
+ }
+ if (bytes_read == 0) {
+ break;
+ }
+ len += bytes_read;
+ }
+
+ *out_ptr = buf;
+ *out_len = len;
+ ret = 1;
+ buf = NULL;
+
+err:
+ OPENSSL_free(buf);
+ close(fd);
+ return ret;
+}
+
+/* getauxval_proc behaves like |getauxval| but reads from /proc/self/auxv. */
+static unsigned long getauxval_proc(unsigned long type) {
+ int fd = open_eintr("/proc/self/auxv", O_RDONLY);
+ if (fd < 0) {
+ return 0;
+ }
+
+ struct {
+ unsigned long tag;
+ unsigned long value;
+ } entry;
+
+ for (;;) {
+ if (!read_full(fd, &entry, sizeof(entry)) ||
+ (entry.tag == 0 && entry.value == 0)) {
+ break;
+ }
+ if (entry.tag == type) {
+ close(fd);
+ return entry.value;
+ }
+ }
+ close(fd);
+ return 0;
+}
+
+typedef struct {
+ const char *data;
+ size_t len;
+} STRING_PIECE;
+
+static int STRING_PIECE_equals(const STRING_PIECE *a, const char *b) {
+ size_t b_len = strlen(b);
+ return a->len == b_len && memcmp(a->data, b, b_len) == 0;
+}
+
+/* STRING_PIECE_split finds the first occurence of |sep| in |in| and, if found,
+ * sets |*out_left| and |*out_right| to |in| split before and after it. It
+ * returns one if |sep| was found and zero otherwise. */
+static int STRING_PIECE_split(STRING_PIECE *out_left, STRING_PIECE *out_right,
+ const STRING_PIECE *in, char sep) {
+ const char *p = memchr(in->data, sep, in->len);
+ if (p == NULL) {
+ return 0;
+ }
+ /* |out_left| or |out_right| may alias |in|, so make a copy. */
+ STRING_PIECE in_copy = *in;
+ out_left->data = in_copy.data;
+ out_left->len = p - in_copy.data;
+ out_right->data = in_copy.data + out_left->len + 1;
+ out_right->len = in_copy.len - out_left->len - 1;
+ return 1;
+}
+
+/* STRING_PIECE_trim removes leading and trailing whitespace from |s|. */
+static void STRING_PIECE_trim(STRING_PIECE *s) {
+ while (s->len != 0 && (s->data[0] == ' ' || s->data[0] == '\t')) {
+ s->data++;
+ s->len--;
+ }
+ while (s->len != 0 &&
+ (s->data[s->len - 1] == ' ' || s->data[s->len - 1] == '\t')) {
+ s->len--;
+ }
+}
+
+/* extract_cpuinfo_field extracts a /proc/cpuinfo field named |field| from
+ * |in|. If found, it sets |*out| to the value and returns one. Otherwise, it
+ * returns zero. */
+static int extract_cpuinfo_field(STRING_PIECE *out, const STRING_PIECE *in,
+ const char *field) {
+ /* Process |in| one line at a time. */
+ STRING_PIECE remaining = *in, line;
+ while (STRING_PIECE_split(&line, &remaining, &remaining, '\n')) {
+ STRING_PIECE key, value;
+ if (!STRING_PIECE_split(&key, &value, &line, ':')) {
+ continue;
+ }
+ STRING_PIECE_trim(&key);
+ if (STRING_PIECE_equals(&key, field)) {
+ STRING_PIECE_trim(&value);
+ *out = value;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int cpuinfo_field_equals(const STRING_PIECE *cpuinfo, const char *field,
+ const char *value) {
+ STRING_PIECE extracted;
+ return extract_cpuinfo_field(&extracted, cpuinfo, field) &&
+ STRING_PIECE_equals(&extracted, value);
+}
+
+/* has_list_item treats |list| as a space-separated list of items and returns
+ * one if |item| is contained in |list| and zero otherwise. */
+static int has_list_item(const STRING_PIECE *list, const char *item) {
+ STRING_PIECE remaining = *list, feature;
+ while (STRING_PIECE_split(&feature, &remaining, &remaining, ' ')) {
+ if (STRING_PIECE_equals(&feature, item)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static unsigned long get_hwcap_cpuinfo(const STRING_PIECE *cpuinfo) {
+ if (cpuinfo_field_equals(cpuinfo, "CPU architecture", "8")) {
+ /* This is a 32-bit ARM binary running on a 64-bit kernel. NEON is always
+ * available on ARMv8. Linux omits required features, so reading the
+ * "Features" line does not work. (For simplicity, use strict equality. We
+ * assume everything running on future ARM architectures will have a
+ * working |getauxval|.) */
+ return HWCAP_NEON;
+ }
+
+ STRING_PIECE features;
+ if (extract_cpuinfo_field(&features, cpuinfo, "Features") &&
+ has_list_item(&features, "neon")) {
+ return HWCAP_NEON;
+ }
+ return 0;
+}
+
+static unsigned long get_hwcap2_cpuinfo(const STRING_PIECE *cpuinfo) {
+ STRING_PIECE features;
+ if (!extract_cpuinfo_field(&features, cpuinfo, "Features")) {
+ return 0;
+ }
+
+ unsigned long ret = 0;
+ if (has_list_item(&features, "aes")) {
+ ret |= HWCAP2_AES;
+ }
+ if (has_list_item(&features, "pmull")) {
+ ret |= HWCAP2_PMULL;
+ }
+ if (has_list_item(&features, "sha1")) {
+ ret |= HWCAP2_SHA1;
+ }
+ if (has_list_item(&features, "sha2")) {
+ ret |= HWCAP2_SHA2;
+ }
+ return ret;
+}
+
+/* has_broken_neon returns one if |in| matches a CPU known to have a broken
+ * NEON unit. See https://crbug.com/341598. */
+static int has_broken_neon(const STRING_PIECE *cpuinfo) {
+ return cpuinfo_field_equals(cpuinfo, "CPU implementer", "0x51") &&
+ cpuinfo_field_equals(cpuinfo, "CPU architecture", "7") &&
+ cpuinfo_field_equals(cpuinfo, "CPU variant", "0x1") &&
+ cpuinfo_field_equals(cpuinfo, "CPU part", "0x04d") &&
+ cpuinfo_field_equals(cpuinfo, "CPU revision", "0");
+}
+
+extern uint32_t OPENSSL_armcap_P;
+
+static int g_has_broken_neon;
+
+void OPENSSL_cpuid_setup(void) {
+ char *cpuinfo_data;
+ size_t cpuinfo_len;
+ if (!read_file(&cpuinfo_data, &cpuinfo_len, "/proc/cpuinfo")) {
+ return;
+ }
+ STRING_PIECE cpuinfo;
+ cpuinfo.data = cpuinfo_data;
+ cpuinfo.len = cpuinfo_len;
+
+ /* |getauxval| is not available on Android until API level 20. If it is
+ * unavailable, read from /proc/self/auxv as a fallback. This is unreadable
+ * on some versions of Android, so further fall back to /proc/cpuinfo.
+ *
+ * See
+ * https://android.googlesource.com/platform/ndk/+/882ac8f3392858991a0e1af33b4b7387ec856bd2
+ * and b/13679666 (Google-internal) for details. */
+ unsigned long hwcap = 0;
+ if (getauxval != NULL) {
+ hwcap = getauxval(AT_HWCAP);
+ }
+ if (hwcap == 0) {
+ hwcap = getauxval_proc(AT_HWCAP);
+ }
+ if (hwcap == 0) {
+ hwcap = get_hwcap_cpuinfo(&cpuinfo);
+ }
+
+ /* Clear NEON support if known broken. */
+ g_has_broken_neon = has_broken_neon(&cpuinfo);
+ if (g_has_broken_neon) {
+ hwcap &= ~HWCAP_NEON;
+ }
+
+ /* Matching OpenSSL, only report other features if NEON is present. */
+ if (hwcap & HWCAP_NEON) {
+ OPENSSL_armcap_P |= ARMV7_NEON;
+
+ /* Some ARMv8 Android devices don't expose AT_HWCAP2. Fall back to
+ * /proc/cpuinfo. See https://crbug.com/596156. */
+ unsigned long hwcap2 = 0;
+ if (getauxval != NULL) {
+ hwcap2 = getauxval(AT_HWCAP2);
+ }
+ if (hwcap2 == 0) {
+ hwcap2 = get_hwcap2_cpuinfo(&cpuinfo);
+ }
+
+ if (hwcap2 & HWCAP2_AES) {
+ OPENSSL_armcap_P |= ARMV8_AES;
+ }
+ if (hwcap2 & HWCAP2_PMULL) {
+ OPENSSL_armcap_P |= ARMV8_PMULL;
+ }
+ if (hwcap2 & HWCAP2_SHA1) {
+ OPENSSL_armcap_P |= ARMV8_SHA1;
+ }
+ if (hwcap2 & HWCAP2_SHA2) {
+ OPENSSL_armcap_P |= ARMV8_SHA256;
+ }
+ }
+
+ OPENSSL_free(cpuinfo_data);
+}
+
+int CRYPTO_has_broken_NEON(void) { return g_has_broken_neon; }
+
+#endif /* OPENSSL_ARM && !OPENSSL_STATIC_ARMCAP */
diff --git a/crypto/cpu-arm.c b/crypto/cpu-arm.c
index 675d174e..ef395eae 100644
--- a/crypto/cpu-arm.c
+++ b/crypto/cpu-arm.c
@@ -17,52 +17,15 @@
#if (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) && \
!defined(OPENSSL_STATIC_ARMCAP)
-#include <inttypes.h>
-#include <string.h>
-
-#include <setjmp.h>
-#include <signal.h>
-
#include <openssl/arm_arch.h>
-/* We can't include <sys/auxv.h> because the Android SDK version against which
- * Chromium builds is too old to have it. Instead we define all the constants
- * that we need and have a weak pointer to getauxval. */
-
-unsigned long getauxval(unsigned long type) __attribute__((weak));
-
extern uint32_t OPENSSL_armcap_P;
char CRYPTO_is_NEON_capable_at_runtime(void) {
return (OPENSSL_armcap_P & ARMV7_NEON) != 0;
}
-static char g_set_neon_called = 0;
-
-void CRYPTO_set_NEON_capable(char neon_capable) {
- g_set_neon_called = 1;
-
- if (neon_capable) {
- OPENSSL_armcap_P |= ARMV7_NEON;
- } else {
- OPENSSL_armcap_P &= ~ARMV7_NEON;
- }
-}
-
-char CRYPTO_is_NEON_functional(void) {
- static const uint32_t kWantFlags = ARMV7_NEON | ARMV7_NEON_FUNCTIONAL;
- return (OPENSSL_armcap_P & kWantFlags) == kWantFlags;
-}
-
-void CRYPTO_set_NEON_functional(char neon_functional) {
- if (neon_functional) {
- OPENSSL_armcap_P |= ARMV7_NEON_FUNCTIONAL;
- } else {
- OPENSSL_armcap_P &= ~ARMV7_NEON_FUNCTIONAL;
- }
-}
-
int CRYPTO_is_ARMv8_AES_capable(void) {
return (OPENSSL_armcap_P & ARMV8_AES) != 0;
}
@@ -71,129 +34,5 @@ int CRYPTO_is_ARMv8_PMULL_capable(void) {
return (OPENSSL_armcap_P & ARMV8_PMULL) != 0;
}
-#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_ARM)
-
-static sigjmp_buf sigill_jmp;
-
-static void sigill_handler(int signal) {
- siglongjmp(sigill_jmp, signal);
-}
-
-void CRYPTO_arm_neon_probe(void);
-
-// probe_for_NEON returns 1 if a NEON instruction runs successfully. Because
-// getauxval doesn't exist on Android until Jelly Bean, supporting NEON on
-// older devices requires this.
-static int probe_for_NEON(void) {
- int supported = 0;
-
- sigset_t sigmask;
- sigfillset(&sigmask);
- sigdelset(&sigmask, SIGILL);
- sigdelset(&sigmask, SIGTRAP);
- sigdelset(&sigmask, SIGFPE);
- sigdelset(&sigmask, SIGBUS);
- sigdelset(&sigmask, SIGSEGV);
-
- struct sigaction sigill_original_action, sigill_action;
- memset(&sigill_action, 0, sizeof(sigill_action));
- sigill_action.sa_handler = sigill_handler;
- sigill_action.sa_mask = sigmask;
-
- sigset_t original_sigmask;
- sigprocmask(SIG_SETMASK, &sigmask, &original_sigmask);
-
- if (sigsetjmp(sigill_jmp, 1 /* save signals */) == 0) {
- sigaction(SIGILL, &sigill_action, &sigill_original_action);
-
- // This function cannot be inline asm because GCC will refuse to compile
- // inline NEON instructions unless building with -mfpu=neon, which would
- // defeat the point of probing for support at runtime.
- CRYPTO_arm_neon_probe();
- supported = 1;
- }
- // Note that Android up to and including Lollipop doesn't restore the signal
- // mask correctly after returning from a sigsetjmp. So that would need to be
- // set again here if more probes were added.
- // See https://android-review.googlesource.com/#/c/127624/
-
- sigaction(SIGILL, &sigill_original_action, NULL);
- sigprocmask(SIG_SETMASK, &original_sigmask, NULL);
-
- return supported;
-}
-
-#else
-
-static int probe_for_NEON(void) {
- return 0;
-}
-
-#endif /* !OPENSSL_NO_ASM && OPENSSL_ARM */
-
-void OPENSSL_cpuid_setup(void) {
- if (getauxval == NULL) {
- // On ARM, but not AArch64, try a NEON instruction and see whether it works
- // in order to probe for NEON support.
- //
- // Note that |CRYPTO_is_NEON_capable| can be true even if
- // |CRYPTO_set_NEON_capable| has never been called if the code was compiled
- // with NEON support enabled (e.g. -mfpu=neon).
- if (!g_set_neon_called && !CRYPTO_is_NEON_capable() && probe_for_NEON()) {
- OPENSSL_armcap_P |= ARMV7_NEON;
- }
- return;
- }
-
- static const unsigned long AT_HWCAP = 16;
- unsigned long hwcap = getauxval(AT_HWCAP);
-
-#if defined(OPENSSL_ARM)
- static const unsigned long kNEON = 1 << 12;
- if ((hwcap & kNEON) == 0) {
- return;
- }
-
- /* In 32-bit mode, the ARMv8 feature bits are in a different aux vector
- * value. */
- static const unsigned long AT_HWCAP2 = 26;
- hwcap = getauxval(AT_HWCAP2);
-
- /* See /usr/include/asm/hwcap.h on an ARM installation for the source of
- * these values. */
- static const unsigned long kAES = 1 << 0;
- static const unsigned long kPMULL = 1 << 1;
- static const unsigned long kSHA1 = 1 << 2;
- static const unsigned long kSHA256 = 1 << 3;
-#elif defined(OPENSSL_AARCH64)
- /* See /usr/include/asm/hwcap.h on an aarch64 installation for the source of
- * these values. */
- static const unsigned long kNEON = 1 << 1;
- static const unsigned long kAES = 1 << 3;
- static const unsigned long kPMULL = 1 << 4;
- static const unsigned long kSHA1 = 1 << 5;
- static const unsigned long kSHA256 = 1 << 6;
-
- if ((hwcap & kNEON) == 0) {
- return;
- }
-#endif
-
- OPENSSL_armcap_P |= ARMV7_NEON;
-
- if (hwcap & kAES) {
- OPENSSL_armcap_P |= ARMV8_AES;
- }
- if (hwcap & kPMULL) {
- OPENSSL_armcap_P |= ARMV8_PMULL;
- }
- if (hwcap & kSHA1) {
- OPENSSL_armcap_P |= ARMV8_SHA1;
- }
- if (hwcap & kSHA256) {
- OPENSSL_armcap_P |= ARMV8_SHA256;
- }
-}
-
#endif /* (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) &&
!defined(OPENSSL_STATIC_ARMCAP) */
diff --git a/crypto/cpu-intel.c b/crypto/cpu-intel.c
index 6614f63f..f2e0c4cb 100644
--- a/crypto/cpu-intel.c
+++ b/crypto/cpu-intel.c
@@ -64,17 +64,19 @@
#if !defined(OPENSSL_NO_ASM) && (defined(OPENSSL_X86) || defined(OPENSSL_X86_64))
#include <inttypes.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#if defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <immintrin.h>
#include <intrin.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
+#include "internal.h"
+
/* OPENSSL_cpuid runs the cpuid instruction. |leaf| is passed in as EAX and ECX
* is set to zero. It writes EAX, EBX, ECX, and EDX to |*out_eax| through
diff --git a/crypto/crypto.c b/crypto/crypto.c
index da8807db..c9f2bc87 100644
--- a/crypto/crypto.c
+++ b/crypto/crypto.c
@@ -63,7 +63,7 @@ uint32_t OPENSSL_ia32cap_P[4] = {0};
uint32_t OPENSSL_armcap_P =
#if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__)
- ARMV7_NEON | ARMV7_NEON_FUNCTIONAL |
+ ARMV7_NEON |
#endif
#if defined(OPENSSL_STATIC_ARMCAP_AES)
ARMV8_AES |
@@ -79,10 +79,8 @@ uint32_t OPENSSL_armcap_P =
#endif
0;
-#elif defined(__ARM_NEON__)
-uint32_t OPENSSL_armcap_P = ARMV7_NEON | ARMV7_NEON_FUNCTIONAL;
#else
-uint32_t OPENSSL_armcap_P = ARMV7_NEON_FUNCTIONAL;
+uint32_t OPENSSL_armcap_P = 0;
#endif
#endif
@@ -125,6 +123,22 @@ void CRYPTO_library_init(void) {
#endif
}
+int CRYPTO_is_confidential_build(void) {
+#if defined(BORINGSSL_CONFIDENTIAL)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+int CRYPTO_has_asm(void) {
+#if defined(OPENSSL_NO_ASM)
+ return 0;
+#else
+ return 1;
+#endif
+}
+
const char *SSLeay_version(int unused) {
return "BoringSSL";
}
@@ -140,3 +154,5 @@ int CRYPTO_malloc_init(void) {
void ENGINE_load_builtin_engines(void) {}
void OPENSSL_load_builtin_modules(void) {}
+
+int FIPS_mode(void) { return 0; }
diff --git a/crypto/curve25519/CMakeLists.txt b/crypto/curve25519/CMakeLists.txt
index 90c5705e..7260edca 100644
--- a/crypto/curve25519/CMakeLists.txt
+++ b/crypto/curve25519/CMakeLists.txt
@@ -22,6 +22,7 @@ add_library(
OBJECT
curve25519.c
+ spake25519.c
x25519-x86_64.c
${CURVE25519_ARCH_SOURCES}
@@ -46,4 +47,13 @@ add_executable(
target_link_libraries(x25519_test crypto)
add_dependencies(all_tests x25519_test)
+
+add_executable(
+ spake25519_test
+
+ spake25519_test.cc
+)
+
+target_link_libraries(spake25519_test crypto)
+add_dependencies(all_tests spake25519_test)
endif()
diff --git a/crypto/curve25519/curve25519.c b/crypto/curve25519/curve25519.c
index 61bbdced..1dd1b3ed 100644
--- a/crypto/curve25519/curve25519.c
+++ b/crypto/curve25519/curve25519.c
@@ -31,11 +31,10 @@
#include "internal.h"
-/* fe means field element. Here the field is \Z/(2^255-19). An element t,
- * entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
- * t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
- * context. */
-typedef int32_t fe[10];
+static const int64_t kBottom25Bits = INT64_C(0x1ffffff);
+static const int64_t kBottom26Bits = INT64_C(0x3ffffff);
+static const int64_t kTop39Bits = INT64_C(0xfffffffffe000000);
+static const int64_t kTop38Bits = INT64_C(0xfffffffffc000000);
static uint64_t load_3(const uint8_t *in) {
uint64_t result;
@@ -77,17 +76,17 @@ static void fe_frombytes(fe h, const uint8_t *s) {
int64_t carry8;
int64_t carry9;
- carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
- carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
- carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
- carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
- carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+ carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits;
+ carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits;
+ carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits;
+ carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits;
+ carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits;
- carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
- carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
- carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
- carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
- carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+ carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
+ carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits;
+ carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
+ carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits;
+ carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits;
h[0] = h0;
h[1] = h1;
@@ -135,16 +134,6 @@ static void fe_tobytes(uint8_t *s, const fe h) {
int32_t h8 = h[8];
int32_t h9 = h[9];
int32_t q;
- int32_t carry0;
- int32_t carry1;
- int32_t carry2;
- int32_t carry3;
- int32_t carry4;
- int32_t carry5;
- int32_t carry6;
- int32_t carry7;
- int32_t carry8;
- int32_t carry9;
q = (19 * h9 + (((int32_t) 1) << 24)) >> 25;
q = (h0 + q) >> 26;
@@ -162,16 +151,16 @@ static void fe_tobytes(uint8_t *s, const fe h) {
h0 += 19 * q;
/* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
- carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
- carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
- carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
- carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
- carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
- carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
- carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
- carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
- carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
- carry9 = h9 >> 25; h9 -= carry9 << 25;
+ h1 += h0 >> 26; h0 &= kBottom26Bits;
+ h2 += h1 >> 25; h1 &= kBottom25Bits;
+ h3 += h2 >> 26; h2 &= kBottom26Bits;
+ h4 += h3 >> 25; h3 &= kBottom25Bits;
+ h5 += h4 >> 26; h4 &= kBottom26Bits;
+ h6 += h5 >> 25; h5 &= kBottom25Bits;
+ h7 += h6 >> 26; h6 &= kBottom26Bits;
+ h8 += h7 >> 25; h7 &= kBottom25Bits;
+ h9 += h8 >> 26; h8 &= kBottom26Bits;
+ h9 &= kBottom25Bits;
/* h10 = carry9 */
/* Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
@@ -182,32 +171,32 @@ static void fe_tobytes(uint8_t *s, const fe h) {
s[0] = h0 >> 0;
s[1] = h0 >> 8;
s[2] = h0 >> 16;
- s[3] = (h0 >> 24) | (h1 << 2);
+ s[3] = (h0 >> 24) | ((uint32_t)(h1) << 2);
s[4] = h1 >> 6;
s[5] = h1 >> 14;
- s[6] = (h1 >> 22) | (h2 << 3);
+ s[6] = (h1 >> 22) | ((uint32_t)(h2) << 3);
s[7] = h2 >> 5;
s[8] = h2 >> 13;
- s[9] = (h2 >> 21) | (h3 << 5);
+ s[9] = (h2 >> 21) | ((uint32_t)(h3) << 5);
s[10] = h3 >> 3;
s[11] = h3 >> 11;
- s[12] = (h3 >> 19) | (h4 << 6);
+ s[12] = (h3 >> 19) | ((uint32_t)(h4) << 6);
s[13] = h4 >> 2;
s[14] = h4 >> 10;
s[15] = h4 >> 18;
s[16] = h5 >> 0;
s[17] = h5 >> 8;
s[18] = h5 >> 16;
- s[19] = (h5 >> 24) | (h6 << 1);
+ s[19] = (h5 >> 24) | ((uint32_t)(h6) << 1);
s[20] = h6 >> 7;
s[21] = h6 >> 15;
- s[22] = (h6 >> 23) | (h7 << 3);
+ s[22] = (h6 >> 23) | ((uint32_t)(h7) << 3);
s[23] = h7 >> 5;
s[24] = h7 >> 13;
- s[25] = (h7 >> 21) | (h8 << 4);
+ s[25] = (h7 >> 21) | ((uint32_t)(h8) << 4);
s[26] = h8 >> 4;
s[27] = h8 >> 12;
- s[28] = (h8 >> 20) | (h9 << 6);
+ s[28] = (h8 >> 20) | ((uint32_t)(h9) << 6);
s[29] = h9 >> 2;
s[30] = h9 >> 10;
s[31] = h9 >> 18;
@@ -447,46 +436,46 @@ static void fe_mul(fe h, const fe f, const fe g) {
* |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19))
* i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 */
- carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
- carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
+ carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
/* |h0| <= 2^25 */
/* |h4| <= 2^25 */
/* |h1| <= 1.71*2^59 */
/* |h5| <= 1.71*2^59 */
- carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
- carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+ carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits;
+ carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits;
/* |h1| <= 2^24; from now on fits into int32 */
/* |h5| <= 2^24; from now on fits into int32 */
/* |h2| <= 1.41*2^60 */
/* |h6| <= 1.41*2^60 */
- carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
- carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+ carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits;
+ carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits;
/* |h2| <= 2^25; from now on fits into int32 unchanged */
/* |h6| <= 2^25; from now on fits into int32 unchanged */
/* |h3| <= 1.71*2^59 */
/* |h7| <= 1.71*2^59 */
- carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
- carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+ carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits;
+ carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits;
/* |h3| <= 2^24; from now on fits into int32 unchanged */
/* |h7| <= 2^24; from now on fits into int32 unchanged */
/* |h4| <= 1.72*2^34 */
/* |h8| <= 1.41*2^60 */
- carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
- carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+ carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
+ carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits;
/* |h4| <= 2^25; from now on fits into int32 unchanged */
/* |h8| <= 2^25; from now on fits into int32 unchanged */
/* |h5| <= 1.01*2^24 */
/* |h9| <= 1.71*2^59 */
- carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+ carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits;
/* |h9| <= 2^24; from now on fits into int32 unchanged */
/* |h0| <= 1.1*2^39 */
- carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
/* |h0| <= 2^25; from now on fits into int32 unchanged */
/* |h1| <= 1.01*2^24 */
@@ -612,24 +601,24 @@ static void fe_sq(fe h, const fe f) {
int64_t carry8;
int64_t carry9;
- carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
- carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
+ carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
- carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
- carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+ carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits;
+ carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits;
- carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
- carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+ carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits;
+ carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits;
- carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
- carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+ carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits;
+ carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits;
- carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
- carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+ carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
+ carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits;
- carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+ carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits;
- carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
h[0] = h0;
h[1] = h1;
@@ -880,24 +869,24 @@ static void fe_sq2(fe h, const fe f) {
h8 += h8;
h9 += h9;
- carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
- carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
+ carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
- carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
- carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+ carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits;
+ carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits;
- carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
- carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+ carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits;
+ carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits;
- carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
- carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+ carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits;
+ carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits;
- carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
- carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+ carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
+ carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits;
- carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+ carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits;
- carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
h[0] = h0;
h[1] = h1;
@@ -974,52 +963,7 @@ static void fe_pow22523(fe out, const fe z) {
fe_mul(out, t0, z);
}
-/* ge means group element.
-
- * Here the group is the set of pairs (x,y) of field elements (see fe.h)
- * satisfying -x^2 + y^2 = 1 + d x^2y^2
- * where d = -121665/121666.
- *
- * Representations:
- * ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
- * ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
- * ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
- * ge_precomp (Duif): (y+x,y-x,2dxy) */
-
-typedef struct {
- fe X;
- fe Y;
- fe Z;
-} ge_p2;
-
-typedef struct {
- fe X;
- fe Y;
- fe Z;
- fe T;
-} ge_p3;
-
-typedef struct {
- fe X;
- fe Y;
- fe Z;
- fe T;
-} ge_p1p1;
-
-typedef struct {
- fe yplusx;
- fe yminusx;
- fe xy2d;
-} ge_precomp;
-
-typedef struct {
- fe YplusX;
- fe YminusX;
- fe Z;
- fe T2d;
-} ge_cached;
-
-static void ge_tobytes(uint8_t *s, const ge_p2 *h) {
+void x25519_ge_tobytes(uint8_t *s, const ge_p2 *h) {
fe recip;
fe x;
fe y;
@@ -1049,7 +993,7 @@ static const fe d = {-10913610, 13857413, -15372611, 6949391, 114729,
static const fe sqrtm1 = {-32595792, -7943725, 9377950, 3500415, 12389472,
-272473, -25146209, -2005654, 326686, 11406482};
-static int ge_frombytes_vartime(ge_p3 *h, const uint8_t *s) {
+int x25519_ge_frombytes_vartime(ge_p3 *h, const uint8_t *s) {
fe u;
fe v;
fe v3;
@@ -1105,6 +1049,13 @@ static void ge_p3_0(ge_p3 *h) {
fe_0(h->T);
}
+static void ge_cached_0(ge_cached *h) {
+ fe_1(h->YplusX);
+ fe_1(h->YminusX);
+ fe_1(h->Z);
+ fe_0(h->T2d);
+}
+
static void ge_precomp_0(ge_precomp *h) {
fe_1(h->yplusx);
fe_1(h->yminusx);
@@ -1122,7 +1073,7 @@ static const fe d2 = {-21827239, -5839606, -30745221, 13898782, 229458,
15978800, -12551817, -6495438, 29715968, 9444199};
/* r = p */
-static void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
+void x25519_ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
fe_add(r->YplusX, p->Y, p->X);
fe_sub(r->YminusX, p->Y, p->X);
fe_copy(r->Z, p->Z);
@@ -1130,20 +1081,27 @@ static void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
}
/* r = p */
-static void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
+void x25519_ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
fe_mul(r->X, p->X, p->T);
fe_mul(r->Y, p->Y, p->Z);
fe_mul(r->Z, p->Z, p->T);
}
/* r = p */
-static void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
+void x25519_ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
fe_mul(r->X, p->X, p->T);
fe_mul(r->Y, p->Y, p->Z);
fe_mul(r->Z, p->Z, p->T);
fe_mul(r->T, p->X, p->Y);
}
+/* r = p */
+static void ge_p1p1_to_cached(ge_cached *r, const ge_p1p1 *p) {
+ ge_p3 t;
+ x25519_ge_p1p1_to_p3(&t, p);
+ x25519_ge_p3_to_cached(r, &t);
+}
+
/* r = 2 * p */
static void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
fe t0;
@@ -1199,7 +1157,7 @@ static void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
}
/* r = p + q */
-static void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
+void x25519_ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
fe t0;
fe_add(r->X, p->Y, p->X);
@@ -1216,7 +1174,7 @@ static void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
}
/* r = p - q */
-static void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
+void x25519_ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
fe t0;
fe_add(r->X, p->Y, p->X);
@@ -1242,12 +1200,64 @@ static uint8_t equal(signed char b, signed char c) {
return y;
}
-static void cmov(ge_precomp *t, ge_precomp *u, uint8_t b) {
+static void cmov(ge_precomp *t, const ge_precomp *u, uint8_t b) {
fe_cmov(t->yplusx, u->yplusx, b);
fe_cmov(t->yminusx, u->yminusx, b);
fe_cmov(t->xy2d, u->xy2d, b);
}
+void x25519_ge_scalarmult_small_precomp(
+ ge_p3 *h, const uint8_t a[32], const uint8_t precomp_table[15 * 2 * 32]) {
+ /* precomp_table is first expanded into matching |ge_precomp|
+ * elements. */
+ ge_precomp multiples[15];
+
+ unsigned i;
+ for (i = 0; i < 15; i++) {
+ const uint8_t *bytes = &precomp_table[i*(2 * 32)];
+ fe x, y;
+ fe_frombytes(x, bytes);
+ fe_frombytes(y, bytes + 32);
+
+ ge_precomp *out = &multiples[i];
+ fe_add(out->yplusx, y, x);
+ fe_sub(out->yminusx, y, x);
+ fe_mul(out->xy2d, x, y);
+ fe_mul(out->xy2d, out->xy2d, d2);
+ }
+
+ /* See the comment above |k25519SmallPrecomp| about the structure of the
+ * precomputed elements. This loop does 64 additions and 64 doublings to
+ * calculate the result. */
+ ge_p3_0(h);
+
+ for (i = 63; i < 64; i--) {
+ unsigned j;
+ signed char index = 0;
+
+ for (j = 0; j < 4; j++) {
+ const uint8_t bit = 1 & (a[(8 * j) + (i / 8)] >> (i & 7));
+ index |= (bit << j);
+ }
+
+ ge_precomp e;
+ ge_precomp_0(&e);
+
+ for (j = 1; j < 16; j++) {
+ cmov(&e, &multiples[j-1], equal(index, j));
+ }
+
+ ge_cached cached;
+ ge_p1p1 r;
+ x25519_ge_p3_to_cached(&cached, h);
+ x25519_ge_add(&r, h, &cached);
+ x25519_ge_p1p1_to_p3(h, &r);
+
+ ge_madd(&r, h, &e);
+ x25519_ge_p1p1_to_p3(h, &r);
+ }
+}
+
#if defined(OPENSSL_SMALL)
/* This block of code replaces the standard base-point table with a much smaller
@@ -1341,61 +1351,14 @@ static const uint8_t k25519SmallPrecomp[15 * 2 * 32] = {
0x45, 0xc9, 0x8b, 0x17, 0x79, 0xe7, 0xc7, 0x90, 0x99, 0x3a, 0x18, 0x25,
};
-static void ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]) {
- /* k25519SmallPrecomp is first expanded into matching |ge_precomp|
- * elements. */
- ge_precomp multiples[15];
-
- unsigned i;
- for (i = 0; i < 15; i++) {
- const uint8_t *bytes = &k25519SmallPrecomp[i*(2 * 32)];
- fe x, y;
- fe_frombytes(x, bytes);
- fe_frombytes(y, bytes + 32);
-
- ge_precomp *out = &multiples[i];
- fe_add(out->yplusx, y, x);
- fe_sub(out->yminusx, y, x);
- fe_mul(out->xy2d, x, y);
- fe_mul(out->xy2d, out->xy2d, d2);
- }
-
- /* See the comment above |k25519SmallPrecomp| about the structure of the
- * precomputed elements. This loop does 64 additions and 64 doublings to
- * calculate the result. */
- ge_p3_0(h);
-
- for (i = 63; i < 64; i--) {
- unsigned j;
- signed char index = 0;
-
- for (j = 0; j < 4; j++) {
- const uint8_t bit = 1 & (a[(8 * j) + (i / 8)] >> (i & 7));
- index |= (bit << j);
- }
-
- ge_precomp e;
- ge_precomp_0(&e);
-
- for (j = 1; j < 16; j++) {
- cmov(&e, &multiples[j-1], equal(index, j));
- }
-
- ge_cached cached;
- ge_p1p1 r;
- ge_p3_to_cached(&cached, h);
- ge_add(&r, h, &cached);
- ge_p1p1_to_p3(h, &r);
-
- ge_madd(&r, h, &e);
- ge_p1p1_to_p3(h, &r);
- }
+void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]) {
+ x25519_ge_scalarmult_small_precomp(h, a, k25519SmallPrecomp);
}
#else
/* k25519Precomp[i][j] = (j+1)*256^i*B */
-static ge_precomp k25519Precomp[32][8] = {
+static const ge_precomp k25519Precomp[32][8] = {
{
{
{25967493, -14356035, 29566456, 3660896, -12694345, 4014787,
@@ -3519,7 +3482,7 @@ static uint8_t negative(signed char b) {
static void table_select(ge_precomp *t, int pos, signed char b) {
ge_precomp minust;
uint8_t bnegative = negative(b);
- uint8_t babs = b - (((-bnegative) & b) << 1);
+ uint8_t babs = b - ((uint8_t)((-bnegative) & b) << 1);
ge_precomp_0(t);
cmov(t, &k25519Precomp[pos][0], equal(babs, 1));
@@ -3542,7 +3505,7 @@ static void table_select(ge_precomp *t, int pos, signed char b) {
*
* Preconditions:
* a[31] <= 127 */
-static void ge_scalarmult_base(ge_p3 *h, const uint8_t *a) {
+void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t *a) {
signed char e[64];
signed char carry;
ge_p1p1 r;
@@ -3571,27 +3534,88 @@ static void ge_scalarmult_base(ge_p3 *h, const uint8_t *a) {
for (i = 1; i < 64; i += 2) {
table_select(&t, i / 2, e[i]);
ge_madd(&r, h, &t);
- ge_p1p1_to_p3(h, &r);
+ x25519_ge_p1p1_to_p3(h, &r);
}
ge_p3_dbl(&r, h);
- ge_p1p1_to_p2(&s, &r);
+ x25519_ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s);
- ge_p1p1_to_p2(&s, &r);
+ x25519_ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s);
- ge_p1p1_to_p2(&s, &r);
+ x25519_ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s);
- ge_p1p1_to_p3(h, &r);
+ x25519_ge_p1p1_to_p3(h, &r);
for (i = 0; i < 64; i += 2) {
table_select(&t, i / 2, e[i]);
ge_madd(&r, h, &t);
- ge_p1p1_to_p3(h, &r);
+ x25519_ge_p1p1_to_p3(h, &r);
}
}
#endif
+static void cmov_cached(ge_cached *t, ge_cached *u, uint8_t b) {
+ fe_cmov(t->YplusX, u->YplusX, b);
+ fe_cmov(t->YminusX, u->YminusX, b);
+ fe_cmov(t->Z, u->Z, b);
+ fe_cmov(t->T2d, u->T2d, b);
+}
+
+/* r = scalar * A.
+ * where a = a[0]+256*a[1]+...+256^31 a[31]. */
+void x25519_ge_scalarmult(ge_p2 *r, const uint8_t *scalar, const ge_p3 *A) {
+ ge_p2 Ai_p2[8];
+ ge_cached Ai[16];
+ ge_p1p1 t;
+
+ ge_cached_0(&Ai[0]);
+ x25519_ge_p3_to_cached(&Ai[1], A);
+ ge_p3_to_p2(&Ai_p2[1], A);
+
+ unsigned i;
+ for (i = 2; i < 16; i += 2) {
+ ge_p2_dbl(&t, &Ai_p2[i / 2]);
+ ge_p1p1_to_cached(&Ai[i], &t);
+ if (i < 8) {
+ x25519_ge_p1p1_to_p2(&Ai_p2[i], &t);
+ }
+ x25519_ge_add(&t, A, &Ai[i]);
+ ge_p1p1_to_cached(&Ai[i + 1], &t);
+ if (i < 7) {
+ x25519_ge_p1p1_to_p2(&Ai_p2[i + 1], &t);
+ }
+ }
+
+ ge_p2_0(r);
+ ge_p3 u;
+
+ for (i = 0; i < 256; i += 4) {
+ ge_p2_dbl(&t, r);
+ x25519_ge_p1p1_to_p2(r, &t);
+ ge_p2_dbl(&t, r);
+ x25519_ge_p1p1_to_p2(r, &t);
+ ge_p2_dbl(&t, r);
+ x25519_ge_p1p1_to_p2(r, &t);
+ ge_p2_dbl(&t, r);
+ x25519_ge_p1p1_to_p3(&u, &t);
+
+ uint8_t index = scalar[31 - i/8];
+ index >>= 4 - (i & 4);
+ index &= 0xf;
+
+ unsigned j;
+ ge_cached selected;
+ ge_cached_0(&selected);
+ for (j = 0; j < 16; j++) {
+ cmov_cached(&selected, &Ai[j], equal(j, index));
+ }
+
+ x25519_ge_add(&t, &u, &selected);
+ x25519_ge_p1p1_to_p2(r, &t);
+ }
+}
+
static void slide(signed char *r, const uint8_t *a) {
int i;
int b;
@@ -3626,7 +3650,7 @@ static void slide(signed char *r, const uint8_t *a) {
}
}
-static ge_precomp Bi[8] = {
+static const ge_precomp Bi[8] = {
{
{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626,
-11754271, -6079156, 2047605},
@@ -3697,8 +3721,8 @@ static ge_precomp Bi[8] = {
* where a = a[0]+256*a[1]+...+256^31 a[31].
* and b = b[0]+256*b[1]+...+256^31 b[31].
* B is the Ed25519 base point (x,4/5) with x positive. */
-void ge_double_scalarmult_vartime(ge_p2 *r, const uint8_t *a,
- const ge_p3 *A, const uint8_t *b) {
+static void ge_double_scalarmult_vartime(ge_p2 *r, const uint8_t *a,
+ const ge_p3 *A, const uint8_t *b) {
signed char aslide[256];
signed char bslide[256];
ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
@@ -3710,30 +3734,30 @@ void ge_double_scalarmult_vartime(ge_p2 *r, const uint8_t *a,
slide(aslide, a);
slide(bslide, b);
- ge_p3_to_cached(&Ai[0], A);
+ x25519_ge_p3_to_cached(&Ai[0], A);
ge_p3_dbl(&t, A);
- ge_p1p1_to_p3(&A2, &t);
- ge_add(&t, &A2, &Ai[0]);
- ge_p1p1_to_p3(&u, &t);
- ge_p3_to_cached(&Ai[1], &u);
- ge_add(&t, &A2, &Ai[1]);
- ge_p1p1_to_p3(&u, &t);
- ge_p3_to_cached(&Ai[2], &u);
- ge_add(&t, &A2, &Ai[2]);
- ge_p1p1_to_p3(&u, &t);
- ge_p3_to_cached(&Ai[3], &u);
- ge_add(&t, &A2, &Ai[3]);
- ge_p1p1_to_p3(&u, &t);
- ge_p3_to_cached(&Ai[4], &u);
- ge_add(&t, &A2, &Ai[4]);
- ge_p1p1_to_p3(&u, &t);
- ge_p3_to_cached(&Ai[5], &u);
- ge_add(&t, &A2, &Ai[5]);
- ge_p1p1_to_p3(&u, &t);
- ge_p3_to_cached(&Ai[6], &u);
- ge_add(&t, &A2, &Ai[6]);
- ge_p1p1_to_p3(&u, &t);
- ge_p3_to_cached(&Ai[7], &u);
+ x25519_ge_p1p1_to_p3(&A2, &t);
+ x25519_ge_add(&t, &A2, &Ai[0]);
+ x25519_ge_p1p1_to_p3(&u, &t);
+ x25519_ge_p3_to_cached(&Ai[1], &u);
+ x25519_ge_add(&t, &A2, &Ai[1]);
+ x25519_ge_p1p1_to_p3(&u, &t);
+ x25519_ge_p3_to_cached(&Ai[2], &u);
+ x25519_ge_add(&t, &A2, &Ai[2]);
+ x25519_ge_p1p1_to_p3(&u, &t);
+ x25519_ge_p3_to_cached(&Ai[3], &u);
+ x25519_ge_add(&t, &A2, &Ai[3]);
+ x25519_ge_p1p1_to_p3(&u, &t);
+ x25519_ge_p3_to_cached(&Ai[4], &u);
+ x25519_ge_add(&t, &A2, &Ai[4]);
+ x25519_ge_p1p1_to_p3(&u, &t);
+ x25519_ge_p3_to_cached(&Ai[5], &u);
+ x25519_ge_add(&t, &A2, &Ai[5]);
+ x25519_ge_p1p1_to_p3(&u, &t);
+ x25519_ge_p3_to_cached(&Ai[6], &u);
+ x25519_ge_add(&t, &A2, &Ai[6]);
+ x25519_ge_p1p1_to_p3(&u, &t);
+ x25519_ge_p3_to_cached(&Ai[7], &u);
ge_p2_0(r);
@@ -3747,22 +3771,22 @@ void ge_double_scalarmult_vartime(ge_p2 *r, const uint8_t *a,
ge_p2_dbl(&t, r);
if (aslide[i] > 0) {
- ge_p1p1_to_p3(&u, &t);
- ge_add(&t, &u, &Ai[aslide[i] / 2]);
+ x25519_ge_p1p1_to_p3(&u, &t);
+ x25519_ge_add(&t, &u, &Ai[aslide[i] / 2]);
} else if (aslide[i] < 0) {
- ge_p1p1_to_p3(&u, &t);
- ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
+ x25519_ge_p1p1_to_p3(&u, &t);
+ x25519_ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
}
if (bslide[i] > 0) {
- ge_p1p1_to_p3(&u, &t);
+ x25519_ge_p1p1_to_p3(&u, &t);
ge_madd(&t, &u, &Bi[bslide[i] / 2]);
} else if (bslide[i] < 0) {
- ge_p1p1_to_p3(&u, &t);
+ x25519_ge_p1p1_to_p3(&u, &t);
ge_msub(&t, &u, &Bi[(-bslide[i]) / 2]);
}
- ge_p1p1_to_p2(r, &t);
+ x25519_ge_p1p1_to_p2(r, &t);
}
}
@@ -3776,7 +3800,7 @@ void ge_double_scalarmult_vartime(ge_p2 *r, const uint8_t *a,
* s[0]+256*s[1]+...+256^31*s[31] = s mod l
* where l = 2^252 + 27742317777372353535851937790883648493.
* Overwrites s in place. */
-static void sc_reduce(uint8_t *s) {
+void x25519_sc_reduce(uint8_t *s) {
int64_t s0 = 2097151 & load_3(s);
int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
@@ -4610,7 +4634,7 @@ void ED25519_keypair(uint8_t out_public_key[32], uint8_t out_private_key[64]) {
az[31] |= 64;
ge_p3 A;
- ge_scalarmult_base(&A, az);
+ x25519_ge_scalarmult_base(&A, az);
ge_p3_tobytes(out_public_key, &A);
memcpy(out_private_key, seed, 32);
@@ -4633,9 +4657,9 @@ int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len,
uint8_t nonce[SHA512_DIGEST_LENGTH];
SHA512_Final(nonce, &hash_ctx);
- sc_reduce(nonce);
+ x25519_sc_reduce(nonce);
ge_p3 R;
- ge_scalarmult_base(&R, nonce);
+ x25519_ge_scalarmult_base(&R, nonce);
ge_p3_tobytes(out_sig, &R);
SHA512_Init(&hash_ctx);
@@ -4645,7 +4669,7 @@ int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len,
uint8_t hram[SHA512_DIGEST_LENGTH];
SHA512_Final(hram, &hash_ctx);
- sc_reduce(hram);
+ x25519_sc_reduce(hram);
sc_muladd(out_sig + 32, hram, az, nonce);
return 1;
@@ -4655,7 +4679,7 @@ int ED25519_verify(const uint8_t *message, size_t message_len,
const uint8_t signature[64], const uint8_t public_key[32]) {
ge_p3 A;
if ((signature[63] & 224) != 0 ||
- ge_frombytes_vartime(&A, public_key) != 0) {
+ x25519_ge_frombytes_vartime(&A, public_key) != 0) {
return 0;
}
@@ -4677,13 +4701,13 @@ int ED25519_verify(const uint8_t *message, size_t message_len,
uint8_t h[SHA512_DIGEST_LENGTH];
SHA512_Final(h, &hash_ctx);
- sc_reduce(h);
+ x25519_sc_reduce(h);
ge_p2 R;
ge_double_scalarmult_vartime(&R, h, &A, scopy);
uint8_t rcheck[32];
- ge_tobytes(rcheck, &R);
+ x25519_ge_tobytes(rcheck, &R);
return CRYPTO_memcmp(rcheck, rcopy, sizeof(rcheck)) == 0;
}
@@ -4753,17 +4777,17 @@ static void fe_mul121666(fe h, fe f) {
int64_t carry8;
int64_t carry9;
- carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
- carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
- carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
- carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
- carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+ carry9 = h9 + (1 << 24); h0 += (carry9 >> 25) * 19; h9 -= carry9 & kTop39Bits;
+ carry1 = h1 + (1 << 24); h2 += carry1 >> 25; h1 -= carry1 & kTop39Bits;
+ carry3 = h3 + (1 << 24); h4 += carry3 >> 25; h3 -= carry3 & kTop39Bits;
+ carry5 = h5 + (1 << 24); h6 += carry5 >> 25; h5 -= carry5 & kTop39Bits;
+ carry7 = h7 + (1 << 24); h8 += carry7 >> 25; h7 -= carry7 & kTop39Bits;
- carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
- carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
- carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
- carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
- carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+ carry0 = h0 + (1 << 25); h1 += carry0 >> 26; h0 -= carry0 & kTop38Bits;
+ carry2 = h2 + (1 << 25); h3 += carry2 >> 26; h2 -= carry2 & kTop38Bits;
+ carry4 = h4 + (1 << 25); h5 += carry4 >> 26; h4 -= carry4 & kTop38Bits;
+ carry6 = h6 + (1 << 25); h7 += carry6 >> 26; h6 -= carry6 & kTop38Bits;
+ carry8 = h8 + (1 << 25); h9 += carry8 >> 26; h8 -= carry8 & kTop38Bits;
h[0] = h0;
h[1] = h1;
@@ -4887,7 +4911,7 @@ void X25519_public_from_private(uint8_t out_public_value[32],
e[31] |= 64;
ge_p3 A;
- ge_scalarmult_base(&A, e);
+ x25519_ge_scalarmult_base(&A, e);
/* We only need the u-coordinate of the curve25519 point. The map is
* u=(y+1)/(1-y). Since y=Y/Z, this gives u=(Z+Y)/(Z-Y). */
diff --git a/crypto/curve25519/internal.h b/crypto/curve25519/internal.h
index 27994b7b..ea206a3e 100644
--- a/crypto/curve25519/internal.h
+++ b/crypto/curve25519/internal.h
@@ -37,6 +37,70 @@ void x25519_NEON(uint8_t out[32], const uint8_t scalar[32],
const uint8_t point[32]);
#endif
+/* fe means field element. Here the field is \Z/(2^255-19). An element t,
+ * entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
+ * t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
+ * context. */
+typedef int32_t fe[10];
+
+/* ge means group element.
+
+ * Here the group is the set of pairs (x,y) of field elements (see fe.h)
+ * satisfying -x^2 + y^2 = 1 + d x^2y^2
+ * where d = -121665/121666.
+ *
+ * Representations:
+ * ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
+ * ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+ * ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+ * ge_precomp (Duif): (y+x,y-x,2dxy) */
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+} ge_p2;
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+ fe T;
+} ge_p3;
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+ fe T;
+} ge_p1p1;
+
+typedef struct {
+ fe yplusx;
+ fe yminusx;
+ fe xy2d;
+} ge_precomp;
+
+typedef struct {
+ fe YplusX;
+ fe YminusX;
+ fe Z;
+ fe T2d;
+} ge_cached;
+
+void x25519_ge_tobytes(uint8_t *s, const ge_p2 *h);
+int x25519_ge_frombytes_vartime(ge_p3 *h, const uint8_t *s);
+void x25519_ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
+void x25519_ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
+void x25519_ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p);
+void x25519_ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
+void x25519_ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
+void x25519_ge_scalarmult_small_precomp(
+ ge_p3 *h, const uint8_t a[32], const uint8_t precomp_table[15 * 2 * 32]);
+void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]);
+void x25519_ge_scalarmult(ge_p2 *r, const uint8_t *scalar, const ge_p3 *A);
+void x25519_sc_reduce(uint8_t *s);
+
#if defined(__cplusplus)
} /* extern C */
diff --git a/crypto/curve25519/spake25519.c b/crypto/curve25519/spake25519.c
new file mode 100644
index 00000000..617418cf
--- /dev/null
+++ b/crypto/curve25519/spake25519.c
@@ -0,0 +1,464 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/curve25519.h>
+
+#include <string.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/mem.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+#include "internal.h"
+
+
+/* The following precomputation tables are for the following
+ * points used in the SPAKE2 protocol.
+ *
+ * N:
+ * x: 49918732221787544735331783592030787422991506689877079631459872391322455579424
+ * y: 54629554431565467720832445949441049581317094546788069926228343916274969994000
+ * encoded: 10e3df0ae37d8e7a99b5fe74b44672103dbddcbd06af680d71329a11693bc778
+ *
+ * M:
+ * x: 31406539342727633121250288103050113562375374900226415211311216773867585644232
+ * y: 21177308356423958466833845032658859666296341766942662650232962324899758529114
+ * encoded: 5ada7e4bf6ddd9adb6626d32131c6b5c51a1e347a3478f53cfcf441b88eed12e
+ *
+ * These points and their precomputation tables are generated with the
+ * following Python code. For a description of the precomputation table,
+ * see curve25519.c in this directory.
+ *
+ * Exact copies of the source code are kept in bug 27296743.
+ *
+ * import hashlib
+ * import ed25519 as E # http://ed25519.cr.yp.to/python/ed25519.py
+ *
+ * SEED_N = 'edwards25519 point generation seed (N)'
+ * SEED_M = 'edwards25519 point generation seed (M)'
+ *
+ * def genpoint(seed):
+ * v = hashlib.sha256(seed).digest()
+ * it = 1
+ * while True:
+ * try:
+ * x,y = E.decodepoint(v)
+ * except Exception, e:
+ * print e
+ * it += 1
+ * v = hashlib.sha256(v).digest()
+ * continue
+ * print "Found in %d iterations:" % it
+ * print " x = %d" % x
+ * print " y = %d" % y
+ * print " Encoded (hex)"
+ * print E.encodepoint((x,y)).encode('hex')
+ * return (x,y)
+ *
+ * def gentable(P):
+ * t = []
+ * for i in range(1,16):
+ * k = (i >> 3 & 1) * (1 << 192) + \
+ * (i >> 2 & 1) * (1 << 128) + \
+ * (i >> 1 & 1) * (1 << 64) + \
+ * (i & 1)
+ * t.append(E.scalarmult(P, k))
+ * return ''.join(E.encodeint(x) + E.encodeint(y) for (x,y) in t)
+ *
+ * def printtable(table, name):
+ * print "static const uint8_t %s[15 * 2 * 32] = {" % name,
+ * for i in range(15 * 2 * 32):
+ * if i % 12 == 0:
+ * print "\n ",
+ * print " 0x%02x," % ord(table[i]),
+ * print "\n};"
+ *
+ * if __name__ == "__main__":
+ * print "Searching for N"
+ * N = genpoint(SEED_N)
+ * print "Generating precomputation table for N"
+ * Ntable = gentable(N)
+ * printtable(Ntable, "kSpakeNSmallPrecomp")
+ *
+ * print "Searching for M"
+ * M = genpoint(SEED_M)
+ * print "Generating precomputation table for M"
+ * Mtable = gentable(M)
+ * printtable(Mtable, "kSpakeMSmallPrecomp")
+ */
+static const uint8_t kSpakeNSmallPrecomp[15 * 2 * 32] = {
+ 0x20, 0x1b, 0xc5, 0xb3, 0x43, 0x17, 0x71, 0x10, 0x44, 0x1e, 0x73, 0xb3,
+ 0xae, 0x3f, 0xbf, 0x9f, 0xf5, 0x44, 0xc8, 0x13, 0x8f, 0xd1, 0x01, 0xc2,
+ 0x8a, 0x1a, 0x6d, 0xea, 0x4d, 0x00, 0x5d, 0x6e, 0x10, 0xe3, 0xdf, 0x0a,
+ 0xe3, 0x7d, 0x8e, 0x7a, 0x99, 0xb5, 0xfe, 0x74, 0xb4, 0x46, 0x72, 0x10,
+ 0x3d, 0xbd, 0xdc, 0xbd, 0x06, 0xaf, 0x68, 0x0d, 0x71, 0x32, 0x9a, 0x11,
+ 0x69, 0x3b, 0xc7, 0x78, 0x93, 0xf1, 0x57, 0x97, 0x6e, 0xf0, 0x6e, 0x45,
+ 0x37, 0x4a, 0xf4, 0x0b, 0x18, 0x51, 0xf5, 0x4f, 0x67, 0x3c, 0xdc, 0xec,
+ 0x84, 0xed, 0xd0, 0xeb, 0xca, 0xfb, 0xdb, 0xff, 0x7f, 0xeb, 0xa8, 0x23,
+ 0x68, 0x87, 0x13, 0x64, 0x6a, 0x10, 0xf7, 0x45, 0xe0, 0x0f, 0x32, 0x21,
+ 0x59, 0x7c, 0x0e, 0x50, 0xad, 0x56, 0xd7, 0x12, 0x69, 0x7b, 0x58, 0xf8,
+ 0xb9, 0x3b, 0xa5, 0xbb, 0x4d, 0x1b, 0x87, 0x1c, 0x46, 0xa7, 0x17, 0x9d,
+ 0x6d, 0x84, 0x45, 0xbe, 0x7f, 0x95, 0xd2, 0x34, 0xcd, 0x89, 0x95, 0xc0,
+ 0xf0, 0xd3, 0xdf, 0x6e, 0x10, 0x4a, 0xe3, 0x7b, 0xce, 0x7f, 0x40, 0x27,
+ 0xc7, 0x2b, 0xab, 0x66, 0x03, 0x59, 0xb4, 0x7b, 0xc7, 0xc7, 0xf0, 0x39,
+ 0x9a, 0x33, 0x35, 0xbf, 0xcc, 0x2f, 0xf3, 0x2e, 0x68, 0x9d, 0x53, 0x5c,
+ 0x88, 0x52, 0xe3, 0x77, 0x90, 0xa1, 0x27, 0x85, 0xc5, 0x74, 0x7f, 0x23,
+ 0x0e, 0x93, 0x01, 0x3e, 0xe7, 0x2e, 0x2e, 0x95, 0xf3, 0x0d, 0xc2, 0x25,
+ 0x25, 0x39, 0x39, 0x3d, 0x6e, 0x8e, 0x89, 0xbd, 0xe8, 0xbb, 0x67, 0x5e,
+ 0x8c, 0x66, 0x8b, 0x63, 0x28, 0x1e, 0x4e, 0x74, 0x85, 0xa8, 0xaf, 0x0f,
+ 0x12, 0x5d, 0xb6, 0x8a, 0x83, 0x1a, 0x77, 0x76, 0x5e, 0x62, 0x8a, 0xa7,
+ 0x3c, 0xb8, 0x05, 0x57, 0x2b, 0xaf, 0x36, 0x2e, 0x10, 0x90, 0xb2, 0x39,
+ 0xb4, 0x3e, 0x75, 0x6d, 0x3a, 0xa8, 0x31, 0x35, 0xc2, 0x1e, 0x8f, 0xc2,
+ 0x79, 0x89, 0x35, 0x16, 0x26, 0xd1, 0xc7, 0x0b, 0x04, 0x1f, 0x1d, 0xf9,
+ 0x9c, 0x05, 0xa6, 0x6b, 0xb5, 0x19, 0x5a, 0x24, 0x6d, 0x91, 0xc5, 0x31,
+ 0xfd, 0xc5, 0xfa, 0xe7, 0xa6, 0xcb, 0x0e, 0x4b, 0x18, 0x0d, 0x94, 0xc7,
+ 0xee, 0x1d, 0x46, 0x1f, 0x92, 0xb1, 0xb2, 0x4a, 0x2b, 0x43, 0x37, 0xfe,
+ 0xc2, 0x15, 0x11, 0x89, 0xef, 0x59, 0x73, 0x3c, 0x06, 0x76, 0x78, 0xcb,
+ 0xa6, 0x0d, 0x79, 0x5f, 0x28, 0x0b, 0x5b, 0x8c, 0x9e, 0xe4, 0xaa, 0x51,
+ 0x9a, 0x42, 0x6f, 0x11, 0x50, 0x3d, 0x01, 0xd6, 0x21, 0xc0, 0x99, 0x5e,
+ 0x1a, 0xe8, 0x81, 0x25, 0x80, 0xeb, 0xed, 0x5d, 0x37, 0x47, 0x30, 0x70,
+ 0xa0, 0x4e, 0x0b, 0x43, 0x17, 0xbe, 0xb6, 0x47, 0xe7, 0x2a, 0x62, 0x9d,
+ 0x5d, 0xa6, 0xc5, 0x33, 0x62, 0x9d, 0x56, 0x24, 0x9d, 0x1d, 0xb2, 0x13,
+ 0xbc, 0x17, 0x66, 0x43, 0xd1, 0x68, 0xd5, 0x3b, 0x17, 0x69, 0x17, 0xa6,
+ 0x06, 0x9e, 0x12, 0xb8, 0x7c, 0xd5, 0xaf, 0x3e, 0x21, 0x1b, 0x31, 0xeb,
+ 0x0b, 0xa4, 0x98, 0x1c, 0xf2, 0x6a, 0x5e, 0x7c, 0x9b, 0x45, 0x8f, 0xb2,
+ 0x12, 0x06, 0xd5, 0x8c, 0x1d, 0xb2, 0xa7, 0x57, 0x5f, 0x2f, 0x4f, 0xdb,
+ 0x52, 0x99, 0x7c, 0x58, 0x01, 0x5f, 0xf2, 0xa5, 0xf6, 0x51, 0x86, 0x21,
+ 0x2f, 0x5b, 0x8d, 0x6a, 0xae, 0x83, 0x34, 0x6d, 0x58, 0x4b, 0xef, 0xfe,
+ 0xbf, 0x73, 0x5d, 0xdb, 0xc4, 0x97, 0x2a, 0x85, 0xf3, 0x6c, 0x46, 0x42,
+ 0xb3, 0x90, 0xc1, 0x57, 0x97, 0x50, 0x35, 0xb1, 0x9d, 0xb7, 0xc7, 0x3c,
+ 0x85, 0x6d, 0x6c, 0xfd, 0xce, 0xb0, 0xc9, 0xa2, 0x77, 0xee, 0xc3, 0x6b,
+ 0x0c, 0x37, 0xfa, 0x30, 0x91, 0xd1, 0x2c, 0xb8, 0x5e, 0x7f, 0x81, 0x5f,
+ 0x87, 0xfd, 0x18, 0x02, 0x5a, 0x30, 0x4e, 0x62, 0xbc, 0x65, 0xc6, 0xce,
+ 0x1a, 0xcf, 0x2b, 0xaa, 0x56, 0x3e, 0x4d, 0xcf, 0xba, 0x62, 0x5f, 0x9a,
+ 0xd0, 0x72, 0xff, 0xef, 0x28, 0xbd, 0xbe, 0xd8, 0x57, 0x3d, 0xf5, 0x57,
+ 0x7d, 0xe9, 0x71, 0x31, 0xec, 0x98, 0x90, 0x94, 0xd9, 0x54, 0xbf, 0x84,
+ 0x0b, 0xe3, 0x06, 0x47, 0x19, 0x9a, 0x13, 0x1d, 0xef, 0x9d, 0x13, 0xf3,
+ 0xdb, 0xc3, 0x5c, 0x72, 0x9e, 0xed, 0x24, 0xaa, 0x64, 0xed, 0xe7, 0x0d,
+ 0xa0, 0x7c, 0x73, 0xba, 0x9b, 0x86, 0xa7, 0x3b, 0x55, 0xab, 0x58, 0x30,
+ 0xf1, 0x15, 0x81, 0x83, 0x2f, 0xf9, 0x62, 0x84, 0x98, 0x66, 0xf6, 0x55,
+ 0x21, 0xd8, 0xf2, 0x25, 0x64, 0x71, 0x4b, 0x12, 0x76, 0x59, 0xc5, 0xaa,
+ 0x93, 0x67, 0xc3, 0x86, 0x25, 0xab, 0x4e, 0x4b, 0xf6, 0xd8, 0x3f, 0x44,
+ 0x2e, 0x11, 0xe0, 0xbd, 0x6a, 0xf2, 0x5d, 0xf5, 0xf9, 0x53, 0xea, 0xa4,
+ 0xc8, 0xd9, 0x50, 0x33, 0x81, 0xd9, 0xa8, 0x2d, 0x91, 0x7d, 0x13, 0x2a,
+ 0x11, 0xcf, 0xde, 0x3f, 0x0a, 0xd2, 0xbc, 0x33, 0xb2, 0x62, 0x53, 0xea,
+ 0x77, 0x88, 0x43, 0x66, 0x27, 0x43, 0x85, 0xe9, 0x5f, 0x55, 0xf5, 0x2a,
+ 0x8a, 0xac, 0xdf, 0xff, 0x9b, 0x4c, 0x96, 0x9c, 0xa5, 0x7a, 0xce, 0xd5,
+ 0x79, 0x18, 0xf1, 0x0b, 0x58, 0x95, 0x7a, 0xe7, 0xd3, 0x74, 0x65, 0x0b,
+ 0xa4, 0x64, 0x30, 0xe8, 0x5c, 0xfc, 0x55, 0x56, 0xee, 0x14, 0x14, 0xd3,
+ 0x45, 0x3b, 0xf8, 0xde, 0x05, 0x3e, 0xb9, 0x3c, 0xd7, 0x6a, 0x52, 0x72,
+ 0x5b, 0x39, 0x09, 0xbe, 0x82, 0x23, 0x10, 0x4a, 0xb7, 0xc3, 0xdc, 0x4c,
+ 0x5d, 0xc9, 0xf1, 0x14, 0x83, 0xf9, 0x0b, 0x9b, 0xe9, 0x23, 0x84, 0x6a,
+ 0xc4, 0x08, 0x3d, 0xda, 0x3d, 0x12, 0x95, 0x87, 0x18, 0xa4, 0x7d, 0x3f,
+ 0x23, 0xde, 0xd4, 0x1e, 0xa8, 0x47, 0xc3, 0x71, 0xdb, 0xf5, 0x03, 0x6c,
+ 0x57, 0xe7, 0xa4, 0x43, 0x82, 0x33, 0x7b, 0x62, 0x46, 0x7d, 0xf7, 0x10,
+ 0x69, 0x18, 0x38, 0x27, 0x9a, 0x6f, 0x38, 0xac, 0xfa, 0x92, 0xc5, 0xae,
+ 0x66, 0xa6, 0x73, 0x95, 0x15, 0x0e, 0x4c, 0x04, 0xb6, 0xfc, 0xf5, 0xc7,
+ 0x21, 0x3a, 0x99, 0xdb, 0x0e, 0x36, 0xf0, 0x56, 0xbc, 0x75, 0xf9, 0x87,
+ 0x9b, 0x11, 0x18, 0x92, 0x64, 0x1a, 0xe7, 0xc7, 0xab, 0x5a, 0xc7, 0x26,
+ 0x7f, 0x13, 0x98, 0x42, 0x52, 0x43, 0xdb, 0xc8, 0x6d, 0x0b, 0xb7, 0x31,
+ 0x93, 0x24, 0xd6, 0xe8, 0x24, 0x1f, 0x6f, 0x21, 0xa7, 0x8c, 0xeb, 0xdb,
+ 0x83, 0xb8, 0x89, 0xe3, 0xc1, 0xd7, 0x69, 0x3b, 0x02, 0x6b, 0x54, 0x0f,
+ 0x84, 0x2f, 0xb5, 0x5c, 0x17, 0x77, 0xbe, 0xe5, 0x61, 0x0d, 0xc5, 0xdf,
+ 0x3b, 0xcf, 0x3e, 0x93, 0x4f, 0xf5, 0x89, 0xb9, 0x5a, 0xc5, 0x29, 0x31,
+ 0xc0, 0xc2, 0xff, 0xe5, 0x3f, 0xa6, 0xac, 0x03, 0xca, 0xf5, 0xff, 0xe0,
+ 0x36, 0xce, 0xf3, 0xe2, 0xb7, 0x9c, 0x02, 0xe9, 0x9e, 0xd2, 0xbc, 0x87,
+ 0x2f, 0x3d, 0x9a, 0x1d, 0x8f, 0xc5, 0x72, 0xb8, 0xa2, 0x01, 0xd4, 0x68,
+ 0xb1, 0x84, 0x16, 0x10, 0xf6, 0xf3, 0x52, 0x25, 0xd9, 0xdc, 0x4c, 0xdd,
+ 0x0f, 0xd6, 0x4a, 0xcf, 0x60, 0x96, 0x7e, 0xcc, 0x42, 0x0f, 0x64, 0x9d,
+ 0x72, 0x46, 0x04, 0x07, 0xf2, 0x5b, 0xf4, 0x07, 0xd1, 0xf4, 0x59, 0x71,
+};
+
+static const uint8_t kSpakeMSmallPrecomp[15 * 2 * 32] = {
+ 0xc8, 0xa6, 0x63, 0xc5, 0x97, 0xf1, 0xee, 0x40, 0xab, 0x62, 0x42, 0xee,
+ 0x25, 0x6f, 0x32, 0x6c, 0x75, 0x2c, 0xa7, 0xd3, 0xbd, 0x32, 0x3b, 0x1e,
+ 0x11, 0x9c, 0xbd, 0x04, 0xa9, 0x78, 0x6f, 0x45, 0x5a, 0xda, 0x7e, 0x4b,
+ 0xf6, 0xdd, 0xd9, 0xad, 0xb6, 0x62, 0x6d, 0x32, 0x13, 0x1c, 0x6b, 0x5c,
+ 0x51, 0xa1, 0xe3, 0x47, 0xa3, 0x47, 0x8f, 0x53, 0xcf, 0xcf, 0x44, 0x1b,
+ 0x88, 0xee, 0xd1, 0x2e, 0x03, 0x89, 0xaf, 0xc0, 0x61, 0x2d, 0x9e, 0x35,
+ 0xeb, 0x0e, 0x03, 0xe0, 0xb7, 0xfb, 0xa5, 0xbc, 0x44, 0xbe, 0x0c, 0x89,
+ 0x0a, 0x0f, 0xd6, 0x59, 0x47, 0x9e, 0xe6, 0x3d, 0x36, 0x9d, 0xff, 0x44,
+ 0x5e, 0xac, 0xab, 0xe5, 0x3a, 0xd5, 0xb0, 0x35, 0x9f, 0x6d, 0x7f, 0xba,
+ 0xc0, 0x85, 0x0e, 0xf4, 0x70, 0x3f, 0x13, 0x90, 0x4c, 0x50, 0x1a, 0xee,
+ 0xc5, 0xeb, 0x69, 0xfe, 0x98, 0x42, 0x87, 0x1d, 0xce, 0x6c, 0x29, 0xaa,
+ 0x2b, 0x31, 0xc2, 0x38, 0x7b, 0x6b, 0xee, 0x88, 0x0b, 0xba, 0xce, 0xa8,
+ 0xca, 0x19, 0x60, 0x1b, 0x16, 0xf1, 0x25, 0x1e, 0xcf, 0x63, 0x66, 0x1e,
+ 0xbb, 0x63, 0xeb, 0x7d, 0xca, 0xd2, 0xb4, 0x23, 0x5a, 0x01, 0x6f, 0x05,
+ 0xd1, 0xdc, 0x41, 0x73, 0x75, 0xc0, 0xfd, 0x30, 0x91, 0x52, 0x68, 0x96,
+ 0x45, 0xb3, 0x66, 0x01, 0x3b, 0x53, 0x89, 0x3c, 0x69, 0xbc, 0x6c, 0x69,
+ 0xe3, 0x51, 0x8f, 0xe3, 0xd2, 0x84, 0xd5, 0x28, 0x66, 0xb5, 0xe6, 0x06,
+ 0x09, 0xfe, 0x6d, 0xb0, 0x72, 0x16, 0xe0, 0x8a, 0xce, 0x61, 0x65, 0xa9,
+ 0x21, 0x32, 0x48, 0xdc, 0x7a, 0x1d, 0xe1, 0x38, 0x7f, 0x8c, 0x75, 0x88,
+ 0x3d, 0x08, 0xa9, 0x4a, 0x6f, 0x3d, 0x9f, 0x7f, 0x3f, 0xbd, 0x57, 0x6b,
+ 0x19, 0xce, 0x3f, 0x4a, 0xc9, 0xd3, 0xf9, 0x6e, 0x72, 0x7b, 0x5b, 0x74,
+ 0xea, 0xbe, 0x9c, 0x7a, 0x6d, 0x9c, 0x40, 0x49, 0xe6, 0xfb, 0x2a, 0x1a,
+ 0x75, 0x70, 0xe5, 0x4e, 0xed, 0x74, 0xe0, 0x75, 0xac, 0xc0, 0xb1, 0x11,
+ 0x3e, 0xf2, 0xaf, 0x88, 0x4d, 0x66, 0xb6, 0xf6, 0x15, 0x4f, 0x3c, 0x6c,
+ 0x77, 0xae, 0x47, 0x51, 0x63, 0x9a, 0xfe, 0xe1, 0xb4, 0x1a, 0x12, 0xdf,
+ 0xe9, 0x54, 0x8d, 0x3b, 0x30, 0x2a, 0x75, 0xe3, 0xe5, 0x29, 0xb1, 0x4c,
+ 0xb0, 0x7c, 0x6d, 0xb5, 0xae, 0x85, 0xdb, 0x1e, 0x38, 0x55, 0x96, 0xa5,
+ 0x5b, 0x9f, 0x15, 0x23, 0x28, 0x36, 0xb8, 0xa2, 0x41, 0xb4, 0xd7, 0x19,
+ 0x91, 0x8d, 0x26, 0x3e, 0xca, 0x9c, 0x05, 0x7a, 0x2b, 0x60, 0x45, 0x86,
+ 0x8b, 0xee, 0x64, 0x6f, 0x5c, 0x09, 0x4d, 0x4b, 0x5a, 0x7f, 0xb0, 0xc3,
+ 0x26, 0x9d, 0x8b, 0xb8, 0x83, 0x69, 0xcf, 0x16, 0x72, 0x62, 0x3e, 0x5e,
+ 0x53, 0x4f, 0x9c, 0x73, 0x76, 0xfc, 0x19, 0xef, 0xa0, 0x74, 0x3a, 0x11,
+ 0x1e, 0xd0, 0x4d, 0xb7, 0x87, 0xa1, 0xd6, 0x87, 0x6c, 0x0e, 0x6c, 0x8c,
+ 0xe9, 0xa0, 0x44, 0xc4, 0x72, 0x3e, 0x73, 0x17, 0x13, 0xd1, 0x4e, 0x3d,
+ 0x8e, 0x1d, 0x5a, 0x8b, 0x75, 0xcb, 0x59, 0x2c, 0x47, 0x87, 0x15, 0x41,
+ 0xfe, 0x08, 0xe9, 0xa6, 0x97, 0x17, 0x08, 0x26, 0x6a, 0xb5, 0xbb, 0x73,
+ 0xaa, 0xb8, 0x5b, 0x65, 0x65, 0x5b, 0x30, 0x9e, 0x62, 0x59, 0x02, 0xf8,
+ 0xb8, 0x0f, 0x32, 0x10, 0xc1, 0x36, 0x08, 0x52, 0x98, 0x4a, 0x1e, 0xf0,
+ 0xab, 0x21, 0x5e, 0xde, 0x16, 0x0c, 0xda, 0x09, 0x99, 0x6b, 0x9e, 0xc0,
+ 0x90, 0xa5, 0x5a, 0xcc, 0xb0, 0xb7, 0xbb, 0xd2, 0x8b, 0x5f, 0xd3, 0x3b,
+ 0x3e, 0x8c, 0xa5, 0x71, 0x66, 0x06, 0xe3, 0x28, 0xd4, 0xf8, 0x3f, 0xe5,
+ 0x27, 0xdf, 0xfe, 0x0f, 0x09, 0xb2, 0x8a, 0x09, 0x5a, 0x23, 0x61, 0x0d,
+ 0x2d, 0xf5, 0x44, 0xf1, 0x5c, 0xf8, 0x82, 0x4e, 0xdc, 0x78, 0x7a, 0xab,
+ 0xc3, 0x57, 0x91, 0xaf, 0x65, 0x6e, 0x71, 0xf1, 0x44, 0xbf, 0xed, 0x43,
+ 0x50, 0xb4, 0x67, 0x48, 0xef, 0x5a, 0x10, 0x46, 0x81, 0xb4, 0x0c, 0xc8,
+ 0x48, 0xed, 0x99, 0x7a, 0x45, 0xa5, 0x92, 0xc3, 0x69, 0xd6, 0xd7, 0x8a,
+ 0x20, 0x1b, 0xeb, 0x8f, 0xb2, 0xff, 0xec, 0x6d, 0x76, 0x04, 0xf8, 0xc2,
+ 0x58, 0x9b, 0xf2, 0x20, 0x53, 0xc4, 0x74, 0x91, 0x19, 0xdd, 0x2d, 0x12,
+ 0x53, 0xc7, 0x6e, 0xd0, 0x02, 0x51, 0x3c, 0xa6, 0x7d, 0x80, 0x75, 0x6b,
+ 0x1d, 0xdf, 0xf8, 0x6a, 0x52, 0xbb, 0x81, 0xf8, 0x30, 0x45, 0xef, 0x51,
+ 0x85, 0x36, 0xbe, 0x8e, 0xcf, 0x0b, 0x9a, 0x46, 0xe8, 0x3f, 0x99, 0xfd,
+ 0xf7, 0xd9, 0x3e, 0x84, 0xe5, 0xe3, 0x37, 0xcf, 0x98, 0x7f, 0xeb, 0x5e,
+ 0x5a, 0x53, 0x77, 0x1c, 0x20, 0xdc, 0xf1, 0x20, 0x99, 0xec, 0x60, 0x40,
+ 0x93, 0xef, 0x5c, 0x1c, 0x81, 0xe2, 0xa5, 0xad, 0x2a, 0xc2, 0xdb, 0x6b,
+ 0xc1, 0x7e, 0x8f, 0xa9, 0x23, 0x5b, 0xd9, 0x0d, 0xfe, 0xa0, 0xac, 0x11,
+ 0x28, 0xba, 0x8e, 0x92, 0x07, 0x2d, 0x07, 0x40, 0x83, 0x14, 0x4c, 0x35,
+ 0x8d, 0xd0, 0x11, 0xff, 0x98, 0xdb, 0x00, 0x30, 0x6f, 0x65, 0xb6, 0xa0,
+ 0x7f, 0x9c, 0x08, 0xb8, 0xce, 0xb3, 0xa8, 0x42, 0xd3, 0x84, 0x45, 0xe1,
+ 0xe3, 0x8f, 0xa6, 0x89, 0x21, 0xd7, 0x74, 0x02, 0x4d, 0x64, 0xdf, 0x54,
+ 0x15, 0x9e, 0xba, 0x12, 0x49, 0x09, 0x41, 0xf6, 0x10, 0x24, 0xa1, 0x84,
+ 0x15, 0xfd, 0x68, 0x6a, 0x57, 0x66, 0xb3, 0x6d, 0x4c, 0xea, 0xbf, 0xbc,
+ 0x60, 0x3f, 0x52, 0x1c, 0x44, 0x1b, 0xc0, 0x4a, 0x25, 0xe3, 0xd9, 0x4c,
+ 0x9a, 0x74, 0xad, 0xfc, 0x9e, 0x8d, 0x0b, 0x18, 0x66, 0x24, 0xd1, 0x06,
+ 0xac, 0x68, 0xc1, 0xae, 0x14, 0xce, 0xb1, 0xf3, 0x86, 0x9f, 0x87, 0x11,
+ 0xd7, 0x9f, 0x30, 0x92, 0xdb, 0xec, 0x0b, 0x4a, 0xe8, 0xf6, 0x53, 0x36,
+ 0x68, 0x12, 0x11, 0x5e, 0xe0, 0x34, 0xa4, 0xff, 0x00, 0x0a, 0x26, 0xb8,
+ 0x62, 0x79, 0x9c, 0x0c, 0xd5, 0xe5, 0xf5, 0x1c, 0x1a, 0x16, 0x84, 0x4d,
+ 0x8e, 0x5d, 0x31, 0x7e, 0xf7, 0xe2, 0xd3, 0xa1, 0x41, 0x90, 0x61, 0x5d,
+ 0x04, 0xb2, 0x9a, 0x18, 0x9e, 0x54, 0xfb, 0xd1, 0x61, 0x95, 0x1b, 0x08,
+ 0xca, 0x7c, 0x49, 0x44, 0x74, 0x1d, 0x2f, 0xca, 0xc4, 0x7a, 0xe1, 0x8b,
+ 0x2f, 0xbb, 0x96, 0xee, 0x19, 0x8a, 0x5d, 0xfb, 0x3e, 0x82, 0xe7, 0x15,
+ 0xdb, 0x29, 0x14, 0xee, 0xc9, 0x4d, 0x9a, 0xfb, 0x9f, 0x8a, 0xbb, 0x17,
+ 0x37, 0x1b, 0x6e, 0x28, 0x6c, 0xf9, 0xff, 0xb5, 0xb5, 0x8b, 0x9d, 0x88,
+ 0x20, 0x08, 0x10, 0xd7, 0xca, 0x58, 0xf6, 0xe1, 0x32, 0x91, 0x6f, 0x36,
+ 0xc0, 0xad, 0xc1, 0x57, 0x5d, 0x76, 0x31, 0x43, 0xf3, 0xdd, 0xec, 0xf1,
+ 0xa9, 0x79, 0xe9, 0xe9, 0x85, 0xd7, 0x91, 0xc7, 0x31, 0x62, 0x3c, 0xd2,
+ 0x90, 0x2c, 0x9c, 0xa4, 0x56, 0x37, 0x7b, 0xbe, 0x40, 0x58, 0xc0, 0x81,
+ 0x83, 0x22, 0xe8, 0x13, 0x79, 0x18, 0xdb, 0x3a, 0x1b, 0x31, 0x0d, 0x00,
+ 0x6c, 0x22, 0x62, 0x75, 0x70, 0xd8, 0x96, 0x59, 0x99, 0x44, 0x79, 0x71,
+ 0xa6, 0x76, 0x81, 0x28, 0xb2, 0x65, 0xe8, 0x47, 0x14, 0xc6, 0x39, 0x06,
+};
+
+enum spake2_state_t {
+ spake2_state_init = 0,
+ spake2_state_msg_generated,
+ spake2_state_key_generated,
+};
+
+struct spake2_ctx_st {
+ uint8_t private_key[32];
+ uint8_t my_msg[32];
+ uint8_t password_scalar[32];
+ uint8_t password_hash[SHA512_DIGEST_LENGTH];
+ uint8_t *my_name;
+ size_t my_name_len;
+ uint8_t *their_name;
+ size_t their_name_len;
+ enum spake2_role_t my_role;
+ enum spake2_state_t state;
+};
+
+SPAKE2_CTX *SPAKE2_CTX_new(enum spake2_role_t my_role,
+ const uint8_t *my_name, size_t my_name_len,
+ const uint8_t *their_name, size_t their_name_len) {
+ SPAKE2_CTX *ctx = OPENSSL_malloc(sizeof(SPAKE2_CTX));
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ memset(ctx, 0, sizeof(SPAKE2_CTX));
+ ctx->my_role = my_role;
+
+ CBS my_name_cbs, their_name_cbs;
+ CBS_init(&my_name_cbs, my_name, my_name_len);
+ CBS_init(&their_name_cbs, their_name, their_name_len);
+ if (!CBS_stow(&my_name_cbs, &ctx->my_name, &ctx->my_name_len) ||
+ !CBS_stow(&their_name_cbs, &ctx->their_name, &ctx->their_name_len)) {
+ SPAKE2_CTX_free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+void SPAKE2_CTX_free(SPAKE2_CTX *ctx) {
+ if (ctx == NULL) {
+ return;
+ }
+
+ OPENSSL_free(ctx->my_name);
+ OPENSSL_free(ctx->their_name);
+ OPENSSL_free(ctx);
+}
+
+/* left_shift_3 sets |n| to |n|*8, where |n| is represented in little-endian
+ * order. */
+static void left_shift_3(uint8_t n[32]) {
+ uint8_t carry = 0;
+ unsigned i;
+
+ for (i = 0; i < 32; i++) {
+ const uint8_t next_carry = n[i] >> 5;
+ n[i] = (n[i] << 3) | carry;
+ carry = next_carry;
+ }
+}
+
+int SPAKE2_generate_msg(SPAKE2_CTX *ctx, uint8_t *out, size_t *out_len,
+ size_t max_out_len, const uint8_t *password,
+ size_t password_len) {
+ if (ctx->state != spake2_state_init) {
+ return 0;
+ }
+
+ if (max_out_len < sizeof(ctx->my_msg)) {
+ return 0;
+ }
+
+ uint8_t private_tmp[64];
+ RAND_bytes(private_tmp, sizeof(private_tmp));
+ x25519_sc_reduce(private_tmp);
+ /* Multiply by the cofactor (eight) so that we'll clear it when operating on
+ * the peer's point later in the protocol. */
+ left_shift_3(private_tmp);
+ memcpy(ctx->private_key, private_tmp, sizeof(ctx->private_key));
+
+ ge_p3 P;
+ x25519_ge_scalarmult_base(&P, ctx->private_key);
+
+ /* mask = h(password) * <N or M>. */
+ uint8_t password_tmp[SHA512_DIGEST_LENGTH];
+ SHA512(password, password_len, password_tmp);
+ memcpy(ctx->password_hash, password_tmp, sizeof(ctx->password_hash));
+ x25519_sc_reduce(password_tmp);
+ memcpy(ctx->password_scalar, password_tmp, sizeof(ctx->password_scalar));
+
+ ge_p3 mask;
+ x25519_ge_scalarmult_small_precomp(&mask, ctx->password_scalar,
+ ctx->my_role == spake2_role_alice
+ ? kSpakeMSmallPrecomp
+ : kSpakeNSmallPrecomp);
+
+ /* P* = P + mask. */
+ ge_cached mask_cached;
+ x25519_ge_p3_to_cached(&mask_cached, &mask);
+ ge_p1p1 Pstar;
+ x25519_ge_add(&Pstar, &P, &mask_cached);
+
+ /* Encode P* */
+ ge_p2 Pstar_proj;
+ x25519_ge_p1p1_to_p2(&Pstar_proj, &Pstar);
+ x25519_ge_tobytes(ctx->my_msg, &Pstar_proj);
+
+ memcpy(out, ctx->my_msg, sizeof(ctx->my_msg));
+ *out_len = sizeof(ctx->my_msg);
+ ctx->state = spake2_state_msg_generated;
+
+ return 1;
+}
+
+static void update_with_length_prefix(SHA512_CTX *sha, const uint8_t *data,
+ const size_t len) {
+ uint8_t len_le[8];
+ size_t l = len;
+ unsigned i;
+
+ for (i = 0; i < 8; i++) {
+ len_le[i] = l & 0xff;
+ l >>= 8;
+ }
+
+ SHA512_Update(sha, len_le, sizeof(len_le));
+ SHA512_Update(sha, data, len);
+}
+
+int SPAKE2_process_msg(SPAKE2_CTX *ctx, uint8_t *out_key, size_t *out_key_len,
+ size_t max_out_key_len, const uint8_t *their_msg,
+ size_t their_msg_len) {
+ if (ctx->state != spake2_state_msg_generated ||
+ their_msg_len != 32) {
+ return 0;
+ }
+
+ ge_p3 Qstar;
+ if (0 != x25519_ge_frombytes_vartime(&Qstar, their_msg)) {
+ /* Point received from peer was not on the curve. */
+ return 0;
+ }
+
+ /* Unmask peer's value. */
+ ge_p3 peers_mask;
+ x25519_ge_scalarmult_small_precomp(&peers_mask, ctx->password_scalar,
+ ctx->my_role == spake2_role_alice
+ ? kSpakeNSmallPrecomp
+ : kSpakeMSmallPrecomp);
+
+ ge_cached peers_mask_cached;
+ x25519_ge_p3_to_cached(&peers_mask_cached, &peers_mask);
+
+ ge_p1p1 Q_compl;
+ ge_p3 Q_ext;
+ x25519_ge_sub(&Q_compl, &Qstar, &peers_mask_cached);
+ x25519_ge_p1p1_to_p3(&Q_ext, &Q_compl);
+
+ ge_p2 dh_shared;
+ x25519_ge_scalarmult(&dh_shared, ctx->private_key, &Q_ext);
+
+ uint8_t dh_shared_encoded[32];
+ x25519_ge_tobytes(dh_shared_encoded, &dh_shared);
+
+ SHA512_CTX sha;
+ SHA512_Init(&sha);
+ if (ctx->my_role == spake2_role_alice) {
+ update_with_length_prefix(&sha, ctx->my_name, ctx->my_name_len);
+ update_with_length_prefix(&sha, ctx->their_name, ctx->their_name_len);
+ update_with_length_prefix(&sha, ctx->my_msg, sizeof(ctx->my_msg));
+ update_with_length_prefix(&sha, their_msg, 32);
+ } else {
+ update_with_length_prefix(&sha, ctx->their_name, ctx->their_name_len);
+ update_with_length_prefix(&sha, ctx->my_name, ctx->my_name_len);
+ update_with_length_prefix(&sha, their_msg, 32);
+ update_with_length_prefix(&sha, ctx->my_msg, sizeof(ctx->my_msg));
+ }
+ update_with_length_prefix(&sha, dh_shared_encoded, sizeof(dh_shared_encoded));
+ update_with_length_prefix(&sha, ctx->password_hash,
+ sizeof(ctx->password_hash));
+
+ uint8_t key[SHA512_DIGEST_LENGTH];
+ SHA512_Final(key, &sha);
+
+ size_t to_copy = max_out_key_len;
+ if (to_copy > sizeof(key)) {
+ to_copy = sizeof(key);
+ }
+ memcpy(out_key, key, to_copy);
+ *out_key_len = to_copy;
+ ctx->state = spake2_state_key_generated;
+
+ return 1;
+}
diff --git a/crypto/curve25519/spake25519_test.cc b/crypto/curve25519/spake25519_test.cc
new file mode 100644
index 00000000..d97a8602
--- /dev/null
+++ b/crypto/curve25519/spake25519_test.cc
@@ -0,0 +1,169 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <string>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/curve25519.h>
+#include "../test/scoped_types.h"
+
+
+struct SPAKE2Run {
+ bool Run() {
+ ScopedSPAKE2_CTX alice(SPAKE2_CTX_new(
+ spake2_role_alice,
+ reinterpret_cast<const uint8_t *>(alice_names.first.data()),
+ alice_names.first.size(),
+ reinterpret_cast<const uint8_t *>(alice_names.second.data()),
+ alice_names.second.size()));
+ ScopedSPAKE2_CTX bob(SPAKE2_CTX_new(
+ spake2_role_bob,
+ reinterpret_cast<const uint8_t *>(bob_names.first.data()),
+ bob_names.first.size(),
+ reinterpret_cast<const uint8_t *>(bob_names.second.data()),
+ bob_names.second.size()));
+
+ if (!alice || !bob) {
+ return false;
+ }
+
+ uint8_t alice_msg[SPAKE2_MAX_MSG_SIZE];
+ uint8_t bob_msg[SPAKE2_MAX_MSG_SIZE];
+ size_t alice_msg_len, bob_msg_len;
+
+ if (!SPAKE2_generate_msg(
+ alice.get(), alice_msg, &alice_msg_len, sizeof(alice_msg),
+ reinterpret_cast<const uint8_t *>(alice_password.data()),
+ alice_password.size()) ||
+ !SPAKE2_generate_msg(
+ bob.get(), bob_msg, &bob_msg_len, sizeof(bob_msg),
+ reinterpret_cast<const uint8_t *>(bob_password.data()),
+ bob_password.size())) {
+ return false;
+ }
+
+ if (alice_corrupt_msg_bit >= 0 &&
+ static_cast<size_t>(alice_corrupt_msg_bit) < 8 * alice_msg_len) {
+ alice_msg[alice_corrupt_msg_bit/8] ^= 1 << (alice_corrupt_msg_bit & 7);
+ }
+
+ uint8_t alice_key[64], bob_key[64];
+ size_t alice_key_len, bob_key_len;
+
+ if (!SPAKE2_process_msg(alice.get(), alice_key, &alice_key_len,
+ sizeof(alice_key), bob_msg, bob_msg_len) ||
+ !SPAKE2_process_msg(bob.get(), bob_key, &bob_key_len, sizeof(bob_key),
+ alice_msg, alice_msg_len)) {
+ return false;
+ }
+
+ key_matches_ = (alice_key_len == bob_key_len &&
+ memcmp(alice_key, bob_key, alice_key_len) == 0);
+
+ return true;
+ }
+
+ bool key_matches() const {
+ return key_matches_;
+ }
+
+ std::string alice_password = "password";
+ std::string bob_password = "password";
+ std::pair<std::string, std::string> alice_names = {"alice", "bob"};
+ std::pair<std::string, std::string> bob_names = {"bob", "alice"};
+ int alice_corrupt_msg_bit = -1;
+
+ private:
+ bool key_matches_ = false;
+};
+
+static bool TestSPAKE2() {
+ for (unsigned i = 0; i < 20; i++) {
+ SPAKE2Run spake2;
+ if (!spake2.Run()) {
+ fprintf(stderr, "TestSPAKE2: SPAKE2 failed.\n");
+ return false;
+ }
+
+ if (!spake2.key_matches()) {
+ fprintf(stderr, "Key didn't match for equal passwords.\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool TestWrongPassword() {
+ SPAKE2Run spake2;
+ spake2.bob_password = "wrong password";
+ if (!spake2.Run()) {
+ fprintf(stderr, "TestSPAKE2: SPAKE2 failed.\n");
+ return false;
+ }
+
+ if (spake2.key_matches()) {
+ fprintf(stderr, "Key matched for unequal passwords.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestWrongNames() {
+ SPAKE2Run spake2;
+ spake2.alice_names.second = "charlie";
+ spake2.bob_names.second = "charlie";
+ if (!spake2.Run()) {
+ fprintf(stderr, "TestSPAKE2: SPAKE2 failed.\n");
+ return false;
+ }
+
+ if (spake2.key_matches()) {
+ fprintf(stderr, "Key matched for unequal names.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestCorruptMessages() {
+ for (int i = 0; i < 8 * SPAKE2_MAX_MSG_SIZE; i++) {
+ SPAKE2Run spake2;
+ spake2.alice_corrupt_msg_bit = i;
+ if (spake2.Run() && spake2.key_matches()) {
+ fprintf(stderr, "Passed after corrupting Alice's message, bit %d\n", i);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* TODO(agl): add tests with fixed vectors once SPAKE2 is nailed down. */
+
+int main(int argc, char **argv) {
+ if (!TestSPAKE2() ||
+ !TestWrongPassword() ||
+ !TestWrongNames() ||
+ !TestCorruptMessages()) {
+ return 1;
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/curve25519/x25519-x86_64.c b/crypto/curve25519/x25519-x86_64.c
index 9776c755..1bd86a09 100644
--- a/crypto/curve25519/x25519-x86_64.c
+++ b/crypto/curve25519/x25519-x86_64.c
@@ -1,3 +1,24 @@
+/* Copyright (c) 2015, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+/* This code is mostly taken from the ref10 version of Ed25519 in SUPERCOP
+ * 20141124 (http://bench.cr.yp.to/supercop.html). That code is released as
+ * public domain but this file has the ISC license just to keep licencing
+ * simple.
+ *
+ * The field functions are shared by Ed25519 and X25519 where possible. */
+
#include <openssl/curve25519.h>
#include <string.h>
diff --git a/crypto/dh/dh.c b/crypto/dh/dh.c
index aed8720b..94eb3643 100644
--- a/crypto/dh/dh.c
+++ b/crypto/dh/dh.c
@@ -236,7 +236,6 @@ int DH_generate_key(DH *dh) {
int generate_new_key = 0;
unsigned l;
BN_CTX *ctx = NULL;
- BN_MONT_CTX *mont = NULL;
BIGNUM *pub_key = NULL, *priv_key = NULL;
BIGNUM local_priv;
@@ -269,9 +268,8 @@ int DH_generate_key(DH *dh) {
pub_key = dh->pub_key;
}
- mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock,
- dh->p, ctx);
- if (!mont) {
+ if (!BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock,
+ dh->p, ctx)) {
goto err;
}
@@ -293,7 +291,8 @@ int DH_generate_key(DH *dh) {
}
BN_with_flags(&local_priv, priv_key, BN_FLG_CONSTTIME);
- if (!BN_mod_exp_mont(pub_key, dh->g, &local_priv, dh->p, ctx, mont)) {
+ if (!BN_mod_exp_mont_consttime(pub_key, dh->g, &local_priv, dh->p, ctx,
+ dh->method_mont_p)) {
goto err;
}
@@ -318,7 +317,6 @@ err:
int DH_compute_key(unsigned char *out, const BIGNUM *peers_key, DH *dh) {
BN_CTX *ctx = NULL;
- BN_MONT_CTX *mont = NULL;
BIGNUM *shared_key;
int ret = -1;
int check_result;
@@ -344,9 +342,8 @@ int DH_compute_key(unsigned char *out, const BIGNUM *peers_key, DH *dh) {
goto err;
}
- mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock,
- dh->p, ctx);
- if (!mont) {
+ if (!BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock,
+ dh->p, ctx)) {
goto err;
}
@@ -356,8 +353,8 @@ int DH_compute_key(unsigned char *out, const BIGNUM *peers_key, DH *dh) {
}
BN_with_flags(&local_priv, dh->priv_key, BN_FLG_CONSTTIME);
- if (!BN_mod_exp_mont(shared_key, peers_key, &local_priv, dh->p, ctx,
- mont)) {
+ if (!BN_mod_exp_mont_consttime(shared_key, peers_key, &local_priv, dh->p, ctx,
+ dh->method_mont_p)) {
OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB);
goto err;
}
diff --git a/crypto/dh/dh_asn1.c b/crypto/dh/dh_asn1.c
index 73cd4df7..1a147eea 100644
--- a/crypto/dh/dh_asn1.c
+++ b/crypto/dh/dh_asn1.c
@@ -55,30 +55,106 @@
#include <openssl/dh.h>
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
-
-#include "internal.h"
-
-/* Override the default free and new methods */
-static int dh_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
- void *exarg) {
- if (operation == ASN1_OP_NEW_PRE) {
- *pval = (ASN1_VALUE *)DH_new();
- if (*pval) {
- return 2;
+#include <assert.h>
+#include <limits.h>
+
+#include <openssl/bn.h>
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+
+#include "../bytestring/internal.h"
+
+
+static int parse_integer(CBS *cbs, BIGNUM **out) {
+ assert(*out == NULL);
+ *out = BN_new();
+ if (*out == NULL) {
+ return 0;
+ }
+ return BN_parse_asn1_unsigned(cbs, *out);
+}
+
+static int marshal_integer(CBB *cbb, BIGNUM *bn) {
+ if (bn == NULL) {
+ /* A DH object may be missing some components. */
+ OPENSSL_PUT_ERROR(DH, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ return BN_marshal_asn1(cbb, bn);
+}
+
+DH *DH_parse_parameters(CBS *cbs) {
+ DH *ret = DH_new();
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ CBS child;
+ if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) ||
+ !parse_integer(&child, &ret->p) ||
+ !parse_integer(&child, &ret->g)) {
+ goto err;
+ }
+
+ uint64_t priv_length;
+ if (CBS_len(&child) != 0) {
+ if (!CBS_get_asn1_uint64(&child, &priv_length) ||
+ priv_length > UINT_MAX) {
+ goto err;
}
+ ret->priv_length = (unsigned)priv_length;
+ }
+
+ if (CBS_len(&child) != 0) {
+ goto err;
+ }
+
+ return ret;
+
+err:
+ OPENSSL_PUT_ERROR(DH, DH_R_DECODE_ERROR);
+ DH_free(ret);
+ return NULL;
+}
+
+int DH_marshal_parameters(CBB *cbb, const DH *dh) {
+ CBB child;
+ if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) ||
+ !marshal_integer(&child, dh->p) ||
+ !marshal_integer(&child, dh->g) ||
+ (dh->priv_length != 0 &&
+ !CBB_add_asn1_uint64(&child, dh->priv_length)) ||
+ !CBB_flush(cbb)) {
+ OPENSSL_PUT_ERROR(DH, DH_R_ENCODE_ERROR);
return 0;
- } else if (operation == ASN1_OP_FREE_PRE) {
- DH_free((DH *)*pval);
- *pval = NULL;
- return 2;
}
return 1;
}
-ASN1_SEQUENCE_cb(DHparams, dh_cb) = {
- ASN1_SIMPLE(DH, p, BIGNUM), ASN1_SIMPLE(DH, g, BIGNUM),
- ASN1_OPT(DH, priv_length, ZLONG)} ASN1_SEQUENCE_END_cb(DH, DHparams);
+DH *d2i_DHparams(DH **out, const uint8_t **inp, long len) {
+ if (len < 0) {
+ return NULL;
+ }
+ CBS cbs;
+ CBS_init(&cbs, *inp, (size_t)len);
+ DH *ret = DH_parse_parameters(&cbs);
+ if (ret == NULL) {
+ return NULL;
+ }
+ if (out != NULL) {
+ DH_free(*out);
+ *out = ret;
+ }
+ *inp = CBS_data(&cbs);
+ return ret;
+}
-IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DH, DHparams, DHparams)
+int i2d_DHparams(const DH *in, uint8_t **outp) {
+ CBB cbb;
+ if (!CBB_init(&cbb, 0) ||
+ !DH_marshal_parameters(&cbb, in)) {
+ CBB_cleanup(&cbb);
+ return -1;
+ }
+ return CBB_finish_i2d(&cbb, outp);
+}
diff --git a/crypto/dh/dh_test.cc b/crypto/dh/dh_test.cc
index 885bd32b..1c244283 100644
--- a/crypto/dh/dh_test.cc
+++ b/crypto/dh/dh_test.cc
@@ -62,6 +62,7 @@
#include <vector>
#include <openssl/bn.h>
+#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/mem.h>
@@ -73,13 +74,15 @@
static bool RunBasicTests();
static bool RunRFC5114Tests();
static bool TestBadY();
+static bool TestASN1();
int main(int argc, char *argv[]) {
CRYPTO_library_init();
if (!RunBasicTests() ||
!RunRFC5114Tests() ||
- !TestBadY()) {
+ !TestBadY() ||
+ !TestASN1()) {
ERR_print_errors_fp(stderr);
return 1;
}
@@ -533,3 +536,91 @@ static bool TestBadY() {
return true;
}
+
+static bool BIGNUMEqualsHex(const BIGNUM *bn, const char *hex) {
+ BIGNUM *hex_bn = NULL;
+ if (!BN_hex2bn(&hex_bn, hex)) {
+ return false;
+ }
+ ScopedBIGNUM free_hex_bn(hex_bn);
+ return BN_cmp(bn, hex_bn) == 0;
+}
+
+static bool TestASN1() {
+ // kParams are a set of Diffie-Hellman parameters generated with
+ // openssl dhparam 256
+ static const uint8_t kParams[] = {
+ 0x30, 0x26, 0x02, 0x21, 0x00, 0xd7, 0x20, 0x34, 0xa3, 0x27,
+ 0x4f, 0xdf, 0xbf, 0x04, 0xfd, 0x24, 0x68, 0x25, 0xb6, 0x56,
+ 0xd8, 0xab, 0x2a, 0x41, 0x2d, 0x74, 0x0a, 0x52, 0x08, 0x7c,
+ 0x40, 0x71, 0x4e, 0xd2, 0x57, 0x93, 0x13, 0x02, 0x01, 0x02,
+ };
+
+ CBS cbs;
+ CBS_init(&cbs, kParams, sizeof(kParams));
+ ScopedDH dh(DH_parse_parameters(&cbs));
+ if (!dh || CBS_len(&cbs) != 0 ||
+ !BIGNUMEqualsHex(
+ dh->p,
+ "d72034a3274fdfbf04fd246825b656d8ab2a412d740a52087c40714ed2579313") ||
+ !BIGNUMEqualsHex(dh->g, "2") || dh->priv_length != 0) {
+ return false;
+ }
+
+ ScopedCBB cbb;
+ uint8_t *der;
+ size_t der_len;
+ if (!CBB_init(cbb.get(), 0) ||
+ !DH_marshal_parameters(cbb.get(), dh.get()) ||
+ !CBB_finish(cbb.get(), &der, &der_len)) {
+ return false;
+ }
+ ScopedOpenSSLBytes free_der(der);
+ if (der_len != sizeof(kParams) || memcmp(der, kParams, der_len) != 0) {
+ return false;
+ }
+
+ // kParamsDSA are a set of Diffie-Hellman parameters generated with
+ // openssl dhparam 256 -dsaparam
+ static const uint8_t kParamsDSA[] = {
+ 0x30, 0x81, 0x89, 0x02, 0x41, 0x00, 0x93, 0xf3, 0xc1, 0x18, 0x01, 0xe6,
+ 0x62, 0xb6, 0xd1, 0x46, 0x9a, 0x2c, 0x72, 0xea, 0x31, 0xd9, 0x18, 0x10,
+ 0x30, 0x28, 0x63, 0xe2, 0x34, 0x7d, 0x80, 0xca, 0xee, 0x82, 0x2b, 0x19,
+ 0x3c, 0x19, 0xbb, 0x42, 0x83, 0x02, 0x70, 0xdd, 0xdb, 0x8c, 0x03, 0xab,
+ 0xe9, 0x9c, 0xc4, 0x00, 0x4d, 0x70, 0x5f, 0x52, 0x03, 0x31, 0x2c, 0xa4,
+ 0x67, 0x34, 0x51, 0x95, 0x2a, 0xac, 0x11, 0xe2, 0x6a, 0x55, 0x02, 0x40,
+ 0x44, 0xc8, 0x10, 0x53, 0x44, 0x32, 0x31, 0x63, 0xd8, 0xd1, 0x8c, 0x75,
+ 0xc8, 0x98, 0x53, 0x3b, 0x5b, 0x4a, 0x2a, 0x0a, 0x09, 0xe7, 0xd0, 0x3c,
+ 0x53, 0x72, 0xa8, 0x6b, 0x70, 0x41, 0x9c, 0x26, 0x71, 0x44, 0xfc, 0x7f,
+ 0x08, 0x75, 0xe1, 0x02, 0xab, 0x74, 0x41, 0xe8, 0x2a, 0x3d, 0x3c, 0x26,
+ 0x33, 0x09, 0xe4, 0x8b, 0xb4, 0x41, 0xec, 0xa6, 0xa8, 0xba, 0x1a, 0x07,
+ 0x8a, 0x77, 0xf5, 0x5f, 0x02, 0x02, 0x00, 0xa0,
+ };
+
+ CBS_init(&cbs, kParamsDSA, sizeof(kParamsDSA));
+ dh.reset(DH_parse_parameters(&cbs));
+ if (!dh || CBS_len(&cbs) != 0 ||
+ !BIGNUMEqualsHex(dh->p,
+ "93f3c11801e662b6d1469a2c72ea31d91810302863e2347d80caee8"
+ "22b193c19bb42830270dddb8c03abe99cc4004d705f5203312ca467"
+ "3451952aac11e26a55") ||
+ !BIGNUMEqualsHex(dh->g,
+ "44c8105344323163d8d18c75c898533b5b4a2a0a09e7d03c5372a86"
+ "b70419c267144fc7f0875e102ab7441e82a3d3c263309e48bb441ec"
+ "a6a8ba1a078a77f55f") ||
+ dh->priv_length != 160) {
+ return false;
+ }
+
+ if (!CBB_init(cbb.get(), 0) ||
+ !DH_marshal_parameters(cbb.get(), dh.get()) ||
+ !CBB_finish(cbb.get(), &der, &der_len)) {
+ return false;
+ }
+ ScopedOpenSSLBytes free_der2(der);
+ if (der_len != sizeof(kParamsDSA) || memcmp(der, kParamsDSA, der_len) != 0) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/crypto/digest/digest.c b/crypto/digest/digest.c
index eb71b073..fdd9fe55 100644
--- a/crypto/digest/digest.c
+++ b/crypto/digest/digest.c
@@ -60,7 +60,6 @@
#include <string.h>
#include <openssl/err.h>
-#include <openssl/obj.h>
#include <openssl/mem.h>
#include "internal.h"
@@ -166,6 +165,7 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *engine) {
if (ctx->digest != type) {
if (ctx->digest && ctx->digest->ctx_size > 0) {
OPENSSL_free(ctx->md_data);
+ ctx->md_data = NULL;
}
ctx->digest = type;
if (type->ctx_size > 0) {
@@ -231,11 +231,11 @@ const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx) {
return ctx->digest;
}
-unsigned EVP_MD_CTX_size(const EVP_MD_CTX *ctx) {
+size_t EVP_MD_CTX_size(const EVP_MD_CTX *ctx) {
return EVP_MD_size(EVP_MD_CTX_md(ctx));
}
-unsigned EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx) {
+size_t EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx) {
return EVP_MD_block_size(EVP_MD_CTX_md(ctx));
}
diff --git a/crypto/directory.h b/crypto/directory.h
deleted file mode 100644
index 29123ea9..00000000
--- a/crypto/directory.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Copied from Richard Levitte's (richard@levitte.org) LP library. All
- * symbol names have been changed, with permission from the author. */
-
-/* $LP: LPlib/source/LPdir.h,v 1.1 2004/06/14 08:56:04 _cvs_levitte Exp $ */
-/*
- * Copyright (c) 2004, Richard Levitte <richard@levitte.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef OPENSSL_HEADER_DIRECTORY_H
-#define OPENSSL_HEADER_DIRECTORY_H
-
-#include <openssl/base.h>
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-
-/* Directory functions abstract the O/S specific operations for opening and
- * reading directories in the filesystem. */
-
-
-/* OPENSSL_dir_context_st is an opaque structure that represents an open
- * directory and a position in that directory. */
-typedef struct OPENSSL_dir_context_st OPENSSL_DIR_CTX;
-
-/* OPENSSL_DIR_read reads a single filename from |ctx|. On the first call,
- * |directory| must be given and |*ctx| must be NULL. Subsequent calls with the
- * same |*ctx| will return subsequent file names until it returns NULL to
- * indicate EOF. The strings returned reference a buffer internal to the
- * |OPENSSL_DIR_CTX| and will be overridden by subsequent calls. */
-OPENSSL_EXPORT const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx,
- const char *directory);
-
-/* OPENSSL_DIR_end closes |*ctx|. It returns one on success and zero on
- * error. */
-OPENSSL_EXPORT int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx);
-
-
-#if defined(__cplusplus)
-} /* extern C */
-#endif
-
-#endif /* OPENSSL_HEADER_DIRECTORY_H */
diff --git a/crypto/directory_posix.c b/crypto/directory_posix.c
deleted file mode 100644
index b944b692..00000000
--- a/crypto/directory_posix.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/* $LP: LPlib/source/LPdir_unix.c,v 1.11 2004/09/23 22:07:22 _cvs_levitte Exp $ */
-/*
- * Copyright (c) 2004, Richard Levitte <richard@levitte.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
-
-#if !defined(_POSIX_C_SOURCE)
-#define _POSIX_C_SOURCE 201409 /* for readdir_r */
-#endif
-
-#include "directory.h"
-
-
-#if !defined(OPENSSL_WINDOWS)
-
-#include <dirent.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#if defined(OPENSSL_PNACL)
-/* pnacl doesn't include readdir_r! So we do the best we can. */
-int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
- errno = 0;
- *result = readdir(dirp);
- if (*result != NULL) {
- return 0;
- }
- if (errno) {
- return 1;
- }
- return 0;
-}
-#endif
-
-struct OPENSSL_dir_context_st {
- DIR *dir;
- struct dirent dirent;
-};
-
-const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, const char *directory) {
- struct dirent *dirent;
-
- if (ctx == NULL || directory == NULL) {
- errno = EINVAL;
- return NULL;
- }
-
- errno = 0;
- if (*ctx == NULL) {
- *ctx = malloc(sizeof(OPENSSL_DIR_CTX));
- if (*ctx == NULL) {
- errno = ENOMEM;
- return 0;
- }
- memset(*ctx, 0, sizeof(OPENSSL_DIR_CTX));
-
- (*ctx)->dir = opendir(directory);
- if ((*ctx)->dir == NULL) {
- int save_errno = errno; /* Probably not needed, but I'm paranoid */
- free(*ctx);
- *ctx = NULL;
- errno = save_errno;
- return 0;
- }
- }
-
- if (readdir_r((*ctx)->dir, &(*ctx)->dirent, &dirent) != 0 ||
- dirent == NULL) {
- return 0;
- }
-
- return (*ctx)->dirent.d_name;
-}
-
-int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx) {
- if (ctx != NULL && *ctx != NULL) {
- int r = closedir((*ctx)->dir);
- free(*ctx);
- *ctx = NULL;
- return r == 0;
- }
-
- errno = EINVAL;
- return 0;
-}
-
-#endif /* !OPENSSL_WINDOWS */
diff --git a/crypto/directory_win.c b/crypto/directory_win.c
deleted file mode 100644
index 4ebacf21..00000000
--- a/crypto/directory_win.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/* $LP: LPlib/source/LPdir_win.c,v 1.10 2004/08/26 13:36:05 _cvs_levitte Exp $ */
-/*
- * Copyright (c) 2004, Richard Levitte <richard@levitte.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "directory.h"
-
-
-#if defined(OPENSSL_WINDOWS)
-
-#pragma warning(push, 3)
-#include <windows.h>
-#pragma warning(pop)
-#include <errno.h>
-#include <string.h>
-#include <tchar.h>
-
-#ifndef NAME_MAX
-#define NAME_MAX 255
-#endif
-
-#include <openssl/mem.h>
-
-
-struct OPENSSL_dir_context_st {
- WIN32_FIND_DATA ctx;
- HANDLE handle;
- char entry_name[NAME_MAX + 1];
-};
-
-const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, const char *directory) {
- if (ctx == NULL || directory == NULL) {
- errno = EINVAL;
- return 0;
- }
-
- errno = 0;
- if (*ctx == NULL) {
- *ctx = malloc(sizeof(OPENSSL_DIR_CTX));
- if (*ctx == NULL) {
- errno = ENOMEM;
- return 0;
- }
- memset(*ctx, 0, sizeof(OPENSSL_DIR_CTX));
-
- if (sizeof(TCHAR) != sizeof(char)) {
- TCHAR *wdir = NULL;
- /* len_0 denotes string length *with* trailing 0 */
- size_t index = 0, len_0 = strlen(directory) + 1;
-
- wdir = (TCHAR *)malloc(len_0 * sizeof(TCHAR));
- if (wdir == NULL) {
- free(*ctx);
- *ctx = NULL;
- errno = ENOMEM;
- return 0;
- }
-
- if (!MultiByteToWideChar(CP_ACP, 0, directory, len_0, (WCHAR *)wdir,
- len_0)) {
- for (index = 0; index < len_0; index++) {
- wdir[index] = (TCHAR)directory[index];
- }
- }
-
- (*ctx)->handle = FindFirstFile(wdir, &(*ctx)->ctx);
-
- free(wdir);
- } else {
- (*ctx)->handle = FindFirstFile((TCHAR *)directory, &(*ctx)->ctx);
- }
-
- if ((*ctx)->handle == INVALID_HANDLE_VALUE) {
- free(*ctx);
- *ctx = NULL;
- errno = EINVAL;
- return 0;
- }
- } else {
- if (FindNextFile((*ctx)->handle, &(*ctx)->ctx) == FALSE) {
- return 0;
- }
- }
-
- if (sizeof(TCHAR) != sizeof(char)) {
- TCHAR *wdir = (*ctx)->ctx.cFileName;
- size_t index, len_0 = 0;
-
- while (wdir[len_0] && len_0 < (sizeof((*ctx)->entry_name) - 1)) {
- len_0++;
- }
- len_0++;
-
- if (!WideCharToMultiByte(CP_ACP, 0, (WCHAR *)wdir, len_0,
- (*ctx)->entry_name, sizeof((*ctx)->entry_name),
- NULL, 0)) {
- for (index = 0; index < len_0; index++) {
- (*ctx)->entry_name[index] = (char)wdir[index];
- }
- }
- } else {
- strncpy((*ctx)->entry_name, (const char *)(*ctx)->ctx.cFileName,
- sizeof((*ctx)->entry_name) - 1);
- }
-
- (*ctx)->entry_name[sizeof((*ctx)->entry_name) - 1] = '\0';
-
- return (*ctx)->entry_name;
-}
-
-int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx) {
- if (ctx != NULL && *ctx != NULL) {
- FindClose((*ctx)->handle);
- free(*ctx);
- *ctx = NULL;
- return 1;
- }
- errno = EINVAL;
- return 0;
-}
-
-#endif /* OPENSSL_WINDOWS */
diff --git a/crypto/dsa/dsa.c b/crypto/dsa/dsa.c
index 979079d8..1de0071e 100644
--- a/crypto/dsa/dsa.c
+++ b/crypto/dsa/dsa.c
@@ -591,7 +591,6 @@ int DSA_do_check_signature(int *out_valid, const uint8_t *digest,
size_t digest_len, DSA_SIG *sig, const DSA *dsa) {
BN_CTX *ctx;
BIGNUM u1, u2, t1;
- BN_MONT_CTX *mont = NULL;
int ret = 0;
unsigned i;
@@ -662,15 +661,14 @@ int DSA_do_check_signature(int *out_valid, const uint8_t *digest,
goto err;
}
- mont = BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p,
- (CRYPTO_MUTEX *)&dsa->method_mont_p_lock,
- dsa->p, ctx);
- if (!mont) {
+ if (!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p,
+ (CRYPTO_MUTEX *)&dsa->method_mont_p_lock, dsa->p,
+ ctx)) {
goto err;
}
if (!BN_mod_exp2_mont(&t1, dsa->g, &u1, dsa->pub_key, &u2, dsa->p, ctx,
- mont)) {
+ dsa->method_mont_p)) {
goto err;
}
@@ -823,9 +821,9 @@ int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
BN_set_flags(&k, BN_FLG_CONSTTIME);
- if (BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p,
- (CRYPTO_MUTEX *)&dsa->method_mont_p_lock, dsa->p,
- ctx) == NULL) {
+ if (!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p,
+ (CRYPTO_MUTEX *)&dsa->method_mont_p_lock, dsa->p,
+ ctx)) {
goto err;
}
@@ -847,6 +845,7 @@ int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
goto err;
}
+ BN_set_flags(&kq, BN_FLG_CONSTTIME);
K = &kq;
if (!BN_mod_exp_mont(r, dsa->g, K, dsa->p, ctx, dsa->method_mont_p)) {
diff --git a/crypto/dsa/dsa_asn1.c b/crypto/dsa/dsa_asn1.c
index 7615fca2..ff5ee003 100644
--- a/crypto/dsa/dsa_asn1.c
+++ b/crypto/dsa/dsa_asn1.c
@@ -248,6 +248,7 @@ int i2d_DSA_SIG(const DSA_SIG *in, uint8_t **outp) {
CBB cbb;
if (!CBB_init(&cbb, 0) ||
!DSA_SIG_marshal(&cbb, in)) {
+ CBB_cleanup(&cbb);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
@@ -275,6 +276,7 @@ int i2d_DSAPublicKey(const DSA *in, uint8_t **outp) {
CBB cbb;
if (!CBB_init(&cbb, 0) ||
!DSA_marshal_public_key(&cbb, in)) {
+ CBB_cleanup(&cbb);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
@@ -302,6 +304,7 @@ int i2d_DSAPrivateKey(const DSA *in, uint8_t **outp) {
CBB cbb;
if (!CBB_init(&cbb, 0) ||
!DSA_marshal_private_key(&cbb, in)) {
+ CBB_cleanup(&cbb);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
@@ -329,6 +332,7 @@ int i2d_DSAparams(const DSA *in, uint8_t **outp) {
CBB cbb;
if (!CBB_init(&cbb, 0) ||
!DSA_marshal_parameters(&cbb, in)) {
+ CBB_cleanup(&cbb);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
diff --git a/crypto/ec/asm/p256-x86_64-asm.pl b/crypto/ec/asm/p256-x86_64-asm.pl
index 361a84b2..50a5fe6e 100644..100755
--- a/crypto/ec/asm/p256-x86_64-asm.pl
+++ b/crypto/ec/asm/p256-x86_64-asm.pl
@@ -1729,6 +1729,7 @@ $code.=<<___;
push %r15
sub \$32*5+8, %rsp
+.Lpoint_double_shortcut$x:
movdqu 0x00($a_ptr), %xmm0 # copy *(P256_POINT *)$a_ptr.x
mov $a_ptr, $b_ptr # backup copy
movdqu 0x10($a_ptr), %xmm1
@@ -2019,6 +2020,7 @@ $code.=<<___;
mov 0x40+8*1($b_ptr), $acc6
mov 0x40+8*2($b_ptr), $acc7
mov 0x40+8*3($b_ptr), $acc0
+ movq $b_ptr, %xmm1
lea 0x40-$bias($b_ptr), $a_ptr
lea $Z1sqr(%rsp), $r_ptr # Z1^2
@@ -2074,7 +2076,7 @@ $code.=<<___;
test $acc0, $acc0
jnz .Ladd_proceed$x # (in1infty || in2infty)?
test $acc1, $acc1
- jz .Ladd_proceed$x # is_equal(S1,S2)?
+ jz .Ladd_double$x # is_equal(S1,S2)?
movq %xmm0, $r_ptr # restore $r_ptr
pxor %xmm0, %xmm0
@@ -2087,6 +2089,13 @@ $code.=<<___;
jmp .Ladd_done$x
.align 32
+.Ladd_double$x:
+ movq %xmm1, $a_ptr # restore $a_ptr
+ movq %xmm0, $r_ptr # restore $r_ptr
+ add \$`32*(18-5)`, %rsp # difference in frame sizes
+ jmp .Lpoint_double_shortcut$x
+
+.align 32
.Ladd_proceed$x:
`&load_for_sqr("$R(%rsp)", "$src0")`
lea $Rsqr(%rsp), $r_ptr # R^2
diff --git a/crypto/ec/ec.c b/crypto/ec/ec.c
index ca3ce373..8f3fa6e1 100644
--- a/crypto/ec/ec.c
+++ b/crypto/ec/ec.c
@@ -73,7 +73,7 @@
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include "internal.h"
#include "../internal.h"
@@ -228,10 +228,25 @@ static const struct curve_data P521 = {
#endif
const struct built_in_curve OPENSSL_built_in_curves[] = {
- {NID_secp521r1, &P521, 0},
- {NID_secp384r1, &P384, 0},
{
- NID_X9_62_prime256v1, &P256,
+ NID_secp521r1,
+ /* 1.3.132.0.35 */
+ {0x2b, 0x81, 0x04, 0x00, 0x23}, 5,
+ &P521,
+ NULL,
+ },
+ {
+ NID_secp384r1,
+ /* 1.3.132.0.34 */
+ {0x2b, 0x81, 0x04, 0x00, 0x22}, 5,
+ &P384,
+ NULL,
+ },
+ {
+ NID_X9_62_prime256v1,
+ /* 1.2.840.10045.3.1.7 */
+ {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}, 8,
+ &P256,
#if defined(BORINGSSL_USE_INT128_CODE)
#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
!defined(OPENSSL_SMALL)
@@ -240,18 +255,21 @@ const struct built_in_curve OPENSSL_built_in_curves[] = {
EC_GFp_nistp256_method,
#endif
#else
- 0,
+ NULL,
#endif
},
{
- NID_secp224r1, &P224,
+ NID_secp224r1,
+ /* 1.3.132.0.33 */
+ {0x2b, 0x81, 0x04, 0x00, 0x21}, 5,
+ &P224,
#if defined(BORINGSSL_USE_INT128_CODE) && !defined(OPENSSL_SMALL)
EC_GFp_nistp224_method,
#else
- 0,
+ NULL,
#endif
},
- {NID_undef, 0, 0},
+ {NID_undef, {0}, 0, NULL, NULL},
};
/* built_in_curve_scalar_field_monts contains Montgomery contexts for
@@ -350,8 +368,8 @@ EC_GROUP *ec_group_new(const EC_METHOD *meth) {
return ret;
}
-static EC_GROUP *ec_group_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
- const BIGNUM *b, BN_CTX *ctx) {
+EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
+ const BIGNUM *b, BN_CTX *ctx) {
const EC_METHOD *meth = EC_GFp_mont_method();
EC_GROUP *ret;
@@ -371,35 +389,49 @@ static EC_GROUP *ec_group_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
return ret;
}
+int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
+ const BIGNUM *order, const BIGNUM *cofactor) {
+ if (group->curve_name != NID_undef || group->generator != NULL) {
+ /* |EC_GROUP_set_generator| may only be used with |EC_GROUP|s returned by
+ * |EC_GROUP_new_curve_GFp| and may only used once on each group. */
+ return 0;
+ }
+
+ group->generator = EC_POINT_new(group);
+ return group->generator != NULL &&
+ EC_POINT_copy(group->generator, generator) &&
+ BN_copy(&group->order, order) &&
+ BN_copy(&group->cofactor, cofactor);
+}
+
EC_GROUP *EC_GROUP_new_arbitrary(const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, const BIGNUM *gx,
const BIGNUM *gy, const BIGNUM *order,
const BIGNUM *cofactor) {
- EC_GROUP *ret = NULL;
- BN_CTX *ctx;
-
- ctx = BN_CTX_new();
+ BN_CTX *ctx = BN_CTX_new();
if (ctx == NULL) {
- goto err;
+ return NULL;
}
- ret = ec_group_new_curve_GFp(p, a, b, ctx);
+ EC_POINT *generator = NULL;
+ EC_GROUP *ret = EC_GROUP_new_curve_GFp(p, a, b, ctx);
if (ret == NULL) {
goto err;
}
- ret->generator = EC_POINT_new(ret);
- if (ret->generator == NULL ||
- !EC_POINT_set_affine_coordinates_GFp(ret, ret->generator, gx, gy, ctx) ||
- !BN_copy(&ret->order, order) ||
- !BN_copy(&ret->cofactor, cofactor)) {
+ generator = EC_POINT_new(ret);
+ if (generator == NULL ||
+ !EC_POINT_set_affine_coordinates_GFp(ret, generator, gx, gy, ctx) ||
+ !EC_GROUP_set_generator(ret, generator, order, cofactor)) {
goto err;
}
+ EC_POINT_free(generator);
BN_CTX_free(ctx);
return ret;
err:
+ EC_POINT_free(generator);
EC_GROUP_free(ret);
BN_CTX_free(ctx);
return NULL;
@@ -438,7 +470,7 @@ static EC_GROUP *ec_group_new_from_data(unsigned built_in_index) {
goto err;
}
} else {
- if ((group = ec_group_new_curve_GFp(p, a, b, ctx)) == NULL) {
+ if ((group = EC_GROUP_new_curve_GFp(p, a, b, ctx)) == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
goto err;
}
diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c
index a29a2dcf..f31e1587 100644
--- a/crypto/ec/ec_asn1.c
+++ b/crypto/ec/ec_asn1.c
@@ -60,7 +60,7 @@
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include "internal.h"
#include "../bytestring/internal.h"
@@ -207,14 +207,9 @@ int EC_KEY_marshal_private_key(CBB *cbb, const EC_KEY *key,
}
if (!(enc_flags & EC_PKEY_NO_PARAMETERS)) {
- int curve_nid = EC_GROUP_get_curve_name(key->group);
- if (curve_nid == NID_undef) {
- OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
- return 0;
- }
CBB child;
if (!CBB_add_asn1(&ec_private_key, &child, kParametersTag) ||
- !OBJ_nid2cbb(&child, curve_nid) ||
+ !EC_KEY_marshal_curve_name(&child, key->group) ||
!CBB_flush(&ec_private_key)) {
OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR);
return 0;
@@ -260,6 +255,9 @@ static int is_unsigned_integer(const CBS *cbs) {
return 1;
}
+/* kPrimeFieldOID is the encoding of 1.2.840.10045.1.1. */
+static const uint8_t kPrimeField[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01};
+
static int parse_explicit_prime_curve(CBS *in, CBS *out_prime, CBS *out_a,
CBS *out_b, CBS *out_base_x,
CBS *out_base_y, CBS *out_order) {
@@ -272,7 +270,8 @@ static int parse_explicit_prime_curve(CBS *in, CBS *out_prime, CBS *out_a,
version != 1 ||
!CBS_get_asn1(&params, &field_id, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&field_id, &field_type, CBS_ASN1_OBJECT) ||
- OBJ_cbs2nid(&field_type) != NID_X9_62_prime_field ||
+ CBS_len(&field_type) != sizeof(kPrimeField) ||
+ memcmp(CBS_data(&field_type), kPrimeField, sizeof(kPrimeField)) != 0 ||
!CBS_get_asn1(&field_id, out_prime, CBS_ASN1_INTEGER) ||
!is_unsigned_integer(out_prime) ||
CBS_len(&field_id) != 0 ||
@@ -324,51 +323,86 @@ static int integers_equal(const CBS *a, const uint8_t *b, size_t b_len) {
return CBS_mem_equal(&a_copy, b, b_len);
}
-EC_GROUP *EC_KEY_parse_parameters(CBS *cbs) {
- if (CBS_peek_asn1_tag(cbs, CBS_ASN1_SEQUENCE)) {
- /* OpenSSL sometimes produces ECPrivateKeys with explicitly-encoded versions
- * of named curves.
- *
- * TODO(davidben): Remove support for this. */
- CBS prime, a, b, base_x, base_y, order;
- if (!parse_explicit_prime_curve(cbs, &prime, &a, &b, &base_x, &base_y,
- &order)) {
- return NULL;
- }
+EC_GROUP *EC_KEY_parse_curve_name(CBS *cbs) {
+ CBS named_curve;
+ if (!CBS_get_asn1(cbs, &named_curve, CBS_ASN1_OBJECT)) {
+ OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
+ return NULL;
+ }
- /* Look for a matching prime curve. */
- unsigned i;
- for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) {
- const struct built_in_curve *curve = &OPENSSL_built_in_curves[i];
- const unsigned param_len = curve->data->param_len;
- /* |curve->data->data| is ordered p, a, b, x, y, order, each component
- * zero-padded up to the field length. Although SEC 1 states that the
- * Field-Element-to-Octet-String conversion also pads, OpenSSL mis-encodes
- * |a| and |b|, so this comparison must allow omitting leading zeros.
- * (This is relevant for P-521 whose |b| has a leading 0.) */
- if (integers_equal(&prime, curve->data->data, param_len) &&
- integers_equal(&a, curve->data->data + param_len, param_len) &&
- integers_equal(&b, curve->data->data + param_len * 2, param_len) &&
- integers_equal(&base_x, curve->data->data + param_len * 3,
- param_len) &&
- integers_equal(&base_y, curve->data->data + param_len * 4,
- param_len) &&
- integers_equal(&order, curve->data->data + param_len * 5,
- param_len)) {
- return EC_GROUP_new_by_curve_name(curve->nid);
- }
+ /* Look for a matching curve. */
+ unsigned i;
+ for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) {
+ const struct built_in_curve *curve = &OPENSSL_built_in_curves[i];
+ if (CBS_len(&named_curve) == curve->oid_len &&
+ memcmp(CBS_data(&named_curve), curve->oid, curve->oid_len) == 0) {
+ return EC_GROUP_new_by_curve_name(curve->nid);
}
+ }
+
+ OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
+ return NULL;
+}
+int EC_KEY_marshal_curve_name(CBB *cbb, const EC_GROUP *group) {
+ int nid = EC_GROUP_get_curve_name(group);
+ if (nid == NID_undef) {
OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
- return NULL;
+ return 0;
}
- CBS named_curve;
- if (!CBS_get_asn1(cbs, &named_curve, CBS_ASN1_OBJECT)) {
- OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
+ unsigned i;
+ for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) {
+ const struct built_in_curve *curve = &OPENSSL_built_in_curves[i];
+ if (curve->nid == nid) {
+ CBB child;
+ return CBB_add_asn1(cbb, &child, CBS_ASN1_OBJECT) &&
+ CBB_add_bytes(&child, curve->oid, curve->oid_len) &&
+ CBB_flush(cbb);
+ }
+ }
+
+ OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
+ return 0;
+}
+
+EC_GROUP *EC_KEY_parse_parameters(CBS *cbs) {
+ if (!CBS_peek_asn1_tag(cbs, CBS_ASN1_SEQUENCE)) {
+ return EC_KEY_parse_curve_name(cbs);
+ }
+
+ /* OpenSSL sometimes produces ECPrivateKeys with explicitly-encoded versions
+ * of named curves.
+ *
+ * TODO(davidben): Remove support for this. */
+ CBS prime, a, b, base_x, base_y, order;
+ if (!parse_explicit_prime_curve(cbs, &prime, &a, &b, &base_x, &base_y,
+ &order)) {
return NULL;
}
- return EC_GROUP_new_by_curve_name(OBJ_cbs2nid(&named_curve));
+
+ /* Look for a matching prime curve. */
+ unsigned i;
+ for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) {
+ const struct built_in_curve *curve = &OPENSSL_built_in_curves[i];
+ const unsigned param_len = curve->data->param_len;
+ /* |curve->data->data| is ordered p, a, b, x, y, order, each component
+ * zero-padded up to the field length. Although SEC 1 states that the
+ * Field-Element-to-Octet-String conversion also pads, OpenSSL mis-encodes
+ * |a| and |b|, so this comparison must allow omitting leading zeros. (This
+ * is relevant for P-521 whose |b| has a leading 0.) */
+ if (integers_equal(&prime, curve->data->data, param_len) &&
+ integers_equal(&a, curve->data->data + param_len, param_len) &&
+ integers_equal(&b, curve->data->data + param_len * 2, param_len) &&
+ integers_equal(&base_x, curve->data->data + param_len * 3, param_len) &&
+ integers_equal(&base_y, curve->data->data + param_len * 4, param_len) &&
+ integers_equal(&order, curve->data->data + param_len * 5, param_len)) {
+ return EC_GROUP_new_by_curve_name(curve->nid);
+ }
+ }
+
+ OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
+ return NULL;
}
EC_KEY *d2i_ECPrivateKey(EC_KEY **out, const uint8_t **inp, long len) {
@@ -401,6 +435,7 @@ int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp) {
CBB cbb;
if (!CBB_init(&cbb, 0) ||
!EC_KEY_marshal_private_key(&cbb, key, EC_KEY_get_enc_flags(key))) {
+ CBB_cleanup(&cbb);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
@@ -440,15 +475,10 @@ int i2d_ECParameters(const EC_KEY *key, uint8_t **outp) {
return -1;
}
- int curve_nid = EC_GROUP_get_curve_name(key->group);
- if (curve_nid == NID_undef) {
- OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
- return -1;
- }
-
CBB cbb;
if (!CBB_init(&cbb, 0) ||
- !OBJ_nid2cbb(&cbb, curve_nid)) {
+ !EC_KEY_marshal_curve_name(&cbb, key->group)) {
+ CBB_cleanup(&cbb);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c
index f01bf6b4..fee71fed 100644
--- a/crypto/ec/ec_key.c
+++ b/crypto/ec/ec_key.c
@@ -365,15 +365,24 @@ int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x,
return 0;
}
ctx = BN_CTX_new();
+
+ if (ctx == NULL) {
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
point = EC_POINT_new(key->group);
- if (ctx == NULL ||
- point == NULL) {
+ if (point == NULL) {
goto err;
}
tx = BN_CTX_get(ctx);
ty = BN_CTX_get(ctx);
+ if (tx == NULL ||
+ ty == NULL) {
+ goto err;
+ }
if (!EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, ctx) ||
!EC_POINT_get_affine_coordinates_GFp(key->group, point, tx, ty, ctx)) {
@@ -398,6 +407,7 @@ int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x,
ok = 1;
err:
+ BN_CTX_end(ctx);
BN_CTX_free(ctx);
EC_POINT_free(point);
return ok;
diff --git a/crypto/ec/ec_montgomery.c b/crypto/ec/ec_montgomery.c
index 62b0d7f6..35df3651 100644
--- a/crypto/ec/ec_montgomery.c
+++ b/crypto/ec/ec_montgomery.c
@@ -79,23 +79,18 @@ int ec_GFp_mont_group_init(EC_GROUP *group) {
ok = ec_GFp_simple_group_init(group);
group->mont = NULL;
- group->one = NULL;
return ok;
}
void ec_GFp_mont_group_finish(EC_GROUP *group) {
BN_MONT_CTX_free(group->mont);
group->mont = NULL;
- BN_free(group->one);
- group->one = NULL;
ec_GFp_simple_group_finish(group);
}
int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) {
BN_MONT_CTX_free(dest->mont);
dest->mont = NULL;
- BN_clear_free(dest->one);
- dest->one = NULL;
if (!ec_GFp_simple_group_copy(dest, src)) {
return 0;
@@ -110,12 +105,6 @@ int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) {
goto err;
}
}
- if (src->one != NULL) {
- dest->one = BN_dup(src->one);
- if (dest->one == NULL) {
- goto err;
- }
- }
return 1;
@@ -129,13 +118,10 @@ int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p,
const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
BN_CTX *new_ctx = NULL;
BN_MONT_CTX *mont = NULL;
- BIGNUM *one = NULL;
int ret = 0;
BN_MONT_CTX_free(group->mont);
group->mont = NULL;
- BN_free(group->one);
- group->one = NULL;
if (ctx == NULL) {
ctx = new_ctx = BN_CTX_new();
@@ -152,29 +138,20 @@ int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p,
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
}
- one = BN_new();
- if (one == NULL || !BN_to_montgomery(one, BN_value_one(), mont, ctx)) {
- goto err;
- }
group->mont = mont;
mont = NULL;
- group->one = one;
- one = NULL;
ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
if (!ret) {
BN_MONT_CTX_free(group->mont);
group->mont = NULL;
- BN_free(group->one);
- group->one = NULL;
}
err:
BN_CTX_free(new_ctx);
BN_MONT_CTX_free(mont);
- BN_free(one);
return ret;
}
@@ -218,19 +195,6 @@ int ec_GFp_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
return BN_from_montgomery(r, a, group->mont, ctx);
}
-int ec_GFp_mont_field_set_to_one(const EC_GROUP *group, BIGNUM *r,
- BN_CTX *ctx) {
- if (group->one == NULL) {
- OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED);
- return 0;
- }
-
- if (!BN_copy(r, group->one)) {
- return 0;
- }
- return 1;
-}
-
static int ec_GFp_mont_check_pub_key_order(const EC_GROUP *group,
const EC_POINT* pub_key,
BN_CTX *ctx) {
@@ -251,20 +215,108 @@ err:
return ret;
}
+static int ec_GFp_mont_point_get_affine_coordinates(const EC_GROUP *group,
+ const EC_POINT *point,
+ BIGNUM *x, BIGNUM *y,
+ BN_CTX *ctx) {
+ if (EC_POINT_is_at_infinity(group, point)) {
+ OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
+ return 0;
+ }
+
+ BN_CTX *new_ctx = NULL;
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ return 0;
+ }
+ }
+
+ int ret = 0;
+
+ BN_CTX_start(ctx);
+
+ if (BN_cmp(&point->Z, &group->one) == 0) {
+ /* |point| is already affine. */
+ if (x != NULL && !BN_from_montgomery(x, &point->X, group->mont, ctx)) {
+ goto err;
+ }
+ if (y != NULL && !BN_from_montgomery(y, &point->Y, group->mont, ctx)) {
+ goto err;
+ }
+ } else {
+ /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */
+
+ BIGNUM *Z_1 = BN_CTX_get(ctx);
+ BIGNUM *Z_2 = BN_CTX_get(ctx);
+ BIGNUM *Z_3 = BN_CTX_get(ctx);
+ if (Z_1 == NULL ||
+ Z_2 == NULL ||
+ Z_3 == NULL) {
+ goto err;
+ }
+
+ /* The straightforward way to calculate the inverse of a Montgomery-encoded
+ * value where the result is Montgomery-encoded is:
+ *
+ * |BN_from_montgomery| + |BN_mod_inverse| + |BN_to_montgomery|.
+ *
+ * This is equivalent, but more efficient, because |BN_from_montgomery|
+ * is more efficient (at least in theory) than |BN_to_montgomery|, since it
+ * doesn't have to do the multiplication before the reduction. */
+ if (!BN_from_montgomery(Z_1, &point->Z, group->mont, ctx) ||
+ !BN_from_montgomery(Z_1, Z_1, group->mont, ctx) ||
+ !BN_mod_inverse(Z_1, Z_1, &group->field, ctx)) {
+ goto err;
+ }
+
+ if (!BN_mod_mul_montgomery(Z_2, Z_1, Z_1, group->mont, ctx)) {
+ goto err;
+ }
+
+ /* Instead of using |BN_from_montgomery| to convert the |x| coordinate
+ * and then calling |BN_from_montgomery| again to convert the |y|
+ * coordinate below, convert the common factor |Z_2| once now, saving one
+ * reduction. */
+ if (!BN_from_montgomery(Z_2, Z_2, group->mont, ctx)) {
+ goto err;
+ }
+
+ if (x != NULL) {
+ if (!BN_mod_mul_montgomery(x, &point->X, Z_2, group->mont, ctx)) {
+ goto err;
+ }
+ }
+
+ if (y != NULL) {
+ if (!BN_mod_mul_montgomery(Z_3, Z_2, Z_1, group->mont, ctx) ||
+ !BN_mod_mul_montgomery(y, &point->Y, Z_3, group->mont, ctx)) {
+ goto err;
+ }
+ }
+ }
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
const EC_METHOD *EC_GFp_mont_method(void) {
static const EC_METHOD ret = {
ec_GFp_mont_group_init,
ec_GFp_mont_group_finish,
ec_GFp_mont_group_copy,
ec_GFp_mont_group_set_curve,
- ec_GFp_simple_point_get_affine_coordinates,
+ ec_GFp_mont_point_get_affine_coordinates,
ec_wNAF_mul /* XXX: Not constant time. */,
ec_GFp_mont_check_pub_key_order,
ec_GFp_mont_field_mul,
ec_GFp_mont_field_sqr,
ec_GFp_mont_field_encode,
ec_GFp_mont_field_decode,
- ec_GFp_mont_field_set_to_one,
};
return &ret;
diff --git a/crypto/ec/ec_test.cc b/crypto/ec/ec_test.cc
index d45e193a..ce9d99f3 100644
--- a/crypto/ec/ec_test.cc
+++ b/crypto/ec/ec_test.cc
@@ -122,7 +122,7 @@ static bool EncodeECPrivateKey(std::vector<uint8_t> *out, const EC_KEY *key) {
return true;
}
-bool Testd2i_ECPrivateKey() {
+static bool Testd2i_ECPrivateKey() {
ScopedEC_KEY key = DecodeECPrivateKey(kECKeyWithoutPublic,
sizeof(kECKeyWithoutPublic));
if (!key) {
@@ -349,23 +349,32 @@ static bool TestArbitraryCurve() {
0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
};
+ ScopedBN_CTX ctx(BN_CTX_new());
ScopedBIGNUM p(BN_bin2bn(kP, sizeof(kP), nullptr));
ScopedBIGNUM a(BN_bin2bn(kA, sizeof(kA), nullptr));
ScopedBIGNUM b(BN_bin2bn(kB, sizeof(kB), nullptr));
- ScopedBIGNUM x(BN_bin2bn(kX, sizeof(kX), nullptr));
- ScopedBIGNUM y(BN_bin2bn(kY, sizeof(kY), nullptr));
+ ScopedBIGNUM gx(BN_bin2bn(kX, sizeof(kX), nullptr));
+ ScopedBIGNUM gy(BN_bin2bn(kY, sizeof(kY), nullptr));
ScopedBIGNUM order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr));
ScopedBIGNUM cofactor(BN_new());
- if (!p || !a || !b || !x || !y || !order || !cofactor ||
+ if (!ctx || !p || !a || !b || !gx || !gy || !order || !cofactor ||
!BN_set_word(cofactor.get(), 1)) {
return false;
}
- ScopedEC_GROUP group(EC_GROUP_new_arbitrary(p.get(), a.get(), b.get(),
- x.get(), y.get(), order.get(),
- cofactor.get()));
+
+ ScopedEC_GROUP group(
+ EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
if (!group) {
return false;
}
+ ScopedEC_POINT generator(EC_POINT_new(group.get()));
+ if (!generator ||
+ !EC_POINT_set_affine_coordinates_GFp(group.get(), generator.get(),
+ gx.get(), gy.get(), ctx.get()) ||
+ !EC_GROUP_set_generator(group.get(), generator.get(), order.get(),
+ cofactor.get())) {
+ return false;
+ }
// |group| should not have a curve name.
if (EC_GROUP_get_curve_name(group.get()) != NID_undef) {
@@ -375,7 +384,8 @@ static bool TestArbitraryCurve() {
// Copy |key| to |key2| using |group|.
ScopedEC_KEY key2(EC_KEY_new());
ScopedEC_POINT point(EC_POINT_new(group.get()));
- if (!key2 || !point ||
+ ScopedBIGNUM x(BN_new()), y(BN_new());
+ if (!key2 || !point || !x || !y ||
!EC_KEY_set_group(key2.get(), group.get()) ||
!EC_KEY_set_private_key(key2.get(), EC_KEY_get0_private_key(key.get())) ||
!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(key.get()),
@@ -394,6 +404,101 @@ static bool TestArbitraryCurve() {
return false;
}
+ // Repeat the process for |EC_GROUP_new_arbitrary|.
+ group.reset(EC_GROUP_new_arbitrary(p.get(), a.get(), b.get(), gx.get(),
+ gy.get(), order.get(), cofactor.get()));
+ if (!group) {
+ return false;
+ }
+
+ // |group| should not have a curve name.
+ if (EC_GROUP_get_curve_name(group.get()) != NID_undef) {
+ return false;
+ }
+
+ // Copy |key| to |key2| using |group|.
+ key2.reset(EC_KEY_new());
+ point.reset(EC_POINT_new(group.get()));
+ if (!key2 || !point ||
+ !EC_KEY_set_group(key2.get(), group.get()) ||
+ !EC_KEY_set_private_key(key2.get(), EC_KEY_get0_private_key(key.get())) ||
+ !EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(), x.get(),
+ y.get(), nullptr) ||
+ !EC_KEY_set_public_key(key2.get(), point.get())) {
+ fprintf(stderr, "Could not copy key.\n");
+ return false;
+ }
+
+ // The key must be valid according to the new group too.
+ if (!EC_KEY_check_key(key2.get())) {
+ fprintf(stderr, "Copied key is not valid.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestAddingEqualPoints(int nid) {
+ ScopedEC_KEY key(EC_KEY_new_by_curve_name(nid));
+ if (!key) {
+ return false;
+ }
+
+ const EC_GROUP *const group = EC_KEY_get0_group(key.get());
+
+ if (!EC_KEY_generate_key(key.get())) {
+ fprintf(stderr, "EC_KEY_generate_key failed with nid %d\n", nid);
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ ScopedEC_POINT p1(EC_POINT_new(group));
+ ScopedEC_POINT p2(EC_POINT_new(group));
+ ScopedEC_POINT double_p1(EC_POINT_new(group));
+ ScopedEC_POINT p1_plus_p2(EC_POINT_new(group));
+ if (!p1 || !p2 || !double_p1 || !p1_plus_p2) {
+ return false;
+ }
+
+ if (!EC_POINT_copy(p1.get(), EC_KEY_get0_public_key(key.get())) ||
+ !EC_POINT_copy(p2.get(), EC_KEY_get0_public_key(key.get()))) {
+ fprintf(stderr, "EC_POINT_COPY failed with nid %d\n", nid);
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ ScopedBN_CTX ctx(BN_CTX_new());
+ if (!ctx) {
+ return false;
+ }
+
+ if (!EC_POINT_dbl(group, double_p1.get(), p1.get(), ctx.get()) ||
+ !EC_POINT_add(group, p1_plus_p2.get(), p1.get(), p2.get(), ctx.get())) {
+ fprintf(stderr, "Point operation failed with nid %d\n", nid);
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ if (EC_POINT_cmp(group, double_p1.get(), p1_plus_p2.get(), ctx.get()) != 0) {
+ fprintf(stderr, "A+A != 2A for nid %d", nid);
+ return false;
+ }
+
+ return true;
+}
+
+static bool ForEachCurve(bool (*test_func)(int nid)) {
+ const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
+ std::vector<EC_builtin_curve> curves(num_curves);
+ EC_get_builtin_curves(curves.data(), num_curves);
+
+ for (const auto& curve : curves) {
+ if (!test_func(curve.nid)) {
+ fprintf(stderr, "Test failed for %s\n", curve.comment);
+ return false;
+ }
+ }
+
return true;
}
@@ -403,10 +508,8 @@ int main(void) {
if (!Testd2i_ECPrivateKey() ||
!TestZeroPadding() ||
!TestSpecifiedCurve() ||
- !TestSetAffine(NID_secp224r1) ||
- !TestSetAffine(NID_X9_62_prime256v1) ||
- !TestSetAffine(NID_secp384r1) ||
- !TestSetAffine(NID_secp521r1) ||
+ !ForEachCurve(TestSetAffine) ||
+ !ForEachCurve(TestAddingEqualPoints) ||
!TestArbitraryCurve()) {
fprintf(stderr, "failed\n");
return 1;
diff --git a/crypto/ec/example_mul.c b/crypto/ec/example_mul.c
index ebb724fa..a2bdd527 100644
--- a/crypto/ec/example_mul.c
+++ b/crypto/ec/example_mul.c
@@ -70,10 +70,10 @@
#include <openssl/bn.h>
#include <openssl/crypto.h>
#include <openssl/ec.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
-int example_EC_POINT_mul(void) {
+static int example_EC_POINT_mul(void) {
/* This example ensures that 10×∞ + G = G, in P-256. */
EC_GROUP *group = NULL;
EC_POINT *p = NULL, *result = NULL;
diff --git a/crypto/ec/internal.h b/crypto/ec/internal.h
index 2b788c1c..f2cbb961 100644
--- a/crypto/ec/internal.h
+++ b/crypto/ec/internal.h
@@ -116,7 +116,6 @@ struct ec_method_st {
BN_CTX *); /* e.g. to Montgomery */
int (*field_decode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
BN_CTX *); /* e.g. from Montgomery */
- int (*field_set_to_one)(const EC_GROUP *, BIGNUM *r, BN_CTX *);
} /* EC_METHOD */;
const EC_METHOD* EC_GFp_mont_method(void);
@@ -141,7 +140,8 @@ struct ec_group_st {
int a_is_minus3; /* enable optimized point arithmetics for special case */
BN_MONT_CTX *mont; /* Montgomery structure. */
- BIGNUM *one; /* The value one */
+
+ BIGNUM one; /* The value one. */
} /* EC_GROUP */;
struct ec_point_st {
@@ -151,7 +151,6 @@ struct ec_point_st {
BIGNUM Y;
BIGNUM Z; /* Jacobian projective coordinates:
* (X, Y, Z) represents (X/Z^2, Y/Z^3) if Z != 0 */
- int Z_is_one; /* enable optimized point arithmetics for special case */
} /* EC_POINT */;
EC_GROUP *ec_group_new(const EC_METHOD *meth);
@@ -190,9 +189,6 @@ int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *,
int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *,
const BIGNUM *x, const BIGNUM *y,
BN_CTX *);
-int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *,
- const EC_POINT *, BIGNUM *x,
- BIGNUM *y, BN_CTX *);
int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *,
const BIGNUM *x, int y_bit,
BN_CTX *);
@@ -227,22 +223,12 @@ int ec_GFp_mont_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
BN_CTX *);
int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
BN_CTX *);
-int ec_GFp_mont_field_set_to_one(const EC_GROUP *, BIGNUM *r, BN_CTX *);
int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group,
EC_POINT *point, const BIGNUM *x,
const BIGNUM *y, const BIGNUM *z,
BN_CTX *ctx);
-void ec_GFp_nistp_points_make_affine_internal(
- size_t num, void *point_array, size_t felem_size, void *tmp_felems,
- void (*felem_one)(void *out), int (*felem_is_zero)(const void *in),
- void (*felem_assign)(void *out, const void *in),
- void (*felem_square)(void *out, const void *in),
- void (*felem_mul)(void *out, const void *in1, const void *in2),
- void (*felem_inv)(void *out, const void *in),
- void (*felem_contract)(void *out, const void *in));
-
void ec_GFp_nistp_recode_scalar_bits(uint8_t *sign, uint8_t *digit, uint8_t in);
const EC_METHOD *EC_GFp_nistp224_method(void);
@@ -285,6 +271,8 @@ struct curve_data {
struct built_in_curve {
int nid;
+ uint8_t oid[8];
+ uint8_t oid_len;
const struct curve_data *data;
const EC_METHOD *(*method)(void);
};
diff --git a/crypto/ec/oct.c b/crypto/ec/oct.c
index 9e18535a..bf1957ca 100644
--- a/crypto/ec/oct.c
+++ b/crypto/ec/oct.c
@@ -281,10 +281,15 @@ int EC_POINT_point2cbb(CBB *out, const EC_GROUP *group, const EC_POINT *point,
}
int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group,
- EC_POINT *point, const BIGNUM *x_,
+ EC_POINT *point, const BIGNUM *x,
int y_bit, BN_CTX *ctx) {
+ if (BN_is_negative(x) || BN_cmp(x, &group->field) >= 0) {
+ OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT);
+ return 0;
+ }
+
BN_CTX *new_ctx = NULL;
- BIGNUM *tmp1, *tmp2, *x, *y;
+ BIGNUM *tmp1, *tmp2, *y;
int ret = 0;
ERR_clear_error();
@@ -301,7 +306,6 @@ int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group,
BN_CTX_start(ctx);
tmp1 = BN_CTX_get(ctx);
tmp2 = BN_CTX_get(ctx);
- x = BN_CTX_get(ctx);
y = BN_CTX_get(ctx);
if (y == NULL) {
goto err;
@@ -312,19 +316,15 @@ int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group,
* so y is one of the square roots of x^3 + a*x + b. */
/* tmp1 := x^3 */
- if (!BN_nnmod(x, x_, &group->field, ctx)) {
- goto err;
- }
-
if (group->meth->field_decode == 0) {
/* field_{sqr,mul} work on standard representation */
- if (!group->meth->field_sqr(group, tmp2, x_, ctx) ||
- !group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) {
+ if (!group->meth->field_sqr(group, tmp2, x, ctx) ||
+ !group->meth->field_mul(group, tmp1, tmp2, x, ctx)) {
goto err;
}
} else {
- if (!BN_mod_sqr(tmp2, x_, &group->field, ctx) ||
- !BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) {
+ if (!BN_mod_sqr(tmp2, x, &group->field, ctx) ||
+ !BN_mod_mul(tmp1, tmp2, x, &group->field, ctx)) {
goto err;
}
}
diff --git a/crypto/ec/p224-64.c b/crypto/ec/p224-64.c
index 9de6cd49..7bf889c9 100644
--- a/crypto/ec/p224-64.c
+++ b/crypto/ec/p224-64.c
@@ -26,7 +26,6 @@
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
#include <string.h>
@@ -193,7 +192,7 @@ static void bin28_to_felem(felem out, const u8 in[28]) {
}
static void felem_to_bin28(u8 out[28], const felem in) {
- unsigned i;
+ size_t i;
for (i = 0; i < 7; ++i) {
out[i] = in[0] >> (8 * i);
out[i + 7] = in[1] >> (8 * i);
@@ -203,8 +202,8 @@ static void felem_to_bin28(u8 out[28], const felem in) {
}
/* To preserve endianness when using BN_bn2bin and BN_bin2bn */
-static void flip_endian(u8 *out, const u8 *in, unsigned len) {
- unsigned i;
+static void flip_endian(u8 *out, const u8 *in, size_t len) {
+ size_t i;
for (i = 0; i < len; ++i) {
out[i] = in[len - 1 - i];
}
@@ -215,7 +214,7 @@ static int BN_to_felem(felem out, const BIGNUM *bn) {
/* BN_bn2bin eats leading zeroes */
felem_bytearray b_out;
memset(b_out, 0, sizeof(b_out));
- unsigned num_bytes = BN_num_bytes(bn);
+ size_t num_bytes = BN_num_bytes(bn);
if (num_bytes > sizeof(b_out) ||
BN_is_negative(bn)) {
OPENSSL_PUT_ERROR(EC, EC_R_BIGNUM_OUT_OF_RANGE);
@@ -242,13 +241,6 @@ static BIGNUM *felem_to_BN(BIGNUM *out, const felem in) {
* expected to be correct in general - e.g., multiplication with a large scalar
* will cause an overflow. */
-static void felem_one(felem out) {
- out[0] = 1;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
-}
-
static void felem_assign(felem out, const felem in) {
out[0] = in[0];
out[1] = in[1];
@@ -460,18 +452,6 @@ static void felem_reduce(felem out, const widefelem in) {
out[3] = output[3];
}
-static void felem_square_reduce(felem out, const felem in) {
- widefelem tmp;
- felem_square(tmp, in);
- felem_reduce(out, tmp);
-}
-
-static void felem_mul_reduce(felem out, const felem in1, const felem in2) {
- widefelem tmp;
- felem_mul(tmp, in1, in2);
- felem_reduce(out, tmp);
-}
-
/* Reduce to unique minimal representation.
* Requires 0 <= in < 2*p (always call felem_reduce first) */
static void felem_contract(felem out, const felem in) {
@@ -539,16 +519,12 @@ static limb felem_is_zero(const felem in) {
return (zero | two224m96p1 | two225m97p2);
}
-static limb felem_is_zero_int(const felem in) {
- return (int)(felem_is_zero(in) & ((limb)1));
-}
-
/* Invert a field element */
/* Computation chain copied from djb's code */
static void felem_inv(felem out, const felem in) {
felem ftmp, ftmp2, ftmp3, ftmp4;
widefelem tmp;
- unsigned i;
+ size_t i;
felem_square(tmp, in);
felem_reduce(ftmp, tmp); /* 2 */
@@ -628,7 +604,7 @@ static void felem_inv(felem out, const felem in) {
* if icopy == 1, copy in to out,
* if icopy == 0, copy out to itself. */
static void copy_conditional(felem out, const felem in, limb icopy) {
- unsigned i;
+ size_t i;
/* icopy is a (64-bit) 0 or 1, so copy is either all-zero or all-one */
const limb copy = -icopy;
for (i = 0; i < 4; ++i) {
@@ -885,12 +861,12 @@ static void point_add(felem x3, felem y3, felem z3, const felem x1,
/* select_point selects the |idx|th point from a precomputation table and
* copies it to out. */
-static void select_point(const u64 idx, unsigned int size,
+static void select_point(const u64 idx, size_t size,
const felem pre_comp[/*size*/][3], felem out[3]) {
- unsigned i, j;
limb *outlimbs = &out[0][0];
memset(outlimbs, 0, 3 * sizeof(felem));
+ size_t i;
for (i = 0; i < size; i++) {
const limb *inlimbs = &pre_comp[i][0][0];
u64 mask = i ^ idx;
@@ -899,6 +875,7 @@ static void select_point(const u64 idx, unsigned int size,
mask |= mask >> 1;
mask &= 1;
mask--;
+ size_t j;
for (j = 0; j < 4 * 3; j++) {
outlimbs[j] |= inlimbs[j] & mask;
}
@@ -906,7 +883,7 @@ static void select_point(const u64 idx, unsigned int size,
}
/* get_bit returns the |i|th bit in |in| */
-static char get_bit(const felem_bytearray in, unsigned i) {
+static char get_bit(const felem_bytearray in, size_t i) {
if (i >= 224) {
return 0;
}
@@ -920,11 +897,8 @@ static char get_bit(const felem_bytearray in, unsigned i) {
* Output point (X, Y, Z) is stored in x_out, y_out, z_out */
static void batch_mul(felem x_out, felem y_out, felem z_out,
const felem_bytearray scalars[],
- const unsigned num_points, const u8 *g_scalar,
- const int mixed, const felem pre_comp[][17][3]) {
- int i, skip;
- unsigned num;
- unsigned gen_mul = (g_scalar != NULL);
+ const size_t num_points, const u8 *g_scalar,
+ const felem pre_comp[][17][3]) {
felem nq[3], tmp[4];
u64 bits;
u8 sign, digit;
@@ -935,15 +909,16 @@ static void batch_mul(felem x_out, felem y_out, felem z_out,
/* Loop over all scalars msb-to-lsb, interleaving additions
* of multiples of the generator (two in each of the last 28 rounds)
* and additions of other points multiples (every 5th round). */
- skip = 1; /* save two point operations in the first round */
- for (i = (num_points ? 220 : 27); i >= 0; --i) {
+ int skip = 1; /* save two point operations in the first round */
+ size_t i = num_points != 0 ? 220 : 27;
+ for (;;) {
/* double */
if (!skip) {
point_double(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2]);
}
/* add multiples of the generator */
- if (gen_mul && (i <= 27)) {
+ if (g_scalar != NULL && i <= 27) {
/* first, look 28 bits upwards */
bits = get_bit(g_scalar, i + 196) << 3;
bits |= get_bit(g_scalar, i + 140) << 2;
@@ -972,8 +947,9 @@ static void batch_mul(felem x_out, felem y_out, felem z_out,
}
/* do other additions every 5 doublings */
- if (num_points && (i % 5 == 0)) {
+ if (num_points != 0 && i % 5 == 0) {
/* loop over all scalars */
+ size_t num;
for (num = 0; num < num_points; ++num) {
bits = get_bit(scalars[num], i + 4) << 5;
bits |= get_bit(scalars[num], i + 3) << 4;
@@ -989,14 +965,19 @@ static void batch_mul(felem x_out, felem y_out, felem z_out,
copy_conditional(tmp[1], tmp[3], sign);
if (!skip) {
- point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], mixed, tmp[0],
- tmp[1], tmp[2]);
+ point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 0 /* mixed */,
+ tmp[0], tmp[1], tmp[2]);
} else {
memcpy(nq, tmp, 3 * sizeof(felem));
skip = 0;
}
}
}
+
+ if (i == 0) {
+ break;
+ }
+ --i;
}
felem_assign(x_out, nq[0]);
felem_assign(y_out, nq[1]);
@@ -1005,10 +986,10 @@ static void batch_mul(felem x_out, felem y_out, felem z_out,
/* Takes the Jacobian coordinates (X, Y, Z) of a point and returns
* (X', Y') = (X/Z^2, Y/Z^3) */
-int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group,
- const EC_POINT *point,
- BIGNUM *x, BIGNUM *y,
- BN_CTX *ctx) {
+static int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group,
+ const EC_POINT *point,
+ BIGNUM *x, BIGNUM *y,
+ BN_CTX *ctx) {
felem z1, z2, x_in, y_in, x_out, y_out;
widefelem tmp;
@@ -1047,23 +1028,12 @@ int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group,
return 1;
}
-static void make_points_affine(size_t num, felem points[/*num*/][3],
- felem tmp_felems[/*num+1*/]) {
- /* Runs in constant time, unless an input is the point at infinity
- * (which normally shouldn't happen). */
- ec_GFp_nistp_points_make_affine_internal(
- num, points, sizeof(felem), tmp_felems, (void (*)(void *))felem_one,
- (int (*)(const void *))felem_is_zero_int,
- (void (*)(void *, const void *))felem_assign,
- (void (*)(void *, const void *))felem_square_reduce,
- (void (*)(void *, const void *, const void *))felem_mul_reduce,
- (void (*)(void *, const void *))felem_inv,
- (void (*)(void *, const void *))felem_contract);
-}
-
-int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
- const BIGNUM *g_scalar, const EC_POINT *p_,
- const BIGNUM *p_scalar_, BN_CTX *ctx) {
+static int ec_GFp_nistp224_points_mul(const EC_GROUP *group,
+ EC_POINT *r,
+ const BIGNUM *g_scalar,
+ const EC_POINT *p_,
+ const BIGNUM *p_scalar_,
+ BN_CTX *ctx) {
/* TODO: This function used to take |points| and |scalars| as arrays of
* |num| elements. The code below should be simplified to work in terms of
* |p_| and |p_scalar_|. */
@@ -1072,17 +1042,12 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
BIGNUM const *const *scalars = p_ != NULL ? &p_scalar_ : NULL;
int ret = 0;
- int j;
- unsigned i;
- int mixed = 0;
BN_CTX *new_ctx = NULL;
BIGNUM *x, *y, *z, *tmp_scalar;
felem_bytearray g_secret;
felem_bytearray *secrets = NULL;
felem(*pre_comp)[17][3] = NULL;
- felem *tmp_felems = NULL;
felem_bytearray tmp;
- unsigned num_bytes;
size_t num_points = num;
felem x_in, y_in, z_in, x_out, y_out, z_out;
const EC_POINT *p = NULL;
@@ -1105,19 +1070,10 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
}
if (num_points > 0) {
- if (num_points >= 3) {
- /* unless we precompute multiples for just one or two points,
- * converting those into affine form is time well spent */
- mixed = 1;
- }
secrets = OPENSSL_malloc(num_points * sizeof(felem_bytearray));
pre_comp = OPENSSL_malloc(num_points * sizeof(felem[17][3]));
- if (mixed) {
- tmp_felems = OPENSSL_malloc((num_points * 17 + 1) * sizeof(felem));
- }
if (secrets == NULL ||
- pre_comp == NULL ||
- (mixed && tmp_felems == NULL)) {
+ pre_comp == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -1126,6 +1082,7 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
* i.e., they contribute nothing to the linear combination */
memset(secrets, 0, num_points * sizeof(felem_bytearray));
memset(pre_comp, 0, num_points * 17 * 3 * sizeof(felem));
+ size_t i;
for (i = 0; i < num_points; ++i) {
if (i == num) {
/* the generator */
@@ -1138,6 +1095,7 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
}
if (p_scalar != NULL && p != NULL) {
+ size_t num_bytes;
/* reduce g_scalar to 0 <= g_scalar < 2^224 */
if (BN_num_bits(p_scalar) > 224 || BN_is_negative(p_scalar)) {
/* this is an unusual input, and we don't guarantee
@@ -1163,6 +1121,7 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
felem_assign(pre_comp[i][1][1], y_out);
felem_assign(pre_comp[i][1][2], z_out);
+ size_t j;
for (j = 2; j <= 16; ++j) {
if (j & 1) {
point_add(pre_comp[i][j][0], pre_comp[i][j][1], pre_comp[i][j][2],
@@ -1177,14 +1136,11 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
}
}
}
-
- if (mixed) {
- make_points_affine(num_points * 17, pre_comp[0], tmp_felems);
- }
}
if (g_scalar != NULL) {
memset(g_secret, 0, sizeof(g_secret));
+ size_t num_bytes;
/* reduce g_scalar to 0 <= g_scalar < 2^224 */
if (BN_num_bits(g_scalar) > 224 || BN_is_negative(g_scalar)) {
/* this is an unusual input, and we don't guarantee constant-timeness */
@@ -1200,7 +1156,7 @@ int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
flip_endian(g_secret, tmp, num_bytes);
}
batch_mul(x_out, y_out, z_out, (const felem_bytearray(*))secrets,
- num_points, g_scalar != NULL ? g_secret : NULL, mixed,
+ num_points, g_scalar != NULL ? g_secret : NULL,
(const felem(*)[17][3])pre_comp);
/* reduce the output to its unique minimal representation */
@@ -1220,7 +1176,6 @@ err:
BN_CTX_free(new_ctx);
OPENSSL_free(secrets);
OPENSSL_free(pre_comp);
- OPENSSL_free(tmp_felems);
return ret;
}
@@ -1235,8 +1190,7 @@ const EC_METHOD *EC_GFp_nistp224_method(void) {
ec_GFp_simple_field_mul,
ec_GFp_simple_field_sqr,
0 /* field_encode */,
- 0 /* field_decode */,
- 0 /* field_set_to_one */};
+ 0 /* field_decode */};
return &ret;
}
diff --git a/crypto/ec/p256-64.c b/crypto/ec/p256-64.c
index b94e226e..c4259b62 100644
--- a/crypto/ec/p256-64.c
+++ b/crypto/ec/p256-64.c
@@ -27,7 +27,6 @@
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
#include <string.h>
@@ -94,8 +93,8 @@ static void smallfelem_to_bin32(u8 out[32], const smallfelem in) {
}
/* To preserve endianness when using BN_bn2bin and BN_bin2bn. */
-static void flip_endian(u8 *out, const u8 *in, unsigned len) {
- unsigned i;
+static void flip_endian(u8 *out, const u8 *in, size_t len) {
+ size_t i;
for (i = 0; i < len; ++i) {
out[i] = in[len - 1 - i];
}
@@ -111,7 +110,7 @@ static int BN_to_felem(felem out, const BIGNUM *bn) {
felem_bytearray b_out;
/* BN_bn2bin eats leading zeroes */
memset(b_out, 0, sizeof(b_out));
- unsigned num_bytes = BN_num_bytes(bn);
+ size_t num_bytes = BN_num_bytes(bn);
if (num_bytes > sizeof(b_out)) {
OPENSSL_PUT_ERROR(EC, EC_R_BIGNUM_OUT_OF_RANGE);
return 0;
@@ -134,20 +133,6 @@ static BIGNUM *smallfelem_to_BN(BIGNUM *out, const smallfelem in) {
/* Field operations. */
-static void smallfelem_one(smallfelem out) {
- out[0] = 1;
- out[1] = 0;
- out[2] = 0;
- out[3] = 0;
-}
-
-static void smallfelem_assign(smallfelem out, const smallfelem in) {
- out[0] = in[0];
- out[1] = in[1];
- out[2] = in[2];
- out[3] = in[3];
-}
-
static void felem_assign(felem out, const felem in) {
out[0] = in[0];
out[1] = in[1];
@@ -343,8 +328,7 @@ static void felem_shrink(smallfelem out, const felem in) {
* conditionally subtract kPrime if tmp[3] is large enough. */
high = tmp[3] >> 64;
/* As tmp[3] < 2^65, high is either 1 or 0 */
- high <<= 63;
- high >>= 63;
+ high = ~(high - 1);
/* high is:
* all ones if the high word of tmp[3] is 1
* all zeros if the high word of tmp[3] if 0 */
@@ -735,7 +719,7 @@ static void felem_contract(smallfelem out, const felem in) {
* each u64, from most-significant to least significant. For each one, if
* all words so far have been equal (m is all ones) then a non-equal
* result is the answer. Otherwise we continue. */
- unsigned i;
+ size_t i;
for (i = 3; i < 4; i--) {
u64 equal;
uint128_t a = ((uint128_t)kPrime[i]) - out[i];
@@ -779,25 +763,6 @@ static void felem_contract(smallfelem out, const felem in) {
subtract_u64(&out[3], &carry, result & kPrime[3]);
}
-static void smallfelem_square_contract(smallfelem out, const smallfelem in) {
- longfelem longtmp;
- felem tmp;
-
- smallfelem_square(longtmp, in);
- felem_reduce(tmp, longtmp);
- felem_contract(out, tmp);
-}
-
-static void smallfelem_mul_contract(smallfelem out, const smallfelem in1,
- const smallfelem in2) {
- longfelem longtmp;
- felem tmp;
-
- smallfelem_mul(longtmp, in1, in2);
- felem_reduce(tmp, longtmp);
- felem_contract(out, tmp);
-}
-
/* felem_is_zero returns a limb with all bits set if |in| == 0 (mod p) and 0
* otherwise.
* On entry:
@@ -834,10 +799,6 @@ static limb smallfelem_is_zero(const smallfelem small) {
return result;
}
-static int smallfelem_is_zero_int(const smallfelem small) {
- return (int)(smallfelem_is_zero(small) & ((limb)1));
-}
-
/* felem_inv calculates |out| = |in|^{-1}
*
* Based on Fermat's Little Theorem:
@@ -849,7 +810,7 @@ static void felem_inv(felem out, const felem in) {
/* each e_I will hold |in|^{2^I - 1} */
felem e2, e4, e8, e16, e32, e64;
longfelem tmp;
- unsigned i;
+ size_t i;
felem_square(tmp, in);
felem_reduce(ftmp, tmp); /* 2^1 */
@@ -937,14 +898,6 @@ static void felem_inv(felem out, const felem in) {
felem_reduce(out, tmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */
}
-static void smallfelem_inv_contract(smallfelem out, const smallfelem in) {
- felem tmp;
-
- smallfelem_expand(tmp, in);
- felem_inv(tmp, tmp);
- felem_contract(out, tmp);
-}
-
/* Group operations
* ----------------
*
@@ -1055,7 +1008,7 @@ static void point_double_small(smallfelem x_out, smallfelem y_out,
/* copy_conditional copies in to out iff mask is all ones. */
static void copy_conditional(felem out, const felem in, limb mask) {
- unsigned i;
+ size_t i;
for (i = 0; i < NLIMBS; ++i) {
const limb tmp = mask & (in[i] ^ out[i]);
out[i] ^= tmp;
@@ -1064,7 +1017,7 @@ static void copy_conditional(felem out, const felem in, limb mask) {
/* copy_small_conditional copies in to out iff mask is all ones. */
static void copy_small_conditional(felem out, const smallfelem in, limb mask) {
- unsigned i;
+ size_t i;
const u64 mask64 = mask;
for (i = 0; i < NLIMBS; ++i) {
out[i] = ((limb)(in[i] & mask64)) | (out[i] & ~mask);
@@ -1448,12 +1401,13 @@ static const smallfelem g_pre_comp[2][16][3] = {
/* select_point selects the |idx|th point from a precomputation table and
* copies it to out. */
-static void select_point(const u64 idx, unsigned int size,
- const smallfelem pre_comp[16][3], smallfelem out[3]) {
- unsigned i, j;
+static void select_point(const u64 idx, size_t size,
+ const smallfelem pre_comp[/*size*/][3],
+ smallfelem out[3]) {
u64 *outlimbs = &out[0][0];
memset(outlimbs, 0, 3 * sizeof(smallfelem));
+ size_t i;
for (i = 0; i < size; i++) {
const u64 *inlimbs = (const u64 *)&pre_comp[i][0][0];
u64 mask = i ^ idx;
@@ -1462,6 +1416,7 @@ static void select_point(const u64 idx, unsigned int size,
mask |= mask >> 1;
mask &= 1;
mask--;
+ size_t j;
for (j = 0; j < NLIMBS * 3; j++) {
outlimbs[j] |= inlimbs[j] & mask;
}
@@ -1483,10 +1438,8 @@ static char get_bit(const felem_bytearray in, int i) {
* Output point (X, Y, Z) is stored in x_out, y_out, z_out. */
static void batch_mul(felem x_out, felem y_out, felem z_out,
const felem_bytearray scalars[],
- const unsigned num_points, const u8 *g_scalar,
- const int mixed, const smallfelem pre_comp[][17][3]) {
- int i, skip;
- unsigned num, gen_mul = (g_scalar != NULL);
+ const size_t num_points, const u8 *g_scalar,
+ const smallfelem pre_comp[][17][3]) {
felem nq[3], ftmp;
smallfelem tmp[3];
u64 bits;
@@ -1499,16 +1452,16 @@ static void batch_mul(felem x_out, felem y_out, felem z_out,
* of the generator (two in each of the last 32 rounds) and additions of
* other points multiples (every 5th round). */
- skip = 1; /* save two point operations in the first
- * round */
- for (i = (num_points ? 255 : 31); i >= 0; --i) {
+ int skip = 1; /* save two point operations in the first round */
+ size_t i = num_points != 0 ? 255 : 31;
+ for (;;) {
/* double */
if (!skip) {
point_double(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2]);
}
/* add multiples of the generator */
- if (gen_mul && i <= 31) {
+ if (g_scalar != NULL && i <= 31) {
/* first, look 32 bits upwards */
bits = get_bit(g_scalar, i + 224) << 3;
bits |= get_bit(g_scalar, i + 160) << 2;
@@ -1518,9 +1471,8 @@ static void batch_mul(felem x_out, felem y_out, felem z_out,
select_point(bits, 16, g_pre_comp[1], tmp);
if (!skip) {
- /* Arg 1 below is for "mixed" */
- point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1, tmp[0], tmp[1],
- tmp[2]);
+ point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1 /* mixed */,
+ tmp[0], tmp[1], tmp[2]);
} else {
smallfelem_expand(nq[0], tmp[0]);
smallfelem_expand(nq[1], tmp[1]);
@@ -1535,14 +1487,14 @@ static void batch_mul(felem x_out, felem y_out, felem z_out,
bits |= get_bit(g_scalar, i);
/* select the point to add, in constant time */
select_point(bits, 16, g_pre_comp[0], tmp);
- /* Arg 1 below is for "mixed" */
- point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1, tmp[0], tmp[1],
- tmp[2]);
+ point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1 /* mixed */, tmp[0],
+ tmp[1], tmp[2]);
}
/* do other additions every 5 doublings */
- if (num_points && (i % 5 == 0)) {
+ if (num_points != 0 && i % 5 == 0) {
/* loop over all scalars */
+ size_t num;
for (num = 0; num < num_points; ++num) {
bits = get_bit(scalars[num], i + 4) << 5;
bits |= get_bit(scalars[num], i + 3) << 4;
@@ -1560,8 +1512,8 @@ static void batch_mul(felem x_out, felem y_out, felem z_out,
felem_contract(tmp[1], ftmp);
if (!skip) {
- point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], mixed, tmp[0],
- tmp[1], tmp[2]);
+ point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 0 /* mixed */,
+ tmp[0], tmp[1], tmp[2]);
} else {
smallfelem_expand(nq[0], tmp[0]);
smallfelem_expand(nq[1], tmp[1]);
@@ -1570,6 +1522,11 @@ static void batch_mul(felem x_out, felem y_out, felem z_out,
}
}
}
+
+ if (i == 0) {
+ break;
+ }
+ --i;
}
felem_assign(x_out, nq[0]);
felem_assign(y_out, nq[1]);
@@ -1583,10 +1540,10 @@ static void batch_mul(felem x_out, felem y_out, felem z_out,
/* Takes the Jacobian coordinates (X, Y, Z) of a point and returns (X', Y') =
* (X/Z^2, Y/Z^3). */
-int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group,
- const EC_POINT *point,
- BIGNUM *x, BIGNUM *y,
- BN_CTX *ctx) {
+static int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group,
+ const EC_POINT *point,
+ BIGNUM *x, BIGNUM *y,
+ BN_CTX *ctx) {
felem z1, z2, x_in, y_in;
smallfelem x_out, y_out;
longfelem tmp;
@@ -1603,45 +1560,38 @@ int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group,
felem_inv(z2, z1);
felem_square(tmp, z2);
felem_reduce(z1, tmp);
- felem_mul(tmp, x_in, z1);
- felem_reduce(x_in, tmp);
- felem_contract(x_out, x_in);
- if (x != NULL && !smallfelem_to_BN(x, x_out)) {
- OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
- return 0;
+
+ if (x != NULL) {
+ felem_mul(tmp, x_in, z1);
+ felem_reduce(x_in, tmp);
+ felem_contract(x_out, x_in);
+ if (!smallfelem_to_BN(x, x_out)) {
+ OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
+ return 0;
+ }
}
- felem_mul(tmp, z1, z2);
- felem_reduce(z1, tmp);
- felem_mul(tmp, y_in, z1);
- felem_reduce(y_in, tmp);
- felem_contract(y_out, y_in);
- if (y != NULL && !smallfelem_to_BN(y, y_out)) {
- OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
- return 0;
+
+ if (y != NULL) {
+ felem_mul(tmp, z1, z2);
+ felem_reduce(z1, tmp);
+ felem_mul(tmp, y_in, z1);
+ felem_reduce(y_in, tmp);
+ felem_contract(y_out, y_in);
+ if (!smallfelem_to_BN(y, y_out)) {
+ OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
+ return 0;
+ }
}
- return 1;
-}
-/* points below is of size |num|, and tmp_smallfelems is of size |num+1| */
-static void make_points_affine(size_t num, smallfelem points[][3],
- smallfelem tmp_smallfelems[]) {
- /* Runs in constant time, unless an input is the point at infinity (which
- * normally shouldn't happen). */
- ec_GFp_nistp_points_make_affine_internal(
- num, points, sizeof(smallfelem), tmp_smallfelems,
- (void (*)(void *))smallfelem_one,
- (int (*)(const void *))smallfelem_is_zero_int,
- (void (*)(void *, const void *))smallfelem_assign,
- (void (*)(void *, const void *))smallfelem_square_contract,
- (void (*)(void *, const void *, const void *))smallfelem_mul_contract,
- (void (*)(void *, const void *))smallfelem_inv_contract,
- /* nothing to contract */
- (void (*)(void *, const void *))smallfelem_assign);
+ return 1;
}
-int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
- const BIGNUM *g_scalar, const EC_POINT *p_,
- const BIGNUM *p_scalar_, BN_CTX *ctx) {
+static int ec_GFp_nistp256_points_mul(const EC_GROUP *group,
+ EC_POINT *r,
+ const BIGNUM *g_scalar,
+ const EC_POINT *p_,
+ const BIGNUM *p_scalar_,
+ BN_CTX *ctx) {
/* TODO: This function used to take |points| and |scalars| as arrays of
* |num| elements. The code below should be simplified to work in terms of |p|
* and |p_scalar|. */
@@ -1650,16 +1600,12 @@ int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
BIGNUM const *const *scalars = p_ != NULL ? &p_scalar_ : NULL;
int ret = 0;
- int j;
- int mixed = 0;
BN_CTX *new_ctx = NULL;
BIGNUM *x, *y, *z, *tmp_scalar;
felem_bytearray g_secret;
felem_bytearray *secrets = NULL;
smallfelem(*pre_comp)[17][3] = NULL;
- smallfelem *tmp_smallfelems = NULL;
felem_bytearray tmp;
- unsigned i, num_bytes;
size_t num_points = num;
smallfelem x_in, y_in, z_in;
felem x_out, y_out, z_out;
@@ -1682,19 +1628,9 @@ int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
}
if (num_points > 0) {
- if (num_points >= 3) {
- /* unless we precompute multiples for just one or two points,
- * converting those into affine form is time well spent */
- mixed = 1;
- }
secrets = OPENSSL_malloc(num_points * sizeof(felem_bytearray));
pre_comp = OPENSSL_malloc(num_points * sizeof(smallfelem[17][3]));
- if (mixed) {
- tmp_smallfelems =
- OPENSSL_malloc((num_points * 17 + 1) * sizeof(smallfelem));
- }
- if (secrets == NULL || pre_comp == NULL ||
- (mixed && tmp_smallfelems == NULL)) {
+ if (secrets == NULL || pre_comp == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -1703,6 +1639,7 @@ int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
* i.e., they contribute nothing to the linear combination. */
memset(secrets, 0, num_points * sizeof(felem_bytearray));
memset(pre_comp, 0, num_points * 17 * 3 * sizeof(smallfelem));
+ size_t i;
for (i = 0; i < num_points; ++i) {
if (i == num) {
/* we didn't have a valid precomputation, so we pick the generator. */
@@ -1714,6 +1651,7 @@ int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
p_scalar = scalars[i];
}
if (p_scalar != NULL && p != NULL) {
+ size_t num_bytes;
/* reduce g_scalar to 0 <= g_scalar < 2^256 */
if (BN_num_bits(p_scalar) > 256 || BN_is_negative(p_scalar)) {
/* this is an unusual input, and we don't guarantee
@@ -1736,6 +1674,7 @@ int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
felem_shrink(pre_comp[i][1][0], x_out);
felem_shrink(pre_comp[i][1][1], y_out);
felem_shrink(pre_comp[i][1][2], z_out);
+ size_t j;
for (j = 2; j <= 16; ++j) {
if (j & 1) {
point_add_small(pre_comp[i][j][0], pre_comp[i][j][1],
@@ -1751,12 +1690,11 @@ int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
}
}
}
- if (mixed) {
- make_points_affine(num_points * 17, pre_comp[0], tmp_smallfelems);
- }
}
if (g_scalar != NULL) {
+ size_t num_bytes;
+
memset(g_secret, 0, sizeof(g_secret));
/* reduce g_scalar to 0 <= g_scalar < 2^256 */
if (BN_num_bits(g_scalar) > 256 || BN_is_negative(g_scalar)) {
@@ -1773,7 +1711,7 @@ int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
flip_endian(g_secret, tmp, num_bytes);
}
batch_mul(x_out, y_out, z_out, (const felem_bytearray(*))secrets,
- num_points, g_scalar != NULL ? g_secret : NULL, mixed,
+ num_points, g_scalar != NULL ? g_secret : NULL,
(const smallfelem(*)[17][3])pre_comp);
/* reduce the output to its unique minimal representation */
@@ -1793,7 +1731,6 @@ err:
BN_CTX_free(new_ctx);
OPENSSL_free(secrets);
OPENSSL_free(pre_comp);
- OPENSSL_free(tmp_smallfelems);
return ret;
}
@@ -1807,7 +1744,7 @@ const EC_METHOD *EC_GFp_nistp256_method(void) {
ec_GFp_nistp256_points_mul,
0 /* check_pub_key_order */,
ec_GFp_simple_field_mul, ec_GFp_simple_field_sqr,
- 0 /* field_encode */, 0 /* field_decode */, 0 /* field_set_to_one */
+ 0 /* field_encode */, 0 /* field_decode */,
};
return &ret;
diff --git a/crypto/ec/p256-x86_64.c b/crypto/ec/p256-x86_64.c
index ca967b31..e1afec48 100644
--- a/crypto/ec/p256-x86_64.c
+++ b/crypto/ec/p256-x86_64.c
@@ -205,9 +205,7 @@ static void ecp_nistz256_mod_inverse(BN_ULONG r[P256_LIMBS],
ecp_nistz256_sqr_mont(res, res);
ecp_nistz256_sqr_mont(res, res);
- ecp_nistz256_mul_mont(res, res, in);
-
- memcpy(r, res, sizeof(res));
+ ecp_nistz256_mul_mont(r, res, in);
}
/* ecp_nistz256_bignum_to_field_elem copies the contents of |in| to |out| and
@@ -390,17 +388,6 @@ static int ecp_nistz256_points_mul(
BN_CTX *new_ctx = NULL;
int ctx_started = 0;
- /* Need 256 bits for space for all coordinates. */
- if (bn_wexpand(&r->X, P256_LIMBS) == NULL ||
- bn_wexpand(&r->Y, P256_LIMBS) == NULL ||
- bn_wexpand(&r->Z, P256_LIMBS) == NULL) {
- OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- r->X.top = P256_LIMBS;
- r->Y.top = P256_LIMBS;
- r->Z.top = P256_LIMBS;
-
if (g_scalar != NULL) {
if (BN_num_bits(g_scalar) > 256 || BN_is_negative(g_scalar)) {
if (ctx == NULL) {
@@ -494,15 +481,12 @@ static int ecp_nistz256_points_mul(
}
}
- memcpy(r->X.d, p.p.X, sizeof(p.p.X));
- memcpy(r->Y.d, p.p.Y, sizeof(p.p.Y));
- memcpy(r->Z.d, p.p.Z, sizeof(p.p.Z));
-
/* Not constant-time, but we're only operating on the public output. */
- bn_correct_top(&r->X);
- bn_correct_top(&r->Y);
- bn_correct_top(&r->Z);
- r->Z_is_one = BN_is_one(&r->Z);
+ if (!bn_set_words(&r->X, p.p.X, P256_LIMBS) ||
+ !bn_set_words(&r->Y, p.p.Y, P256_LIMBS) ||
+ !bn_set_words(&r->Z, p.p.Z, P256_LIMBS)) {
+ return 0;
+ }
ret = 1;
@@ -518,8 +502,6 @@ static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point,
BIGNUM *x, BIGNUM *y, BN_CTX *ctx) {
BN_ULONG z_inv2[P256_LIMBS];
BN_ULONG z_inv3[P256_LIMBS];
- BN_ULONG x_aff[P256_LIMBS];
- BN_ULONG y_aff[P256_LIMBS];
BN_ULONG point_x[P256_LIMBS], point_y[P256_LIMBS], point_z[P256_LIMBS];
if (EC_POINT_is_at_infinity(group, point)) {
@@ -536,7 +518,12 @@ static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point,
ecp_nistz256_mod_inverse(z_inv3, point_z);
ecp_nistz256_sqr_mont(z_inv2, z_inv3);
- ecp_nistz256_mul_mont(x_aff, z_inv2, point_x);
+
+ /* Instead of using |ecp_nistz256_from_mont| to convert the |x| coordinate
+ * and then calling |ecp_nistz256_from_mont| again to convert the |y|
+ * coordinate below, convert the common factor |z_inv2| once now, saving one
+ * reduction. */
+ ecp_nistz256_from_mont(z_inv2, z_inv2);
if (x != NULL) {
if (bn_wexpand(x, P256_LIMBS) == NULL) {
@@ -544,19 +531,20 @@ static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point,
return 0;
}
x->top = P256_LIMBS;
- ecp_nistz256_from_mont(x->d, x_aff);
+ x->neg = 0;
+ ecp_nistz256_mul_mont(x->d, z_inv2, point_x);
bn_correct_top(x);
}
if (y != NULL) {
ecp_nistz256_mul_mont(z_inv3, z_inv3, z_inv2);
- ecp_nistz256_mul_mont(y_aff, z_inv3, point_y);
if (bn_wexpand(y, P256_LIMBS) == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
return 0;
}
y->top = P256_LIMBS;
- ecp_nistz256_from_mont(y->d, y_aff);
+ y->neg = 0;
+ ecp_nistz256_mul_mont(y->d, z_inv3, point_y);
bn_correct_top(y);
}
@@ -576,7 +564,6 @@ const EC_METHOD *EC_GFp_nistz256_method(void) {
ec_GFp_mont_field_sqr,
ec_GFp_mont_field_encode,
ec_GFp_mont_field_decode,
- ec_GFp_mont_field_set_to_one,
};
return &ret;
diff --git a/crypto/ec/simple.c b/crypto/ec/simple.c
index 4eb612eb..4508d83f 100644
--- a/crypto/ec/simple.c
+++ b/crypto/ec/simple.c
@@ -82,16 +82,16 @@
* field_sqr methods will be used for multiplication, and field_encode and
* field_decode (if defined) will be used for converting between
* representations.
-
- * Functions ec_GFp_simple_points_make_affine() and
- * ec_GFp_simple_point_get_affine_coordinates() specifically assume that if a
- * non-trivial representation is used, it is a Montgomery representation (i.e.
- * 'encoding' means multiplying by some factor R). */
+ *
+ * Functions here specifically assume that if a non-trivial representation is
+ * used, it is a Montgomery representation (i.e. 'encoding' means multiplying
+ * by some factor R). */
int ec_GFp_simple_group_init(EC_GROUP *group) {
BN_init(&group->field);
BN_init(&group->a);
BN_init(&group->b);
+ BN_init(&group->one);
group->a_is_minus3 = 0;
return 1;
}
@@ -100,12 +100,14 @@ void ec_GFp_simple_group_finish(EC_GROUP *group) {
BN_free(&group->field);
BN_free(&group->a);
BN_free(&group->b);
+ BN_free(&group->one);
}
int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) {
if (!BN_copy(&dest->field, &src->field) ||
!BN_copy(&dest->a, &src->a) ||
- !BN_copy(&dest->b, &src->b)) {
+ !BN_copy(&dest->b, &src->b) ||
+ !BN_copy(&dest->one, &src->one)) {
return 0;
}
@@ -172,6 +174,14 @@ int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
}
group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field));
+ if (group->meth->field_encode != NULL) {
+ if (!group->meth->field_encode(group, &group->one, BN_value_one(), ctx)) {
+ goto err;
+ }
+ } else if (!BN_copy(&group->one, BN_value_one())) {
+ goto err;
+ }
+
ret = 1;
err:
@@ -228,7 +238,6 @@ int ec_GFp_simple_point_init(EC_POINT *point) {
BN_init(&point->X);
BN_init(&point->Y);
BN_init(&point->Z);
- point->Z_is_one = 0;
return 1;
}
@@ -243,7 +252,6 @@ void ec_GFp_simple_point_clear_finish(EC_POINT *point) {
BN_clear_free(&point->X);
BN_clear_free(&point->Y);
BN_clear_free(&point->Z);
- point->Z_is_one = 0;
}
int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) {
@@ -252,18 +260,32 @@ int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) {
!BN_copy(&dest->Z, &src->Z)) {
return 0;
}
- dest->Z_is_one = src->Z_is_one;
return 1;
}
int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group,
EC_POINT *point) {
- point->Z_is_one = 0;
BN_zero(&point->Z);
return 1;
}
+static int set_Jprojective_coordinate_GFp(const EC_GROUP *group, BIGNUM *out,
+ const BIGNUM *in, BN_CTX *ctx) {
+ if (in == NULL) {
+ return 1;
+ }
+ if (BN_is_negative(in) ||
+ BN_cmp(in, &group->field) >= 0) {
+ OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
+ return 0;
+ }
+ if (group->meth->field_encode) {
+ return group->meth->field_encode(group, out, in, ctx);
+ }
+ return BN_copy(out, in) != NULL;
+}
+
int ec_GFp_simple_set_Jprojective_coordinates_GFp(
const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, const BIGNUM *y,
const BIGNUM *z, BN_CTX *ctx) {
@@ -277,43 +299,10 @@ int ec_GFp_simple_set_Jprojective_coordinates_GFp(
}
}
- if (x != NULL) {
- if (!BN_nnmod(&point->X, x, &group->field, ctx)) {
- goto err;
- }
- if (group->meth->field_encode &&
- !group->meth->field_encode(group, &point->X, &point->X, ctx)) {
- goto err;
- }
- }
-
- if (y != NULL) {
- if (!BN_nnmod(&point->Y, y, &group->field, ctx)) {
- goto err;
- }
- if (group->meth->field_encode &&
- !group->meth->field_encode(group, &point->Y, &point->Y, ctx)) {
- goto err;
- }
- }
-
- if (z != NULL) {
- int Z_is_one;
-
- if (!BN_nnmod(&point->Z, z, &group->field, ctx)) {
- goto err;
- }
- Z_is_one = BN_is_one(&point->Z);
- if (group->meth->field_encode) {
- if (Z_is_one && (group->meth->field_set_to_one != 0)) {
- if (!group->meth->field_set_to_one(group, &point->Z, ctx)) {
- goto err;
- }
- } else if (!group->meth->field_encode(group, &point->Z, &point->Z, ctx)) {
- goto err;
- }
- }
- point->Z_is_one = Z_is_one;
+ if (!set_Jprojective_coordinate_GFp(group, &point->X, x, ctx) ||
+ !set_Jprojective_coordinate_GFp(group, &point->Y, y, ctx) ||
+ !set_Jprojective_coordinate_GFp(group, &point->Z, z, ctx)) {
+ goto err;
}
ret = 1;
@@ -379,109 +368,6 @@ int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group,
BN_value_one(), ctx);
}
-int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group,
- const EC_POINT *point, BIGNUM *x,
- BIGNUM *y, BN_CTX *ctx) {
- BN_CTX *new_ctx = NULL;
- BIGNUM *Z, *Z_1, *Z_2, *Z_3;
- const BIGNUM *Z_;
- int ret = 0;
-
- if (EC_POINT_is_at_infinity(group, point)) {
- OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
- return 0;
- }
-
- if (ctx == NULL) {
- ctx = new_ctx = BN_CTX_new();
- if (ctx == NULL) {
- return 0;
- }
- }
-
- BN_CTX_start(ctx);
- Z = BN_CTX_get(ctx);
- Z_1 = BN_CTX_get(ctx);
- Z_2 = BN_CTX_get(ctx);
- Z_3 = BN_CTX_get(ctx);
- if (Z == NULL || Z_1 == NULL || Z_2 == NULL || Z_3 == NULL) {
- goto err;
- }
-
- /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */
-
- if (group->meth->field_decode) {
- if (!group->meth->field_decode(group, Z, &point->Z, ctx)) {
- goto err;
- }
- Z_ = Z;
- } else {
- Z_ = &point->Z;
- }
-
- if (BN_is_one(Z_)) {
- if (group->meth->field_decode) {
- if (x != NULL && !group->meth->field_decode(group, x, &point->X, ctx)) {
- goto err;
- }
- if (y != NULL && !group->meth->field_decode(group, y, &point->Y, ctx)) {
- goto err;
- }
- } else {
- if (x != NULL && !BN_copy(x, &point->X)) {
- goto err;
- }
- if (y != NULL && !BN_copy(y, &point->Y)) {
- goto err;
- }
- }
- } else {
- if (!BN_mod_inverse(Z_1, Z_, &group->field, ctx)) {
- OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
- goto err;
- }
-
- if (group->meth->field_encode == 0) {
- /* field_sqr works on standard representation */
- if (!group->meth->field_sqr(group, Z_2, Z_1, ctx)) {
- goto err;
- }
- } else if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx)) {
- goto err;
- }
-
- /* in the Montgomery case, field_mul will cancel out Montgomery factor in
- * X: */
- if (x != NULL && !group->meth->field_mul(group, x, &point->X, Z_2, ctx)) {
- goto err;
- }
-
- if (y != NULL) {
- if (group->meth->field_encode == 0) {
- /* field_mul works on standard representation */
- if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) {
- goto err;
- }
- } else if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx)) {
- goto err;
- }
-
- /* in the Montgomery case, field_mul will cancel out Montgomery factor in
- * Y: */
- if (!group->meth->field_mul(group, y, &point->Y, Z_3, ctx)) {
- goto err;
- }
- }
- }
-
- ret = 1;
-
-err:
- BN_CTX_end(ctx);
- BN_CTX_free(new_ctx);
- return ret;
-}
-
int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
const EC_POINT *b, BN_CTX *ctx) {
int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
@@ -531,7 +417,9 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
*/
/* n1, n2 */
- if (b->Z_is_one) {
+ int b_Z_is_one = BN_cmp(&b->Z, &group->one) == 0;
+
+ if (b_Z_is_one) {
if (!BN_copy(n1, &a->X) || !BN_copy(n2, &a->Y)) {
goto end;
}
@@ -552,7 +440,8 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
}
/* n3, n4 */
- if (a->Z_is_one) {
+ int a_Z_is_one = BN_cmp(&a->Z, &group->one) == 0;
+ if (a_Z_is_one) {
if (!BN_copy(n3, &b->X) || !BN_copy(n4, &b->Y)) {
goto end;
}
@@ -590,7 +479,6 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
} else {
/* a is the inverse of b */
BN_zero(&r->Z);
- r->Z_is_one = 0;
ret = 1;
goto end;
}
@@ -605,16 +493,16 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
/* 'n8' = n2 + n4 */
/* Z_r */
- if (a->Z_is_one && b->Z_is_one) {
+ if (a_Z_is_one && b_Z_is_one) {
if (!BN_copy(&r->Z, n5)) {
goto end;
}
} else {
- if (a->Z_is_one) {
+ if (a_Z_is_one) {
if (!BN_copy(n0, &b->Z)) {
goto end;
}
- } else if (b->Z_is_one) {
+ } else if (b_Z_is_one) {
if (!BN_copy(n0, &a->Z)) {
goto end;
}
@@ -625,7 +513,7 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
goto end;
}
}
- r->Z_is_one = 0;
+
/* Z_r = Z_a * Z_b * n5 */
/* X_r */
@@ -685,7 +573,6 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
if (EC_POINT_is_at_infinity(group, a)) {
BN_zero(&r->Z);
- r->Z_is_one = 0;
return 1;
}
@@ -715,7 +602,7 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
*/
/* n1 */
- if (a->Z_is_one) {
+ if (BN_cmp(&a->Z, &group->one) == 0) {
if (!field_sqr(group, n0, &a->X, ctx) ||
!BN_mod_lshift1_quick(n1, n0, p) ||
!BN_mod_add_quick(n0, n0, n1, p) ||
@@ -748,7 +635,7 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
}
/* Z_r */
- if (a->Z_is_one) {
+ if (BN_cmp(&a->Z, &group->one) == 0) {
if (!BN_copy(n0, &a->Y)) {
goto err;
}
@@ -758,7 +645,6 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
if (!BN_mod_lshift1_quick(&r->Z, n0, p)) {
goto err;
}
- r->Z_is_one = 0;
/* Z_r = 2 * Y_a * Z_a */
/* n2 */
@@ -810,7 +696,7 @@ int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) {
}
int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) {
- return !point->Z_is_one && BN_is_zero(&point->Z);
+ return BN_is_zero(&point->Z);
}
int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
@@ -821,7 +707,7 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
const BIGNUM *p;
BN_CTX *new_ctx = NULL;
BIGNUM *rh, *tmp, *Z4, *Z6;
- int ret = -1;
+ int ret = 0;
if (EC_POINT_is_at_infinity(group, point)) {
return 1;
@@ -834,7 +720,7 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
if (ctx == NULL) {
ctx = new_ctx = BN_CTX_new();
if (ctx == NULL) {
- return -1;
+ return 0;
}
}
@@ -862,7 +748,7 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
goto err;
}
- if (!point->Z_is_one) {
+ if (BN_cmp(&point->Z, &group->one) != 0) {
if (!field_sqr(group, tmp, &point->Z, ctx) ||
!field_sqr(group, Z4, tmp, ctx) ||
!field_mul(group, Z6, Z4, tmp, ctx)) {
@@ -891,8 +777,6 @@ int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
goto err;
}
} else {
- /* point->Z_is_one */
-
/* rh := (rh + a)*X */
if (!BN_mod_add_quick(rh, rh, &group->a, p) ||
!field_mul(group, rh, rh, &point->X, ctx)) {
@@ -941,7 +825,10 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
return 1;
}
- if (a->Z_is_one && b->Z_is_one) {
+ int a_Z_is_one = BN_cmp(&a->Z, &group->one) == 0;
+ int b_Z_is_one = BN_cmp(&b->Z, &group->one) == 0;
+
+ if (a_Z_is_one && b_Z_is_one) {
return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1;
}
@@ -970,7 +857,7 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
* (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3).
*/
- if (!b->Z_is_one) {
+ if (!b_Z_is_one) {
if (!field_sqr(group, Zb23, &b->Z, ctx) ||
!field_mul(group, tmp1, &a->X, Zb23, ctx)) {
goto end;
@@ -979,7 +866,7 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
} else {
tmp1_ = &a->X;
}
- if (!a->Z_is_one) {
+ if (!a_Z_is_one) {
if (!field_sqr(group, Za23, &a->Z, ctx) ||
!field_mul(group, tmp2, &b->X, Za23, ctx)) {
goto end;
@@ -996,7 +883,7 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
}
- if (!b->Z_is_one) {
+ if (!b_Z_is_one) {
if (!field_mul(group, Zb23, Zb23, &b->Z, ctx) ||
!field_mul(group, tmp1, &a->Y, Zb23, ctx)) {
goto end;
@@ -1005,7 +892,7 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
} else {
tmp1_ = &a->Y;
}
- if (!a->Z_is_one) {
+ if (!a_Z_is_one) {
if (!field_mul(group, Za23, Za23, &a->Z, ctx) ||
!field_mul(group, tmp2, &b->Y, Za23, ctx)) {
goto end;
@@ -1036,7 +923,8 @@ int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point,
BIGNUM *x, *y;
int ret = 0;
- if (point->Z_is_one || EC_POINT_is_at_infinity(group, point)) {
+ if (BN_cmp(&point->Z, &group->one) == 0 ||
+ EC_POINT_is_at_infinity(group, point)) {
return 1;
}
@@ -1058,7 +946,7 @@ int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point,
!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
goto err;
}
- if (!point->Z_is_one) {
+ if (BN_cmp(&point->Z, &group->one) != 0) {
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -1117,14 +1005,8 @@ int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num,
goto err;
}
} else {
- if (group->meth->field_set_to_one != 0) {
- if (!group->meth->field_set_to_one(group, prod_Z[0], ctx)) {
- goto err;
- }
- } else {
- if (!BN_one(prod_Z[0])) {
- goto err;
- }
+ if (BN_copy(prod_Z[0], &group->one) == NULL) {
+ goto err;
}
}
@@ -1195,16 +1077,9 @@ int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num,
goto err;
}
- if (group->meth->field_set_to_one != NULL) {
- if (!group->meth->field_set_to_one(group, &p->Z, ctx)) {
- goto err;
- }
- } else {
- if (!BN_one(&p->Z)) {
- goto err;
- }
+ if (BN_copy(&p->Z, &group->one) == NULL) {
+ goto err;
}
- p->Z_is_one = 1;
}
}
diff --git a/crypto/ec/util-64.c b/crypto/ec/util-64.c
index 171b0631..40062712 100644
--- a/crypto/ec/util-64.c
+++ b/crypto/ec/util-64.c
@@ -21,80 +21,6 @@
#include "internal.h"
-/* Convert an array of points into affine coordinates. (If the point at
- * infinity is found (Z = 0), it remains unchanged.) This function is
- * essentially an equivalent to EC_POINTs_make_affine(), but works with the
- * internal representation of points as used by ecp_nistp###.c rather than
- * with (BIGNUM-based) EC_POINT data structures. point_array is the
- * input/output buffer ('num' points in projective form, i.e. three
- * coordinates each), based on an internal representation of field elements
- * of size 'felem_size'. tmp_felems needs to point to a temporary array of
- * 'num'+1 field elements for storage of intermediate values. */
-void ec_GFp_nistp_points_make_affine_internal(
- size_t num, void *point_array, size_t felem_size, void *tmp_felems,
- void (*felem_one)(void *out), int (*felem_is_zero)(const void *in),
- void (*felem_assign)(void *out, const void *in),
- void (*felem_square)(void *out, const void *in),
- void (*felem_mul)(void *out, const void *in1, const void *in2),
- void (*felem_inv)(void *out, const void *in),
- void (*felem_contract)(void *out, const void *in)) {
- int i = 0;
-
-#define tmp_felem(I) (&((char *)tmp_felems)[(I)*felem_size])
-#define X(I) (&((char *)point_array)[3 * (I)*felem_size])
-#define Y(I) (&((char *)point_array)[(3 * (I) + 1) * felem_size])
-#define Z(I) (&((char *)point_array)[(3 * (I) + 2) * felem_size])
-
- if (!felem_is_zero(Z(0))) {
- felem_assign(tmp_felem(0), Z(0));
- } else {
- felem_one(tmp_felem(0));
- }
-
- for (i = 1; i < (int)num; i++) {
- if (!felem_is_zero(Z(i))) {
- felem_mul(tmp_felem(i), tmp_felem(i - 1), Z(i));
- } else {
- felem_assign(tmp_felem(i), tmp_felem(i - 1));
- }
- }
- /* Now each tmp_felem(i) is the product of Z(0) .. Z(i), skipping any
- * zero-valued factors: if Z(i) = 0, we essentially pretend that Z(i) = 1. */
-
- felem_inv(tmp_felem(num - 1), tmp_felem(num - 1));
- for (i = num - 1; i >= 0; i--) {
- if (i > 0) {
- /* tmp_felem(i-1) is the product of Z(0) .. Z(i-1), tmp_felem(i)
- * is the inverse of the product of Z(0) .. Z(i). */
- /* 1/Z(i) */
- felem_mul(tmp_felem(num), tmp_felem(i - 1), tmp_felem(i));
- } else {
- felem_assign(tmp_felem(num), tmp_felem(0)); /* 1/Z(0) */
- }
-
- if (!felem_is_zero(Z(i))) {
- if (i > 0) {
- /* For next iteration, replace tmp_felem(i-1) by its inverse. */
- felem_mul(tmp_felem(i - 1), tmp_felem(i), Z(i));
- }
-
- /* Convert point (X, Y, Z) into affine form (X/(Z^2), Y/(Z^3), 1). */
- felem_square(Z(i), tmp_felem(num)); /* 1/(Z^2) */
- felem_mul(X(i), X(i), Z(i)); /* X/(Z^2) */
- felem_mul(Z(i), Z(i), tmp_felem(num)); /* 1/(Z^3) */
- felem_mul(Y(i), Y(i), Z(i)); /* Y/(Z^3) */
- felem_contract(X(i), X(i));
- felem_contract(Y(i), Y(i));
- felem_one(Z(i));
- } else {
- if (i > 0) {
- /* For next iteration, replace tmp_felem(i-1) by its inverse. */
- felem_assign(tmp_felem(i - 1), tmp_felem(i));
- }
- }
- }
-}
-
/* This function looks at 5+1 scalar bits (5 current, 1 adjacent less
* significant bit), and recodes them into a signed digit for use in fast point
* multiplication: the use of signed rather than unsigned digits means that
diff --git a/crypto/ecdsa/ecdsa.c b/crypto/ecdsa/ecdsa.c
index 8ce23db7..70cb1189 100644
--- a/crypto/ecdsa/ecdsa.c
+++ b/crypto/ecdsa/ecdsa.c
@@ -79,10 +79,6 @@ int ECDSA_verify(int type, const uint8_t *digest, size_t digest_len,
int ret = 0;
uint8_t *der = NULL;
- if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) {
- return eckey->ecdsa_meth->verify(digest, digest_len, sig, sig_len, eckey);
- }
-
/* Decode the ECDSA signature. */
s = ECDSA_SIG_from_bytes(sig, sig_len);
if (s == NULL) {
@@ -148,11 +144,6 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
const EC_GROUP *group;
const EC_POINT *pub_key;
- if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) {
- OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED);
- return 0;
- }
-
/* check input values */
if ((group = EC_KEY_get0_group(eckey)) == NULL ||
(pub_key = EC_KEY_get0_public_key(eckey)) == NULL ||
diff --git a/crypto/ecdsa/ecdsa_asn1.c b/crypto/ecdsa/ecdsa_asn1.c
index 3a47257a..d41a5366 100644
--- a/crypto/ecdsa/ecdsa_asn1.c
+++ b/crypto/ecdsa/ecdsa_asn1.c
@@ -220,6 +220,7 @@ int i2d_ECDSA_SIG(const ECDSA_SIG *sig, uint8_t **outp) {
CBB cbb;
if (!CBB_init(&cbb, 0) ||
!ECDSA_SIG_marshal(&cbb, sig)) {
+ CBB_cleanup(&cbb);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
diff --git a/crypto/ecdsa/ecdsa_test.cc b/crypto/ecdsa/ecdsa_test.cc
index bef91c93..8d7827df 100644
--- a/crypto/ecdsa/ecdsa_test.cc
+++ b/crypto/ecdsa/ecdsa_test.cc
@@ -59,7 +59,7 @@
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/rand.h>
#include "../test/scoped_types.h"
diff --git a/crypto/err/asn1.errordata b/crypto/err/asn1.errordata
index b1b04375..c304b2ca 100644
--- a/crypto/err/asn1.errordata
+++ b/crypto/err/asn1.errordata
@@ -6,82 +6,87 @@ ASN1,104,BMPSTRING_IS_WRONG_LENGTH
ASN1,105,BN_LIB
ASN1,106,BOOLEAN_IS_WRONG_LENGTH
ASN1,107,BUFFER_TOO_SMALL
-ASN1,108,DECODE_ERROR
-ASN1,109,DEPTH_EXCEEDED
-ASN1,110,ENCODE_ERROR
-ASN1,111,ERROR_GETTING_TIME
-ASN1,112,EXPECTING_AN_ASN1_SEQUENCE
-ASN1,113,EXPECTING_AN_INTEGER
-ASN1,114,EXPECTING_AN_OBJECT
-ASN1,115,EXPECTING_A_BOOLEAN
-ASN1,116,EXPECTING_A_TIME
-ASN1,117,EXPLICIT_LENGTH_MISMATCH
-ASN1,118,EXPLICIT_TAG_NOT_CONSTRUCTED
-ASN1,119,FIELD_MISSING
-ASN1,120,FIRST_NUM_TOO_LARGE
-ASN1,121,HEADER_TOO_LONG
-ASN1,122,ILLEGAL_BITSTRING_FORMAT
-ASN1,123,ILLEGAL_BOOLEAN
-ASN1,124,ILLEGAL_CHARACTERS
-ASN1,125,ILLEGAL_FORMAT
-ASN1,126,ILLEGAL_HEX
-ASN1,127,ILLEGAL_IMPLICIT_TAG
-ASN1,128,ILLEGAL_INTEGER
-ASN1,129,ILLEGAL_NESTED_TAGGING
-ASN1,130,ILLEGAL_NULL
-ASN1,131,ILLEGAL_NULL_VALUE
-ASN1,132,ILLEGAL_OBJECT
-ASN1,133,ILLEGAL_OPTIONAL_ANY
-ASN1,134,ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE
-ASN1,135,ILLEGAL_TAGGED_ANY
-ASN1,136,ILLEGAL_TIME_VALUE
-ASN1,137,INTEGER_NOT_ASCII_FORMAT
-ASN1,138,INTEGER_TOO_LARGE_FOR_LONG
-ASN1,139,INVALID_BIT_STRING_BITS_LEFT
-ASN1,140,INVALID_BMPSTRING_LENGTH
-ASN1,141,INVALID_DIGIT
-ASN1,142,INVALID_MODIFIER
-ASN1,143,INVALID_NUMBER
-ASN1,144,INVALID_OBJECT_ENCODING
-ASN1,145,INVALID_SEPARATOR
-ASN1,146,INVALID_TIME_FORMAT
-ASN1,147,INVALID_UNIVERSALSTRING_LENGTH
-ASN1,148,INVALID_UTF8STRING
-ASN1,149,LIST_ERROR
-ASN1,150,MISSING_ASN1_EOS
-ASN1,151,MISSING_EOC
-ASN1,152,MISSING_SECOND_NUMBER
-ASN1,153,MISSING_VALUE
-ASN1,154,MSTRING_NOT_UNIVERSAL
-ASN1,155,MSTRING_WRONG_TAG
-ASN1,156,NESTED_ASN1_ERROR
-ASN1,157,NESTED_ASN1_STRING
-ASN1,158,NON_HEX_CHARACTERS
-ASN1,159,NOT_ASCII_FORMAT
-ASN1,160,NOT_ENOUGH_DATA
-ASN1,161,NO_MATCHING_CHOICE_TYPE
-ASN1,162,NULL_IS_WRONG_LENGTH
-ASN1,163,OBJECT_NOT_ASCII_FORMAT
-ASN1,164,ODD_NUMBER_OF_CHARS
-ASN1,165,SECOND_NUMBER_TOO_LARGE
-ASN1,166,SEQUENCE_LENGTH_MISMATCH
-ASN1,167,SEQUENCE_NOT_CONSTRUCTED
-ASN1,168,SEQUENCE_OR_SET_NEEDS_CONFIG
-ASN1,169,SHORT_LINE
-ASN1,170,STREAMING_NOT_SUPPORTED
-ASN1,171,STRING_TOO_LONG
-ASN1,172,STRING_TOO_SHORT
-ASN1,173,TAG_VALUE_TOO_HIGH
-ASN1,174,TIME_NOT_ASCII_FORMAT
-ASN1,175,TOO_LONG
-ASN1,176,TYPE_NOT_CONSTRUCTED
-ASN1,177,TYPE_NOT_PRIMITIVE
-ASN1,178,UNEXPECTED_EOC
-ASN1,179,UNIVERSALSTRING_IS_WRONG_LENGTH
-ASN1,180,UNKNOWN_FORMAT
-ASN1,181,UNKNOWN_TAG
-ASN1,182,UNSUPPORTED_ANY_DEFINED_BY_TYPE
-ASN1,183,UNSUPPORTED_PUBLIC_KEY_TYPE
-ASN1,184,UNSUPPORTED_TYPE
-ASN1,185,WRONG_TAG
-ASN1,186,WRONG_TYPE
+ASN1,108,CONTEXT_NOT_INITIALISED
+ASN1,109,DECODE_ERROR
+ASN1,110,DEPTH_EXCEEDED
+ASN1,111,DIGEST_AND_KEY_TYPE_NOT_SUPPORTED
+ASN1,112,ENCODE_ERROR
+ASN1,113,ERROR_GETTING_TIME
+ASN1,114,EXPECTING_AN_ASN1_SEQUENCE
+ASN1,115,EXPECTING_AN_INTEGER
+ASN1,116,EXPECTING_AN_OBJECT
+ASN1,117,EXPECTING_A_BOOLEAN
+ASN1,118,EXPECTING_A_TIME
+ASN1,119,EXPLICIT_LENGTH_MISMATCH
+ASN1,120,EXPLICIT_TAG_NOT_CONSTRUCTED
+ASN1,121,FIELD_MISSING
+ASN1,122,FIRST_NUM_TOO_LARGE
+ASN1,123,HEADER_TOO_LONG
+ASN1,124,ILLEGAL_BITSTRING_FORMAT
+ASN1,125,ILLEGAL_BOOLEAN
+ASN1,126,ILLEGAL_CHARACTERS
+ASN1,127,ILLEGAL_FORMAT
+ASN1,128,ILLEGAL_HEX
+ASN1,129,ILLEGAL_IMPLICIT_TAG
+ASN1,130,ILLEGAL_INTEGER
+ASN1,131,ILLEGAL_NESTED_TAGGING
+ASN1,132,ILLEGAL_NULL
+ASN1,133,ILLEGAL_NULL_VALUE
+ASN1,134,ILLEGAL_OBJECT
+ASN1,135,ILLEGAL_OPTIONAL_ANY
+ASN1,136,ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE
+ASN1,137,ILLEGAL_TAGGED_ANY
+ASN1,138,ILLEGAL_TIME_VALUE
+ASN1,139,INTEGER_NOT_ASCII_FORMAT
+ASN1,140,INTEGER_TOO_LARGE_FOR_LONG
+ASN1,141,INVALID_BIT_STRING_BITS_LEFT
+ASN1,142,INVALID_BMPSTRING_LENGTH
+ASN1,143,INVALID_DIGIT
+ASN1,144,INVALID_MODIFIER
+ASN1,145,INVALID_NUMBER
+ASN1,146,INVALID_OBJECT_ENCODING
+ASN1,147,INVALID_SEPARATOR
+ASN1,148,INVALID_TIME_FORMAT
+ASN1,149,INVALID_UNIVERSALSTRING_LENGTH
+ASN1,150,INVALID_UTF8STRING
+ASN1,151,LIST_ERROR
+ASN1,152,MISSING_ASN1_EOS
+ASN1,153,MISSING_EOC
+ASN1,154,MISSING_SECOND_NUMBER
+ASN1,155,MISSING_VALUE
+ASN1,156,MSTRING_NOT_UNIVERSAL
+ASN1,157,MSTRING_WRONG_TAG
+ASN1,158,NESTED_ASN1_ERROR
+ASN1,159,NESTED_ASN1_STRING
+ASN1,160,NON_HEX_CHARACTERS
+ASN1,161,NOT_ASCII_FORMAT
+ASN1,162,NOT_ENOUGH_DATA
+ASN1,163,NO_MATCHING_CHOICE_TYPE
+ASN1,164,NULL_IS_WRONG_LENGTH
+ASN1,165,OBJECT_NOT_ASCII_FORMAT
+ASN1,166,ODD_NUMBER_OF_CHARS
+ASN1,167,SECOND_NUMBER_TOO_LARGE
+ASN1,168,SEQUENCE_LENGTH_MISMATCH
+ASN1,169,SEQUENCE_NOT_CONSTRUCTED
+ASN1,170,SEQUENCE_OR_SET_NEEDS_CONFIG
+ASN1,171,SHORT_LINE
+ASN1,172,STREAMING_NOT_SUPPORTED
+ASN1,173,STRING_TOO_LONG
+ASN1,174,STRING_TOO_SHORT
+ASN1,175,TAG_VALUE_TOO_HIGH
+ASN1,176,TIME_NOT_ASCII_FORMAT
+ASN1,177,TOO_LONG
+ASN1,178,TYPE_NOT_CONSTRUCTED
+ASN1,179,TYPE_NOT_PRIMITIVE
+ASN1,180,UNEXPECTED_EOC
+ASN1,181,UNIVERSALSTRING_IS_WRONG_LENGTH
+ASN1,182,UNKNOWN_FORMAT
+ASN1,183,UNKNOWN_MESSAGE_DIGEST_ALGORITHM
+ASN1,184,UNKNOWN_SIGNATURE_ALGORITHM
+ASN1,185,UNKNOWN_TAG
+ASN1,186,UNSUPPORTED_ANY_DEFINED_BY_TYPE
+ASN1,187,UNSUPPORTED_PUBLIC_KEY_TYPE
+ASN1,188,UNSUPPORTED_TYPE
+ASN1,189,WRONG_PUBLIC_KEY_TYPE
+ASN1,190,WRONG_TAG
+ASN1,191,WRONG_TYPE
diff --git a/crypto/err/dh.errordata b/crypto/err/dh.errordata
index 571e218a..9e1b87d8 100644
--- a/crypto/err/dh.errordata
+++ b/crypto/err/dh.errordata
@@ -1,4 +1,6 @@
DH,100,BAD_GENERATOR
+DH,104,DECODE_ERROR
+DH,105,ENCODE_ERROR
DH,101,INVALID_PUBKEY
DH,102,MODULUS_TOO_LARGE
DH,103,NO_PRIVATE_VALUE
diff --git a/crypto/err/err.c b/crypto/err/err.c
index 9221bf17..48d631f4 100644
--- a/crypto/err/err.c
+++ b/crypto/err/err.c
@@ -114,9 +114,9 @@
#include <string.h>
#if defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include <openssl/mem.h>
@@ -325,7 +325,7 @@ int ERR_get_next_error_library(void) {
CRYPTO_STATIC_MUTEX_lock_write(&global_next_library_mutex);
ret = global_next_library++;
- CRYPTO_STATIC_MUTEX_unlock(&global_next_library_mutex);
+ CRYPTO_STATIC_MUTEX_unlock_write(&global_next_library_mutex);
return ret;
}
diff --git a/crypto/err/err_data_generate.go b/crypto/err/err_data_generate.go
index 24e0d66f..893ebffe 100644
--- a/crypto/err/err_data_generate.go
+++ b/crypto/err/err_data_generate.go
@@ -18,6 +18,7 @@ import (
"bufio"
"bytes"
"errors"
+ "flag"
"fmt"
"io"
"os"
@@ -26,6 +27,8 @@ import (
"strings"
)
+var verbose = flag.Bool("verbose", false, "If true, prints a status message at the end.")
+
// libraryNames must be kept in sync with the enum in err.h. The generated code
// will contain static assertions to enforce this.
var libraryNames = []string{
@@ -138,7 +141,9 @@ type stringWriter interface {
func (st *stringList) WriteTo(out stringWriter, name string) {
list := st.buildList()
- fmt.Fprintf(os.Stderr, "%s: %d bytes of list and %d bytes of string data.\n", name, 4*len(list), len(st.stringData))
+ if *verbose {
+ fmt.Fprintf(os.Stderr, "%s: %d bytes of list and %d bytes of string data.\n", name, 4*len(list), len(st.stringData))
+ }
values := "kOpenSSL" + name + "Values"
out.WriteString("const uint32_t " + values + "[] = {\n")
@@ -215,6 +220,8 @@ func (e *errorData) readErrorDataFile(filename string) error {
}
func main() {
+ flag.Parse()
+
e := &errorData{
reasons: newStringList(),
libraryMap: make(map[string]uint32),
diff --git a/crypto/err/evp.errordata b/crypto/err/evp.errordata
index cfb81b15..a482f769 100644
--- a/crypto/err/evp.errordata
+++ b/crypto/err/evp.errordata
@@ -1,47 +1,30 @@
-EVP,151,BN_DECODE_ERROR
EVP,100,BUFFER_TOO_SMALL
EVP,101,COMMAND_NOT_SUPPORTED
-EVP,146,CONTEXT_NOT_INITIALISED
-EVP,143,DECODE_ERROR
-EVP,104,DIFFERENT_KEY_TYPES
-EVP,105,DIFFERENT_PARAMETERS
-EVP,147,DIGEST_AND_KEY_TYPE_NOT_SUPPORTED
-EVP,155,ENCODE_ERROR
-EVP,107,EXPECTING_AN_EC_KEY_KEY
-EVP,141,EXPECTING_AN_RSA_KEY
-EVP,109,EXPECTING_A_DH_KEY
-EVP,110,EXPECTING_A_DSA_KEY
-EVP,111,ILLEGAL_OR_UNSUPPORTED_PADDING_MODE
-EVP,112,INVALID_CURVE
-EVP,113,INVALID_DIGEST_LENGTH
-EVP,114,INVALID_DIGEST_TYPE
-EVP,115,INVALID_KEYBITS
-EVP,116,INVALID_MGF1_MD
-EVP,142,INVALID_OPERATION
-EVP,118,INVALID_PADDING_MODE
-EVP,119,INVALID_PSS_PARAMETERS
-EVP,144,INVALID_PSS_SALTLEN
-EVP,121,INVALID_SALT_LENGTH
-EVP,122,INVALID_TRAILER
-EVP,123,KEYS_NOT_SET
-EVP,124,MISSING_PARAMETERS
-EVP,125,NO_DEFAULT_DIGEST
-EVP,126,NO_KEY_SET
-EVP,127,NO_MDC2_SUPPORT
-EVP,128,NO_NID_FOR_CURVE
-EVP,129,NO_OPERATION_SET
-EVP,130,NO_PARAMETERS_SET
-EVP,131,OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE
-EVP,132,OPERATON_NOT_INITIALIZED
-EVP,152,PARAMETER_ENCODING_ERROR
-EVP,133,UNKNOWN_DIGEST
-EVP,134,UNKNOWN_MASK_DIGEST
-EVP,150,UNKNOWN_MESSAGE_DIGEST_ALGORITHM
-EVP,145,UNKNOWN_PUBLIC_KEY_TYPE
-EVP,149,UNKNOWN_SIGNATURE_ALGORITHM
-EVP,138,UNSUPPORTED_ALGORITHM
-EVP,139,UNSUPPORTED_MASK_ALGORITHM
-EVP,140,UNSUPPORTED_MASK_PARAMETER
-EVP,153,UNSUPPORTED_PUBLIC_KEY_TYPE
-EVP,154,UNSUPPORTED_SIGNATURE_TYPE
-EVP,148,WRONG_PUBLIC_KEY_TYPE
+EVP,102,DECODE_ERROR
+EVP,103,DIFFERENT_KEY_TYPES
+EVP,104,DIFFERENT_PARAMETERS
+EVP,105,ENCODE_ERROR
+EVP,106,EXPECTING_AN_EC_KEY_KEY
+EVP,107,EXPECTING_AN_RSA_KEY
+EVP,108,EXPECTING_A_DSA_KEY
+EVP,109,ILLEGAL_OR_UNSUPPORTED_PADDING_MODE
+EVP,110,INVALID_DIGEST_LENGTH
+EVP,111,INVALID_DIGEST_TYPE
+EVP,112,INVALID_KEYBITS
+EVP,113,INVALID_MGF1_MD
+EVP,114,INVALID_OPERATION
+EVP,115,INVALID_PADDING_MODE
+EVP,116,INVALID_PSS_SALTLEN
+EVP,117,KEYS_NOT_SET
+EVP,118,MISSING_PARAMETERS
+EVP,119,NO_DEFAULT_DIGEST
+EVP,120,NO_KEY_SET
+EVP,121,NO_MDC2_SUPPORT
+EVP,122,NO_NID_FOR_CURVE
+EVP,123,NO_OPERATION_SET
+EVP,124,NO_PARAMETERS_SET
+EVP,125,OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE
+EVP,126,OPERATON_NOT_INITIALIZED
+EVP,127,UNKNOWN_PUBLIC_KEY_TYPE
+EVP,128,UNSUPPORTED_ALGORITHM
+EVP,129,UNSUPPORTED_PUBLIC_KEY_TYPE
diff --git a/crypto/err/rsa.errordata b/crypto/err/rsa.errordata
index c19f73c7..62d286cc 100644
--- a/crypto/err/rsa.errordata
+++ b/crypto/err/rsa.errordata
@@ -1,46 +1,46 @@
-RSA,143,BAD_ENCODING
-RSA,100,BAD_E_VALUE
-RSA,101,BAD_FIXED_HEADER_DECRYPT
-RSA,102,BAD_PAD_BYTE_COUNT
-RSA,103,BAD_RSA_PARAMETERS
-RSA,104,BAD_SIGNATURE
-RSA,145,BAD_VERSION
-RSA,105,BLOCK_TYPE_IS_NOT_01
-RSA,106,BN_NOT_INITIALIZED
-RSA,142,CANNOT_RECOVER_MULTI_PRIME_KEY
-RSA,107,CRT_PARAMS_ALREADY_GIVEN
-RSA,108,CRT_VALUES_INCORRECT
-RSA,109,DATA_LEN_NOT_EQUAL_TO_MOD_LEN
-RSA,110,DATA_TOO_LARGE
-RSA,111,DATA_TOO_LARGE_FOR_KEY_SIZE
-RSA,112,DATA_TOO_LARGE_FOR_MODULUS
-RSA,113,DATA_TOO_SMALL
-RSA,114,DATA_TOO_SMALL_FOR_KEY_SIZE
-RSA,115,DIGEST_TOO_BIG_FOR_RSA_KEY
-RSA,116,D_E_NOT_CONGRUENT_TO_1
-RSA,117,EMPTY_PUBLIC_KEY
-RSA,144,ENCODE_ERROR
-RSA,118,FIRST_OCTET_INVALID
-RSA,119,INCONSISTENT_SET_OF_CRT_VALUES
-RSA,120,INTERNAL_ERROR
-RSA,121,INVALID_MESSAGE_LENGTH
-RSA,122,KEY_SIZE_TOO_SMALL
-RSA,123,LAST_OCTET_INVALID
-RSA,124,MODULUS_TOO_LARGE
-RSA,141,MUST_HAVE_AT_LEAST_TWO_PRIMES
-RSA,125,NO_PUBLIC_EXPONENT
-RSA,126,NULL_BEFORE_BLOCK_MISSING
-RSA,127,N_NOT_EQUAL_P_Q
-RSA,128,OAEP_DECODING_ERROR
-RSA,129,ONLY_ONE_OF_P_Q_GIVEN
-RSA,130,OUTPUT_BUFFER_TOO_SMALL
-RSA,131,PADDING_CHECK_FAILED
-RSA,132,PKCS_DECODING_ERROR
-RSA,133,SLEN_CHECK_FAILED
-RSA,134,SLEN_RECOVERY_FAILED
-RSA,135,TOO_LONG
-RSA,136,TOO_MANY_ITERATIONS
-RSA,137,UNKNOWN_ALGORITHM_TYPE
-RSA,138,UNKNOWN_PADDING_TYPE
-RSA,139,VALUE_MISSING
-RSA,140,WRONG_SIGNATURE_LENGTH
+RSA,100,BAD_ENCODING
+RSA,101,BAD_E_VALUE
+RSA,102,BAD_FIXED_HEADER_DECRYPT
+RSA,103,BAD_PAD_BYTE_COUNT
+RSA,104,BAD_RSA_PARAMETERS
+RSA,105,BAD_SIGNATURE
+RSA,106,BAD_VERSION
+RSA,107,BLOCK_TYPE_IS_NOT_01
+RSA,108,BN_NOT_INITIALIZED
+RSA,109,CANNOT_RECOVER_MULTI_PRIME_KEY
+RSA,110,CRT_PARAMS_ALREADY_GIVEN
+RSA,111,CRT_VALUES_INCORRECT
+RSA,112,DATA_LEN_NOT_EQUAL_TO_MOD_LEN
+RSA,113,DATA_TOO_LARGE
+RSA,114,DATA_TOO_LARGE_FOR_KEY_SIZE
+RSA,115,DATA_TOO_LARGE_FOR_MODULUS
+RSA,116,DATA_TOO_SMALL
+RSA,117,DATA_TOO_SMALL_FOR_KEY_SIZE
+RSA,118,DIGEST_TOO_BIG_FOR_RSA_KEY
+RSA,119,D_E_NOT_CONGRUENT_TO_1
+RSA,120,EMPTY_PUBLIC_KEY
+RSA,121,ENCODE_ERROR
+RSA,122,FIRST_OCTET_INVALID
+RSA,123,INCONSISTENT_SET_OF_CRT_VALUES
+RSA,124,INTERNAL_ERROR
+RSA,125,INVALID_MESSAGE_LENGTH
+RSA,126,KEY_SIZE_TOO_SMALL
+RSA,127,LAST_OCTET_INVALID
+RSA,128,MODULUS_TOO_LARGE
+RSA,129,MUST_HAVE_AT_LEAST_TWO_PRIMES
+RSA,130,NO_PUBLIC_EXPONENT
+RSA,131,NULL_BEFORE_BLOCK_MISSING
+RSA,132,N_NOT_EQUAL_P_Q
+RSA,133,OAEP_DECODING_ERROR
+RSA,134,ONLY_ONE_OF_P_Q_GIVEN
+RSA,135,OUTPUT_BUFFER_TOO_SMALL
+RSA,136,PADDING_CHECK_FAILED
+RSA,137,PKCS_DECODING_ERROR
+RSA,138,SLEN_CHECK_FAILED
+RSA,139,SLEN_RECOVERY_FAILED
+RSA,140,TOO_LONG
+RSA,141,TOO_MANY_ITERATIONS
+RSA,142,UNKNOWN_ALGORITHM_TYPE
+RSA,143,UNKNOWN_PADDING_TYPE
+RSA,144,VALUE_MISSING
+RSA,145,WRONG_SIGNATURE_LENGTH
diff --git a/crypto/err/ssl.errordata b/crypto/err/ssl.errordata
index 3766bb98..dfe4ac81 100644
--- a/crypto/err/ssl.errordata
+++ b/crypto/err/ssl.errordata
@@ -108,6 +108,7 @@ SSL,206,SCSV_RECEIVED_WHEN_RENEGOTIATING
SSL,207,SERVERHELLO_TLSEXT
SSL,208,SESSION_ID_CONTEXT_UNINITIALIZED
SSL,209,SESSION_MAY_NOT_BE_CREATED
+SSL,250,SHUTDOWN_WHILE_IN_INIT
SSL,210,SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER
SSL,211,SRTP_COULD_NOT_ALLOCATE_PROFILES
SSL,212,SRTP_UNKNOWN_PROTECTION_PROFILE
diff --git a/crypto/err/x509.errordata b/crypto/err/x509.errordata
index f4828ce8..5687c30c 100644
--- a/crypto/err/x509.errordata
+++ b/crypto/err/x509.errordata
@@ -10,28 +10,27 @@ X509,108,IDP_MISMATCH
X509,109,INVALID_BIT_STRING_BITS_LEFT
X509,110,INVALID_DIRECTORY
X509,111,INVALID_FIELD_NAME
-X509,112,INVALID_TRUST
-X509,113,ISSUER_MISMATCH
-X509,114,KEY_TYPE_MISMATCH
-X509,115,KEY_VALUES_MISMATCH
-X509,116,LOADING_CERT_DIR
-X509,117,LOADING_DEFAULTS
-X509,118,METHOD_NOT_SUPPORTED
+X509,112,INVALID_PSS_PARAMETERS
+X509,113,INVALID_TRUST
+X509,114,ISSUER_MISMATCH
+X509,115,KEY_TYPE_MISMATCH
+X509,116,KEY_VALUES_MISMATCH
+X509,117,LOADING_CERT_DIR
+X509,118,LOADING_DEFAULTS
+X509,135,NAME_TOO_LONG
X509,119,NEWER_CRL_NOT_NEWER
X509,120,NOT_PKCS7_SIGNED_DATA
X509,121,NO_CERTIFICATES_INCLUDED
X509,122,NO_CERT_SET_FOR_US_TO_VERIFY
-X509,136,NO_CRLS_INCLUDED
-X509,123,NO_CRL_NUMBER
-X509,124,PUBLIC_KEY_DECODE_ERROR
-X509,125,PUBLIC_KEY_ENCODE_ERROR
-X509,126,SHOULD_RETRY
-X509,127,UNABLE_TO_FIND_PARAMETERS_IN_CHAIN
-X509,128,UNABLE_TO_GET_CERTS_PUBLIC_KEY
-X509,129,UNKNOWN_KEY_TYPE
-X509,130,UNKNOWN_NID
-X509,131,UNKNOWN_PURPOSE_ID
-X509,132,UNKNOWN_TRUST_ID
-X509,133,UNSUPPORTED_ALGORITHM
-X509,134,WRONG_LOOKUP_TYPE
-X509,135,WRONG_TYPE
+X509,123,NO_CRLS_INCLUDED
+X509,124,NO_CRL_NUMBER
+X509,125,PUBLIC_KEY_DECODE_ERROR
+X509,126,PUBLIC_KEY_ENCODE_ERROR
+X509,127,SHOULD_RETRY
+X509,128,UNKNOWN_KEY_TYPE
+X509,129,UNKNOWN_NID
+X509,130,UNKNOWN_PURPOSE_ID
+X509,131,UNKNOWN_TRUST_ID
+X509,132,UNSUPPORTED_ALGORITHM
+X509,133,WRONG_LOOKUP_TYPE
+X509,134,WRONG_TYPE
diff --git a/crypto/evp/CMakeLists.txt b/crypto/evp/CMakeLists.txt
index d47a7e2d..1174be63 100644
--- a/crypto/evp/CMakeLists.txt
+++ b/crypto/evp/CMakeLists.txt
@@ -5,7 +5,6 @@ add_library(
OBJECT
- algorithm.c
digestsign.c
evp.c
evp_asn1.c
@@ -16,6 +15,7 @@ add_library(
p_rsa.c
p_rsa_asn1.c
pbkdf.c
+ print.c
sign.c
)
diff --git a/crypto/evp/evp.c b/crypto/evp/evp.c
index fa842120..ee207f9b 100644
--- a/crypto/evp/evp.c
+++ b/crypto/evp/evp.c
@@ -59,12 +59,11 @@
#include <assert.h>
#include <string.h>
-#include <openssl/bio.h>
#include <openssl/dsa.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/rsa.h>
#include <openssl/thread.h>
@@ -195,8 +194,10 @@ int EVP_PKEY_id(const EVP_PKEY *pkey) {
return pkey->type;
}
-/* TODO(fork): remove the first argument. */
-const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, int nid) {
+/* evp_pkey_asn1_find returns the ASN.1 method table for the given |nid|, which
+ * should be one of the |EVP_PKEY_*| values. It returns NULL if |nid| is
+ * unknown. */
+static const EVP_PKEY_ASN1_METHOD *evp_pkey_asn1_find(int nid) {
switch (nid) {
case EVP_PKEY_RSA:
return &rsa_asn1_meth;
@@ -210,7 +211,7 @@ const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, int nid) {
}
int EVP_PKEY_type(int nid) {
- const EVP_PKEY_ASN1_METHOD *meth = EVP_PKEY_asn1_find(NULL, nid);
+ const EVP_PKEY_ASN1_METHOD *meth = evp_pkey_asn1_find(nid);
if (meth == NULL) {
return NID_undef;
}
@@ -309,21 +310,6 @@ int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) {
return key != NULL;
}
-const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pengine,
- const char *name,
- size_t len) {
- if (len == 3 && memcmp(name, "RSA", 3) == 0) {
- return &rsa_asn1_meth;
- }
- if (len == 2 && memcmp(name, "EC", 2) == 0) {
- return &ec_asn1_meth;
- }
- if (len == 3 && memcmp(name, "DSA", 3) == 0) {
- return &dsa_asn1_meth;
- }
- return NULL;
-}
-
int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) {
const EVP_PKEY_ASN1_METHOD *ameth;
@@ -331,10 +317,10 @@ int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) {
free_it(pkey);
}
- ameth = EVP_PKEY_asn1_find(NULL, type);
+ ameth = evp_pkey_asn1_find(type);
if (ameth == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
- ERR_add_error_dataf("algorithm %d (%s)", type, OBJ_nid2sn(type));
+ ERR_add_error_dataf("algorithm %d", type);
return 0;
}
@@ -358,41 +344,6 @@ int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
return -2;
}
-static int print_unsupported(BIO *out, const EVP_PKEY *pkey, int indent,
- const char *kstr) {
- BIO_indent(out, indent, 128);
- BIO_printf(out, "%s algorithm \"%s\" unsupported\n", kstr,
- OBJ_nid2ln(pkey->type));
- return 1;
-}
-
-int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *pctx) {
- if (pkey->ameth && pkey->ameth->pub_print) {
- return pkey->ameth->pub_print(out, pkey, indent, pctx);
- }
-
- return print_unsupported(out, pkey, indent, "Public Key");
-}
-
-int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *pctx) {
- if (pkey->ameth && pkey->ameth->priv_print) {
- return pkey->ameth->priv_print(out, pkey, indent, pctx);
- }
-
- return print_unsupported(out, pkey, indent, "Private Key");
-}
-
-int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *pctx) {
- if (pkey->ameth && pkey->ameth->param_print) {
- return pkey->ameth->param_print(out, pkey, indent, pctx);
- }
-
- return print_unsupported(out, pkey, indent, "Parameters");
-}
-
int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0,
(void *)md);
@@ -405,6 +356,8 @@ int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
void OpenSSL_add_all_algorithms(void) {}
+void OPENSSL_add_all_algorithms_conf(void) {}
+
void OpenSSL_add_all_ciphers(void) {}
void OpenSSL_add_all_digests(void) {}
diff --git a/crypto/evp/evp_asn1.c b/crypto/evp/evp_asn1.c
index ed7ae8b7..3681d4fc 100644
--- a/crypto/evp/evp_asn1.c
+++ b/crypto/evp/evp_asn1.c
@@ -56,22 +56,50 @@
#include <openssl/evp.h>
-#include <openssl/asn1.h>
+#include <string.h>
+
#include <openssl/bytestring.h>
+#include <openssl/dsa.h>
+#include <openssl/ec_key.h>
#include <openssl/err.h>
-#include <openssl/obj.h>
-#include <openssl/x509.h>
+#include <openssl/rsa.h>
#include "internal.h"
+static const EVP_PKEY_ASN1_METHOD *const kASN1Methods[] = {
+ &rsa_asn1_meth,
+ &ec_asn1_meth,
+ &dsa_asn1_meth,
+};
+
+static int parse_key_type(CBS *cbs, int *out_type) {
+ CBS oid;
+ if (!CBS_get_asn1(cbs, &oid, CBS_ASN1_OBJECT)) {
+ return 0;
+ }
+
+ unsigned i;
+ for (i = 0; i < sizeof(kASN1Methods)/sizeof(kASN1Methods[0]); i++) {
+ const EVP_PKEY_ASN1_METHOD *method = kASN1Methods[i];
+ if (CBS_len(&oid) == method->oid_len &&
+ memcmp(CBS_data(&oid), method->oid, method->oid_len) == 0) {
+ *out_type = method->pkey_id;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
EVP_PKEY *EVP_parse_public_key(CBS *cbs) {
/* Parse the SubjectPublicKeyInfo. */
- CBS spki, algorithm, oid, key;
+ CBS spki, algorithm, key;
+ int type;
uint8_t padding;
if (!CBS_get_asn1(cbs, &spki, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
- !CBS_get_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
+ !parse_key_type(&algorithm, &type) ||
!CBS_get_asn1(&spki, &key, CBS_ASN1_BITSTRING) ||
CBS_len(&spki) != 0 ||
/* Every key type defined encodes the key as a byte string with the same
@@ -85,7 +113,7 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) {
/* Set up an |EVP_PKEY| of the appropriate type. */
EVP_PKEY *ret = EVP_PKEY_new();
if (ret == NULL ||
- !EVP_PKEY_set_type(ret, OBJ_cbs2nid(&oid))) {
+ !EVP_PKEY_set_type(ret, type)) {
goto err;
}
@@ -106,7 +134,7 @@ err:
}
int EVP_marshal_public_key(CBB *cbb, const EVP_PKEY *key) {
- if (key->ameth->pub_encode == NULL) {
+ if (key->ameth == NULL || key->ameth->pub_encode == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
@@ -116,13 +144,14 @@ int EVP_marshal_public_key(CBB *cbb, const EVP_PKEY *key) {
EVP_PKEY *EVP_parse_private_key(CBS *cbs) {
/* Parse the PrivateKeyInfo. */
- CBS pkcs8, algorithm, oid, key;
+ CBS pkcs8, algorithm, key;
uint64_t version;
+ int type;
if (!CBS_get_asn1(cbs, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1_uint64(&pkcs8, &version) ||
version != 0 ||
!CBS_get_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
- !CBS_get_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
+ !parse_key_type(&algorithm, &type) ||
!CBS_get_asn1(&pkcs8, &key, CBS_ASN1_OCTETSTRING)) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
return NULL;
@@ -133,7 +162,7 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) {
/* Set up an |EVP_PKEY| of the appropriate type. */
EVP_PKEY *ret = EVP_PKEY_new();
if (ret == NULL ||
- !EVP_PKEY_set_type(ret, OBJ_cbs2nid(&oid))) {
+ !EVP_PKEY_set_type(ret, type)) {
goto err;
}
@@ -154,7 +183,7 @@ err:
}
int EVP_marshal_private_key(CBB *cbb, const EVP_PKEY *key) {
- if (key->ameth->priv_encode == NULL) {
+ if (key->ameth == NULL || key->ameth->priv_encode == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
@@ -162,107 +191,134 @@ int EVP_marshal_private_key(CBB *cbb, const EVP_PKEY *key) {
return key->ameth->priv_encode(cbb, key);
}
-EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp,
- long len) {
- EVP_PKEY *ret;
-
- if (out == NULL || *out == NULL) {
- ret = EVP_PKEY_new();
- if (ret == NULL) {
- OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB);
- return NULL;
- }
- } else {
- ret = *out;
- }
-
- if (!EVP_PKEY_set_type(ret, type)) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE);
- goto err;
+static EVP_PKEY *old_priv_decode(CBS *cbs, int type) {
+ EVP_PKEY *ret = EVP_PKEY_new();
+ if (ret == NULL) {
+ return NULL;
}
- const uint8_t *in = *inp;
- /* If trying to remove |old_priv_decode|, note that some code depends on this
- * function writing into |*out| and the |priv_decode| path doesn't support
- * that. */
- if (!ret->ameth->old_priv_decode ||
- !ret->ameth->old_priv_decode(ret, &in, len)) {
- if (ret->ameth->priv_decode) {
- /* Reset |in| in case |old_priv_decode| advanced it on error. */
- in = *inp;
- PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &in, len);
- if (!p8) {
+ switch (type) {
+ case EVP_PKEY_EC: {
+ EC_KEY *ec_key = EC_KEY_parse_private_key(cbs, NULL);
+ if (ec_key == NULL || !EVP_PKEY_assign_EC_KEY(ret, ec_key)) {
+ EC_KEY_free(ec_key);
goto err;
}
- EVP_PKEY_free(ret);
- ret = EVP_PKCS82PKEY(p8);
- PKCS8_PRIV_KEY_INFO_free(p8);
- if (ret == NULL) {
+ return ret;
+ }
+ case EVP_PKEY_DSA: {
+ DSA *dsa = DSA_parse_private_key(cbs);
+ if (dsa == NULL || !EVP_PKEY_assign_DSA(ret, dsa)) {
+ DSA_free(dsa);
goto err;
}
- } else {
- OPENSSL_PUT_ERROR(EVP, ERR_R_ASN1_LIB);
+ return ret;
+ }
+ case EVP_PKEY_RSA: {
+ RSA *rsa = RSA_parse_private_key(cbs);
+ if (rsa == NULL || !EVP_PKEY_assign_RSA(ret, rsa)) {
+ RSA_free(rsa);
+ goto err;
+ }
+ return ret;
+ }
+ default:
+ OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE);
goto err;
+ }
+
+err:
+ EVP_PKEY_free(ret);
+ return NULL;
+}
+
+EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp,
+ long len) {
+ if (len < 0) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return NULL;
+ }
+
+ /* Parse with the legacy format. */
+ CBS cbs;
+ CBS_init(&cbs, *inp, (size_t)len);
+ EVP_PKEY *ret = old_priv_decode(&cbs, type);
+ if (ret == NULL) {
+ /* Try again with PKCS#8. */
+ ERR_clear_error();
+ CBS_init(&cbs, *inp, (size_t)len);
+ ret = EVP_parse_private_key(&cbs);
+ if (ret == NULL) {
+ return NULL;
+ }
+ if (ret->type != type) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES);
+ EVP_PKEY_free(ret);
+ return NULL;
}
}
if (out != NULL) {
+ EVP_PKEY_free(*out);
*out = ret;
}
- *inp = in;
+ *inp = CBS_data(&cbs);
return ret;
+}
-err:
- if (out == NULL || *out != ret) {
- EVP_PKEY_free(ret);
+/* num_elements parses one SEQUENCE from |in| and returns the number of elements
+ * in it. On parse error, it returns zero. */
+static size_t num_elements(const uint8_t *in, size_t in_len) {
+ CBS cbs, sequence;
+ CBS_init(&cbs, in, (size_t)in_len);
+
+ if (!CBS_get_asn1(&cbs, &sequence, CBS_ASN1_SEQUENCE)) {
+ return 0;
}
- return NULL;
+
+ size_t count = 0;
+ while (CBS_len(&sequence) > 0) {
+ if (!CBS_get_any_asn1_element(&sequence, NULL, NULL, NULL)) {
+ return 0;
+ }
+
+ count++;
+ }
+
+ return count;
}
EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len) {
- STACK_OF(ASN1_TYPE) *inkey;
- const uint8_t *p;
- int keytype;
- p = *inp;
-
- /* Dirty trick: read in the ASN1 data into out STACK_OF(ASN1_TYPE):
- * by analyzing it we can determine the passed structure: this
- * assumes the input is surrounded by an ASN1 SEQUENCE. */
- inkey = d2i_ASN1_SEQUENCE_ANY(NULL, &p, len);
- /* Since we only need to discern "traditional format" RSA and DSA
- * keys we can just count the elements. */
- if (sk_ASN1_TYPE_num(inkey) == 6) {
- keytype = EVP_PKEY_DSA;
- } else if (sk_ASN1_TYPE_num(inkey) == 4) {
- keytype = EVP_PKEY_EC;
- } else if (sk_ASN1_TYPE_num(inkey) == 3) {
- /* This seems to be PKCS8, not traditional format */
- p = *inp;
- PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, len);
- EVP_PKEY *ret;
-
- sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
- if (!p8) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
- return NULL;
- }
- ret = EVP_PKCS82PKEY(p8);
- PKCS8_PRIV_KEY_INFO_free(p8);
- if (ret == NULL) {
- return NULL;
- }
+ if (len < 0) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+ return NULL;
+ }
- *inp = p;
- if (out) {
+ /* Parse the input as a PKCS#8 PrivateKeyInfo. */
+ CBS cbs;
+ CBS_init(&cbs, *inp, (size_t)len);
+ EVP_PKEY *ret = EVP_parse_private_key(&cbs);
+ if (ret != NULL) {
+ if (out != NULL) {
+ EVP_PKEY_free(*out);
*out = ret;
}
+ *inp = CBS_data(&cbs);
return ret;
- } else {
- keytype = EVP_PKEY_RSA;
}
+ ERR_clear_error();
- sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
- return d2i_PrivateKey(keytype, out, inp, len);
+ /* Count the elements to determine the legacy key format. */
+ switch (num_elements(*inp, (size_t)len)) {
+ case 4:
+ return d2i_PrivateKey(EVP_PKEY_EC, out, inp, len);
+
+ case 6:
+ return d2i_PrivateKey(EVP_PKEY_DSA, out, inp, len);
+
+ default:
+ return d2i_PrivateKey(EVP_PKEY_RSA, out, inp, len);
+ }
}
int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp) {
diff --git a/crypto/evp/evp_ctx.c b/crypto/evp/evp_ctx.c
index b06eefd6..f510f6c7 100644
--- a/crypto/evp/evp_ctx.c
+++ b/crypto/evp/evp_ctx.c
@@ -56,12 +56,10 @@
#include <openssl/evp.h>
-#include <stdio.h>
#include <string.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
#include "internal.h"
@@ -98,8 +96,7 @@ static EVP_PKEY_CTX *evp_pkey_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id) {
if (pmeth == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
- const char *name = OBJ_nid2sn(id);
- ERR_add_error_dataf("algorithm %d (%s)", id, name);
+ ERR_add_error_dataf("algorithm %d", id);
return NULL;
}
diff --git a/crypto/evp/evp_extra_test.cc b/crypto/evp/evp_extra_test.cc
index 19e4cf6a..9bc36ad8 100644
--- a/crypto/evp/evp_extra_test.cc
+++ b/crypto/evp/evp_extra_test.cc
@@ -26,7 +26,6 @@
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
-#include <openssl/x509.h>
#include "../test/scoped_types.h"
@@ -178,142 +177,6 @@ static const uint8_t kSignature[] = {
0x55, 0xa7, 0xab, 0x45, 0x02, 0x97, 0x60, 0x42,
};
-// kExamplePSSCert is an example self-signed certificate, signed with
-// kExampleRSAKeyDER using RSA-PSS with default hash functions.
-static const uint8_t kExamplePSSCert[] = {
- 0x30, 0x82, 0x02, 0x62, 0x30, 0x82, 0x01, 0xc6, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x8d, 0xea, 0x53, 0x24, 0xfa, 0x48, 0x87, 0xf3,
- 0x30, 0x12, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x0a, 0x30, 0x05, 0xa2, 0x03, 0x02, 0x01, 0x6a, 0x30, 0x45, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31,
- 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f,
- 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f,
- 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
- 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20,
- 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31,
- 0x34, 0x31, 0x30, 0x30, 0x39, 0x31, 0x39, 0x30, 0x39, 0x35, 0x35, 0x5a,
- 0x17, 0x0d, 0x31, 0x35, 0x31, 0x30, 0x30, 0x39, 0x31, 0x39, 0x30, 0x39,
- 0x35, 0x35, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
- 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
- 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
- 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c,
- 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00,
- 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xf8, 0xb8, 0x6c, 0x83, 0xb4,
- 0xbc, 0xd9, 0xa8, 0x57, 0xc0, 0xa5, 0xb4, 0x59, 0x76, 0x8c, 0x54, 0x1d,
- 0x79, 0xeb, 0x22, 0x52, 0x04, 0x7e, 0xd3, 0x37, 0xeb, 0x41, 0xfd, 0x83,
- 0xf9, 0xf0, 0xa6, 0x85, 0x15, 0x34, 0x75, 0x71, 0x5a, 0x84, 0xa8, 0x3c,
- 0xd2, 0xef, 0x5a, 0x4e, 0xd3, 0xde, 0x97, 0x8a, 0xdd, 0xff, 0xbb, 0xcf,
- 0x0a, 0xaa, 0x86, 0x92, 0xbe, 0xb8, 0x50, 0xe4, 0xcd, 0x6f, 0x80, 0x33,
- 0x30, 0x76, 0x13, 0x8f, 0xca, 0x7b, 0xdc, 0xec, 0x5a, 0xca, 0x63, 0xc7,
- 0x03, 0x25, 0xef, 0xa8, 0x8a, 0x83, 0x58, 0x76, 0x20, 0xfa, 0x16, 0x77,
- 0xd7, 0x79, 0x92, 0x63, 0x01, 0x48, 0x1a, 0xd8, 0x7b, 0x67, 0xf1, 0x52,
- 0x55, 0x49, 0x4e, 0xd6, 0x6e, 0x4a, 0x5c, 0xd7, 0x7a, 0x37, 0x36, 0x0c,
- 0xde, 0xdd, 0x8f, 0x44, 0xe8, 0xc2, 0xa7, 0x2c, 0x2b, 0xb5, 0xaf, 0x64,
- 0x4b, 0x61, 0x07, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e,
- 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd0,
- 0x41, 0xfb, 0x89, 0x41, 0x1e, 0xa7, 0xad, 0x5a, 0xec, 0x34, 0x5d, 0x49,
- 0x11, 0xf9, 0x55, 0x81, 0x78, 0x1f, 0x13, 0x30, 0x1f, 0x06, 0x03, 0x55,
- 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xd0, 0x41, 0xfb, 0x89,
- 0x41, 0x1e, 0xa7, 0xad, 0x5a, 0xec, 0x34, 0x5d, 0x49, 0x11, 0xf9, 0x55,
- 0x81, 0x78, 0x1f, 0x13, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04,
- 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x12, 0x06, 0x09, 0x2a, 0x86,
- 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x30, 0x05, 0xa2, 0x03, 0x02,
- 0x01, 0x6a, 0x03, 0x81, 0x81, 0x00, 0x49, 0x4c, 0xb6, 0x45, 0x97, 0x20,
- 0x35, 0xb3, 0x50, 0x64, 0x0d, 0x3f, 0xec, 0x5f, 0x95, 0xd5, 0x84, 0xcb,
- 0x11, 0x7c, 0x03, 0xd7, 0xa6, 0xe6, 0xfa, 0x24, 0x95, 0x9f, 0x31, 0xb0,
- 0xb5, 0xec, 0x66, 0x41, 0x51, 0x18, 0x21, 0x91, 0xbb, 0xe0, 0xaf, 0xf0,
- 0xc5, 0xb7, 0x59, 0x41, 0xd4, 0xdb, 0xa4, 0xd2, 0x64, 0xa7, 0x54, 0x0f,
- 0x8c, 0xf7, 0xe1, 0xd3, 0x3b, 0x1a, 0xb7, 0x0e, 0x9d, 0x9a, 0xde, 0x50,
- 0xa1, 0x9f, 0x0a, 0xf0, 0xda, 0x34, 0x0e, 0x34, 0x7d, 0x76, 0x07, 0xfe,
- 0x5a, 0xfb, 0xf9, 0x58, 0x9b, 0xc9, 0x50, 0x84, 0x01, 0xa0, 0x05, 0x4d,
- 0x67, 0x42, 0x0b, 0xf8, 0xe4, 0x05, 0xcf, 0xaf, 0x8b, 0x71, 0x31, 0xf1,
- 0x0f, 0x6e, 0xc9, 0x24, 0x27, 0x9b, 0xac, 0x04, 0xd7, 0x64, 0x0d, 0x30,
- 0x4e, 0x11, 0x93, 0x40, 0x39, 0xbb, 0x72, 0xb2, 0xfe, 0x6b, 0xe4, 0xae,
- 0x8c, 0x16,
-};
-
-// kBadPSSCert is an example RSA-PSS certificate with bad parameters.
-static const uint8_t kBadPSSCert[] = {
- 0x30, 0x82, 0x03, 0x76, 0x30, 0x82, 0x02, 0x3a, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0xd7, 0x30, 0x64, 0xbc, 0x9f, 0x12, 0xfe, 0xc3,
- 0x30, 0x3e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
- 0x0a, 0x30, 0x31, 0xa0, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48,
- 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0xa1, 0x1a, 0x30, 0x18, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0b, 0x06,
- 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0xa2, 0x04,
- 0x02, 0x02, 0x00, 0xde, 0x30, 0x27, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03,
- 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6e,
- 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x50, 0x53, 0x53, 0x20, 0x63, 0x65,
- 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x1e, 0x17,
- 0x0d, 0x31, 0x35, 0x31, 0x31, 0x30, 0x34, 0x31, 0x36, 0x30, 0x32, 0x33,
- 0x35, 0x5a, 0x17, 0x0d, 0x31, 0x35, 0x31, 0x32, 0x30, 0x34, 0x31, 0x36,
- 0x30, 0x32, 0x33, 0x35, 0x5a, 0x30, 0x27, 0x31, 0x25, 0x30, 0x23, 0x06,
- 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x54, 0x65, 0x73, 0x74, 0x20, 0x49,
- 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x50, 0x53, 0x53, 0x20, 0x63,
- 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x82,
- 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
- 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc4, 0xda, 0x33, 0xb5, 0x87,
- 0xa9, 0x50, 0x80, 0x18, 0x02, 0x00, 0xfb, 0x32, 0xf5, 0x29, 0x6b, 0xef,
- 0x01, 0x24, 0xeb, 0x86, 0x5a, 0xbe, 0xd5, 0xe3, 0xdd, 0x3b, 0xbc, 0x2c,
- 0xad, 0x65, 0xf6, 0x2a, 0x26, 0x28, 0x4d, 0x8a, 0xc9, 0x61, 0x39, 0xf1,
- 0x84, 0xb9, 0xe7, 0xd3, 0x0a, 0xc7, 0xa8, 0x0a, 0x6d, 0xef, 0xd9, 0xcb,
- 0x20, 0x11, 0xbb, 0x71, 0xf4, 0xa1, 0xc9, 0x9a, 0x85, 0x1c, 0xe6, 0x3f,
- 0x23, 0x39, 0x58, 0x3c, 0xc5, 0x6d, 0xfa, 0x03, 0xe8, 0xdb, 0xdd, 0xe0,
- 0xc3, 0xde, 0x85, 0x76, 0xce, 0x49, 0x06, 0xc8, 0xe1, 0x8e, 0x4c, 0x86,
- 0x9c, 0xec, 0xab, 0xf4, 0xe5, 0x27, 0xb4, 0x5a, 0xaf, 0xc4, 0x36, 0xd3,
- 0x20, 0x81, 0x54, 0xee, 0x8f, 0x48, 0x77, 0x10, 0xf8, 0x79, 0xd6, 0xaa,
- 0x8d, 0x1b, 0xfe, 0x7d, 0xe8, 0x15, 0x13, 0xe0, 0x7b, 0xf6, 0x90, 0xe4,
- 0xe2, 0xcd, 0x2e, 0x8e, 0xc9, 0x3a, 0x75, 0x42, 0xed, 0x0a, 0x0f, 0x51,
- 0xb2, 0xdd, 0x2e, 0x70, 0x61, 0x68, 0xd7, 0xd9, 0xab, 0xf9, 0xbe, 0xe4,
- 0x75, 0xb7, 0xe7, 0xf2, 0x96, 0x7b, 0xd9, 0x93, 0x43, 0x24, 0xfb, 0x9e,
- 0x55, 0xda, 0xd4, 0x01, 0x6c, 0x3d, 0xa2, 0x59, 0x7a, 0xd5, 0x47, 0x18,
- 0x7e, 0x4e, 0xf9, 0x5d, 0xda, 0xcb, 0x93, 0xa2, 0x65, 0x2f, 0x8d, 0x46,
- 0xad, 0x81, 0xdc, 0xf0, 0xa9, 0x5f, 0x5d, 0xfe, 0x37, 0x80, 0x64, 0x2a,
- 0x41, 0xfa, 0xe9, 0x1e, 0x48, 0x38, 0x22, 0x1d, 0x9c, 0x23, 0xa5, 0xad,
- 0xda, 0x78, 0x45, 0x18, 0x0c, 0xeb, 0x95, 0xca, 0x2b, 0xcc, 0xb9, 0x62,
- 0x40, 0x85, 0x09, 0x44, 0x88, 0x4c, 0xf2, 0x1e, 0x08, 0x80, 0x37, 0xe9,
- 0x06, 0x96, 0x8f, 0x75, 0x54, 0x0b, 0xa9, 0x2d, 0xa9, 0x15, 0xb5, 0xda,
- 0xe5, 0xe4, 0x23, 0xaa, 0x2c, 0x89, 0xc1, 0xa9, 0x36, 0xbc, 0x9f, 0x02,
- 0x03, 0x01, 0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03,
- 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x2b, 0x75, 0xf3, 0x43, 0x78,
- 0xa0, 0x65, 0x2d, 0xe4, 0xb6, 0xf3, 0x07, 0x04, 0x38, 0x21, 0xaf, 0xb6,
- 0xe1, 0x5f, 0x7b, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
- 0x30, 0x16, 0x80, 0x14, 0x2b, 0x75, 0xf3, 0x43, 0x78, 0xa0, 0x65, 0x2d,
- 0xe4, 0xb6, 0xf3, 0x07, 0x04, 0x38, 0x21, 0xaf, 0xb6, 0xe1, 0x5f, 0x7b,
- 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01,
- 0x01, 0xff, 0x30, 0x31, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x0a, 0x30, 0x24, 0xa0, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
- 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0xa1, 0x0d, 0x30, 0x0b,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0xa2,
- 0x04, 0x02, 0x02, 0x00, 0xde, 0x03, 0x82, 0x01, 0x01, 0x00, 0x08, 0xc1,
- 0xb6, 0x6f, 0x74, 0x94, 0x6c, 0x60, 0x75, 0xd8, 0xdc, 0xe1, 0x7b, 0xbf,
- 0x9d, 0xb5, 0xd7, 0x14, 0x75, 0x6c, 0xdb, 0x35, 0x5c, 0x1e, 0xff, 0xe6,
- 0xa8, 0xe6, 0x68, 0x42, 0x41, 0x81, 0xf6, 0xbf, 0xc1, 0x56, 0x02, 0xdb,
- 0xc6, 0x11, 0xeb, 0x15, 0x9d, 0xa9, 0x1c, 0x61, 0x25, 0x6d, 0x46, 0x0f,
- 0x7e, 0x27, 0xdd, 0x4b, 0xdc, 0xed, 0x07, 0xbd, 0xde, 0xd5, 0xde, 0x09,
- 0xf8, 0xfd, 0xbd, 0xa3, 0x4c, 0x81, 0xa9, 0xf7, 0x78, 0xff, 0x01, 0x80,
- 0x73, 0xf2, 0x40, 0xf2, 0xa8, 0x27, 0xe8, 0x00, 0x04, 0x3b, 0xf5, 0xe7,
- 0xa6, 0x58, 0x45, 0x79, 0x34, 0x49, 0x42, 0xd2, 0xd9, 0x56, 0x5e, 0xf9,
- 0x0a, 0x41, 0xd7, 0x81, 0x41, 0x94, 0x77, 0x78, 0x7e, 0x00, 0x3b, 0xca,
- 0xb5, 0xc0, 0x6e, 0x5b, 0xd7, 0x52, 0x52, 0x77, 0x1a, 0x52, 0xb8, 0x0d,
- 0x29, 0x1f, 0x2e, 0xfe, 0x1f, 0xf6, 0xb0, 0xc1, 0xb7, 0xf1, 0x15, 0x98,
- 0x0f, 0x30, 0x5d, 0x74, 0x2f, 0xfa, 0xe9, 0x84, 0xda, 0xde, 0xbe, 0xca,
- 0x91, 0x55, 0x1f, 0x5b, 0xbc, 0xaa, 0x45, 0x07, 0xc4, 0x2e, 0x21, 0x8a,
- 0x75, 0xc9, 0xbe, 0x6e, 0x39, 0x53, 0x10, 0xcb, 0x2f, 0x4b, 0xe1, 0x21,
- 0x1e, 0xea, 0x7d, 0x0b, 0x36, 0xe9, 0xa0, 0x2c, 0x76, 0x17, 0x1f, 0x69,
- 0x34, 0xfb, 0x45, 0x63, 0x7c, 0x84, 0x39, 0xb4, 0x21, 0x98, 0xbd, 0x49,
- 0xca, 0x80, 0x91, 0x5a, 0xa0, 0x44, 0xef, 0x91, 0xb3, 0x14, 0xf6, 0xd1,
- 0x6a, 0x2b, 0xb1, 0xe5, 0x4a, 0x44, 0x92, 0x7b, 0x3e, 0x8b, 0x7b, 0x6b,
- 0x90, 0x6b, 0x2c, 0x67, 0x3b, 0x0e, 0xb9, 0x5a, 0x87, 0x35, 0x33, 0x59,
- 0x94, 0x2f, 0x7e, 0xf6, 0x13, 0xc7, 0x22, 0x87, 0x3d, 0x50, 0xc9, 0x80,
- 0x40, 0xda, 0x35, 0xbc, 0x62, 0x16, 0xdc, 0xd5, 0x95, 0xa1, 0xe1, 0x9b,
- 0x68, 0x9f,
-};
-
// kExampleRSAKeyPKCS8 is kExampleRSAKeyDER encoded in a PKCS #8
// PrivateKeyInfo.
static const uint8_t kExampleRSAKeyPKCS8[] = {
@@ -558,162 +421,6 @@ static bool TestEVP_DigestVerifyInit(void) {
return true;
}
-// TestAlgorithmRoundtrip signs a message using an already-initialized
-// |md_ctx|, sampling the AlgorithmIdentifier. It then uses |pkey| and the
-// AlgorithmIdentifier to verify the signature.
-static bool TestAlgorithmRoundtrip(EVP_MD_CTX *md_ctx, EVP_PKEY *pkey) {
- if (!EVP_DigestSignUpdate(md_ctx, kMsg, sizeof(kMsg))) {
- return false;
- }
-
- // Save the algorithm.
- ScopedX509_ALGOR algor(X509_ALGOR_new());
- if (!algor || !EVP_DigestSignAlgorithm(md_ctx, algor.get())) {
- return false;
- }
-
- // Determine the size of the signature.
- size_t sig_len = 0;
- if (!EVP_DigestSignFinal(md_ctx, NULL, &sig_len)) {
- return false;
- }
- // Sanity check for testing.
- if (sig_len != (size_t)EVP_PKEY_size(pkey)) {
- fprintf(stderr, "sig_len mismatch\n");
- return false;
- }
-
- std::vector<uint8_t> sig;
- sig.resize(sig_len);
- if (!EVP_DigestSignFinal(md_ctx, sig.data(), &sig_len)) {
- return false;
- }
- sig.resize(sig_len);
-
- // Ensure that the signature round-trips.
- ScopedEVP_MD_CTX md_ctx_verify;
- if (!EVP_DigestVerifyInitFromAlgorithm(md_ctx_verify.get(), algor.get(),
- pkey) ||
- !EVP_DigestVerifyUpdate(md_ctx_verify.get(), kMsg, sizeof(kMsg)) ||
- !EVP_DigestVerifyFinal(md_ctx_verify.get(), sig.data(), sig_len)) {
- return false;
- }
-
- return true;
-}
-
-static bool TestEVP_DigestSignAlgorithm(void) {
- ScopedEVP_PKEY pkey = LoadExampleRSAKey();
-
- // Test a simple AlgorithmIdentifier.
- ScopedEVP_MD_CTX md_ctx;
- if (!pkey ||
- !EVP_DigestSignInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()) ||
- !TestAlgorithmRoundtrip(md_ctx.get(), pkey.get())) {
- fprintf(stderr, "RSA with SHA-256 failed\n");
- return false;
- }
-
- // Test RSA-PSS with custom parameters.
- md_ctx.Reset();
- EVP_PKEY_CTX *pkey_ctx;
- if (!EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, EVP_sha256(), NULL,
- pkey.get()) ||
- !EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) ||
- !EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha512()) ||
- !TestAlgorithmRoundtrip(md_ctx.get(), pkey.get())) {
- fprintf(stderr, "RSA-PSS failed\n");
- return false;
- }
-
- return true;
-}
-
-static bool ParseCertificate(CBS *out_tbs_cert,
- ScopedEVP_PKEY *out_pubkey,
- ScopedX509_ALGOR *out_algor,
- CBS *out_signature,
- const CBS *in_) {
- CBS in = *in_;
- CBS cert_body, tbs_cert, algorithm, signature;
- if (!CBS_get_asn1(&in, &cert_body, CBS_ASN1_SEQUENCE) ||
- CBS_len(&in) != 0 ||
- !CBS_get_any_asn1_element(&cert_body, &tbs_cert, NULL, NULL) ||
- !CBS_get_asn1_element(&cert_body, &algorithm, CBS_ASN1_SEQUENCE) ||
- !CBS_get_asn1(&cert_body, &signature, CBS_ASN1_BITSTRING) ||
- CBS_len(&cert_body) != 0) {
- return false;
- }
-
- CBS tbs_cert_copy = tbs_cert;
- CBS tbs_cert_body, discard, spki;
- if (!CBS_get_asn1(&tbs_cert_copy, &tbs_cert_body, CBS_ASN1_SEQUENCE) ||
- CBS_len(&tbs_cert_copy) != 0 ||
- !CBS_get_optional_asn1(
- &tbs_cert_body, &discard, NULL,
- CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0) ||
- !CBS_get_asn1(&tbs_cert_body, &discard /* serialNumber */,
- CBS_ASN1_INTEGER) ||
- !CBS_get_asn1(&tbs_cert_body, &discard /* signature */,
- CBS_ASN1_SEQUENCE) ||
- !CBS_get_any_asn1_element(&tbs_cert_body, &discard /* issuer */,
- NULL, NULL) ||
- !CBS_get_asn1(&tbs_cert_body, &discard /* validity */,
- CBS_ASN1_SEQUENCE) ||
- !CBS_get_any_asn1_element(&tbs_cert_body, &discard /* subject */,
- NULL, NULL) ||
- !CBS_get_asn1_element(&tbs_cert_body, &spki, CBS_ASN1_SEQUENCE)) {
- return false;
- }
-
- const uint8_t *derp = CBS_data(&spki);
- ScopedEVP_PKEY pubkey(d2i_PUBKEY(NULL, &derp, CBS_len(&spki)));
- if (!pubkey || derp != CBS_data(&spki) + CBS_len(&spki)) {
- return false;
- }
-
- derp = CBS_data(&algorithm);
- ScopedX509_ALGOR algor(d2i_X509_ALGOR(NULL, &derp, CBS_len(&algorithm)));
- if (!algor || derp != CBS_data(&algorithm) + CBS_len(&algorithm)) {
- return false;
- }
-
- // Signatures are BIT STRINGs, but they have are multiple of 8 bytes, so the
- // leading phase byte is just a zero.
- uint8_t padding;
- if (!CBS_get_u8(&signature, &padding) || padding != 0) {
- return false;
- }
-
- *out_tbs_cert = tbs_cert;
- *out_pubkey = std::move(pubkey);
- *out_algor = std::move(algor);
- *out_signature = signature;
- return true;
-}
-
-static bool TestEVP_DigestVerifyInitFromAlgorithm(void) {
- CBS in, tbs_cert, signature;
- ScopedEVP_PKEY pkey;
- ScopedX509_ALGOR algor;
- CBS_init(&in, kExamplePSSCert, sizeof(kExamplePSSCert));
- if (!ParseCertificate(&tbs_cert, &pkey, &algor, &signature, &in)) {
- fprintf(stderr, "Failed to parse certificate\n");
- return false;
- }
-
- ScopedEVP_MD_CTX md_ctx;
- if (!EVP_DigestVerifyInitFromAlgorithm(md_ctx.get(), algor.get(),
- pkey.get()) ||
- !EVP_DigestVerifyUpdate(md_ctx.get(), CBS_data(&tbs_cert),
- CBS_len(&tbs_cert)) ||
- !EVP_DigestVerifyFinal(md_ctx.get(), CBS_data(&signature),
- CBS_len(&signature))) {
- return false;
- }
- return true;
-}
-
static bool TestVerifyRecover() {
ScopedEVP_PKEY pkey = LoadExampleRSAKey();
if (!pkey) {
@@ -792,26 +499,6 @@ static bool TestVerifyRecover() {
return true;
}
-static bool TestBadPSSParameters(void) {
- CBS in, tbs_cert, signature;
- ScopedEVP_PKEY pkey;
- ScopedX509_ALGOR algor;
- CBS_init(&in, kBadPSSCert, sizeof(kBadPSSCert));
- if (!ParseCertificate(&tbs_cert, &pkey, &algor, &signature, &in)) {
- fprintf(stderr, "Failed to parse certificate\n");
- return false;
- }
-
- ScopedEVP_MD_CTX md_ctx;
- if (EVP_DigestVerifyInitFromAlgorithm(md_ctx.get(), algor.get(),
- pkey.get())) {
- fprintf(stderr, "Unexpectedly processed bad signature parameters\n");
- return false;
- }
- ERR_clear_error();
- return true;
-}
-
static bool TestValidPrivateKey(const uint8_t *input, size_t input_len,
int expected_id) {
const uint8_t *p = input;
@@ -899,6 +586,25 @@ static bool TestEVP_PKCS82PKEY(void) {
return true;
}
+// TestEVPMarshalEmptyPublicKey tests |EVP_marshal_public_key| on an empty key.
+static bool TestEVPMarshalEmptyPublicKey(void) {
+ ScopedEVP_PKEY empty(EVP_PKEY_new());
+ if (!empty) {
+ return false;
+ }
+ ScopedCBB cbb;
+ if (EVP_marshal_public_key(cbb.get(), empty.get())) {
+ fprintf(stderr, "Marshalled empty public key.\n");
+ return false;
+ }
+ if (ERR_GET_REASON(ERR_peek_last_error()) != EVP_R_UNSUPPORTED_ALGORITHM) {
+ fprintf(stderr, "Marshalling an empty public key gave wrong error.\n");
+ return false;
+ }
+ ERR_clear_error();
+ return true;
+}
+
// Testd2i_PrivateKey tests |d2i_PrivateKey|.
static bool Testd2i_PrivateKey(void) {
const uint8_t *derp = kExampleRSAKeyDER;
@@ -953,6 +659,15 @@ static bool Testd2i_PrivateKey(void) {
}
ERR_clear_error();
+ derp = kExampleRSAKeyPKCS8;
+ pkey.reset(d2i_PrivateKey(EVP_PKEY_EC, nullptr, &derp,
+ sizeof(kExampleRSAKeyPKCS8)));
+ if (pkey) {
+ fprintf(stderr, "Imported RSA key as EC key.\n");
+ return false;
+ }
+ ERR_clear_error();
+
return true;
}
@@ -971,30 +686,12 @@ int main(void) {
return 1;
}
- if (!TestEVP_DigestSignAlgorithm()) {
- fprintf(stderr, "EVP_DigestSignInit failed\n");
- ERR_print_errors_fp(stderr);
- return 1;
- }
-
- if (!TestEVP_DigestVerifyInitFromAlgorithm()) {
- fprintf(stderr, "EVP_DigestVerifyInitFromAlgorithm failed\n");
- ERR_print_errors_fp(stderr);
- return 1;
- }
-
if (!TestVerifyRecover()) {
fprintf(stderr, "EVP_PKEY_verify_recover failed\n");
ERR_print_errors_fp(stderr);
return 1;
}
- if (!TestBadPSSParameters()) {
- fprintf(stderr, "TestBadPSSParameters failed\n");
- ERR_print_errors_fp(stderr);
- return 1;
- }
-
if (!Testd2i_AutoPrivateKey()) {
fprintf(stderr, "Testd2i_AutoPrivateKey failed\n");
ERR_print_errors_fp(stderr);
@@ -1007,6 +704,12 @@ int main(void) {
return 1;
}
+ if (!TestEVPMarshalEmptyPublicKey()) {
+ fprintf(stderr, "TestEVPMarshalEmptyPublicKey failed\n");
+ ERR_print_errors_fp(stderr);
+ return 1;
+ }
+
if (!Testd2i_PrivateKey()) {
fprintf(stderr, "Testd2i_PrivateKey failed\n");
ERR_print_errors_fp(stderr);
diff --git a/crypto/evp/evp_test.cc b/crypto/evp/evp_test.cc
index a7dac2bf..b01d1e47 100644
--- a/crypto/evp/evp_test.cc
+++ b/crypto/evp/evp_test.cc
@@ -51,30 +51,27 @@
* ====================================================================
*/
+#include <openssl/evp.h>
+
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#if defined(_MSC_VER)
-#pragma warning(push)
-#pragma warning(disable: 4702)
-#endif
+OPENSSL_MSVC_PRAGMA(warning(push))
+OPENSSL_MSVC_PRAGMA(warning(disable: 4702))
#include <map>
#include <string>
#include <utility>
#include <vector>
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
+OPENSSL_MSVC_PRAGMA(warning(pop))
#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/digest.h>
#include <openssl/err.h>
-#include <openssl/evp.h>
#include "../test/file_test.h"
#include "../test/scoped_types.h"
diff --git a/crypto/evp/evp_tests.txt b/crypto/evp/evp_tests.txt
index f0601b21..7c316d81 100644
--- a/crypto/evp/evp_tests.txt
+++ b/crypto/evp/evp_tests.txt
@@ -54,6 +54,11 @@ PublicKey = P-256-SPKI
Input = 3082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551020101034200042c150f429ce70f216c252cf5e062ce1f639cd5d165c7f89424072c27197d78b33b920e95cdb664e990dcf0cfea0d94e2a8e6af9d0e58056e653104925b9fe6c9
Error = DECODE_ERROR
+# The same as above, but with trailing data after the curve name.
+PublicKey = P-256-SPKI
+Input = 305b301506072a8648ce3d020106082a8648ce3d0301070500034200042c150f429ce70f216c252cf5e062ce1f639cd5d165c7f89424072c27197d78b33b920e95cdb664e990dcf0cfea0d94e2a8e6af9d0e58056e653104925b9fe6c9
+Error = DECODE_ERROR
+
# A DSA private key.
PrivateKey = DSA-1024
Type = DSA
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
index 7fe707e1..0783143d 100644
--- a/crypto/evp/internal.h
+++ b/crypto/evp/internal.h
@@ -59,36 +59,17 @@
#include <openssl/base.h>
+#include <openssl/rsa.h>
+
#if defined(__cplusplus)
extern "C" {
#endif
-/* These values are flags for EVP_PKEY_ASN1_METHOD.flags. */
-
-/* ASN1_PKEY_SIGPARAM_NULL controls whether the default behavior of
- * EVP_DigestSignAlgorithm writes an explicit NULL parameter in the
- * AlgorithmIdentifier. */
-#define ASN1_PKEY_SIGPARAM_NULL 0x1
-
-/* evp_digest_sign_algorithm_result_t is the return value of the
- * digest_sign_algorithm function in EVP_PKEY_ASN1_METHOD. */
-typedef enum {
- /* EVP_DIGEST_SIGN_ALGORITHM_ERROR signals an error. */
- EVP_DIGEST_SIGN_ALGORITHM_ERROR = 0,
- /* EVP_DIGEST_SIGN_ALGORITHM_SUCCESS signals that the parameters were
- * serialized in the AlgorithmIdentifier. */
- EVP_DIGEST_SIGN_ALGORITHM_SUCCESS = 1,
- /* EVP_DIGEST_SIGN_ALGORITHM_DEFAULT signals that the parameters are
- * serialized using the default behavior. */
- EVP_DIGEST_SIGN_ALGORITHM_DEFAULT = 2,
-} evp_digest_sign_algorithm_result_t;
-
struct evp_pkey_asn1_method_st {
int pkey_id;
- unsigned long pkey_flags;
-
- const char *pem_str;
+ uint8_t oid[9];
+ uint8_t oid_len;
/* pub_decode decodes |params| and |key| as a SubjectPublicKeyInfo
* and writes the result into |out|. It returns one on success and zero on
@@ -104,7 +85,6 @@ struct evp_pkey_asn1_method_st {
int (*pub_encode)(CBB *out, const EVP_PKEY *key);
int (*pub_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
- int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx);
/* priv_decode decodes |params| and |key| as a PrivateKeyInfo and writes the
* result into |out|. It returns one on success and zero on error. |params| is
@@ -116,9 +96,6 @@ struct evp_pkey_asn1_method_st {
* |out|. It returns one on success and zero on error. */
int (*priv_encode)(CBB *out, const EVP_PKEY *key);
- int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *pctx);
-
/* pkey_opaque returns 1 if the |pk| is opaque. Opaque keys are backed by
* custom implementations which do not expose key material and parameters.*/
int (*pkey_opaque)(const EVP_PKEY *pk);
@@ -135,27 +112,8 @@ struct evp_pkey_asn1_method_st {
int (*param_missing)(const EVP_PKEY *pk);
int (*param_copy)(EVP_PKEY *to, const EVP_PKEY *from);
int (*param_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
- int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *pctx);
- int (*sig_print)(BIO *out, const X509_ALGOR *sigalg, const ASN1_STRING *sig,
- int indent, ASN1_PCTX *pctx);
-
void (*pkey_free)(EVP_PKEY *pkey);
-
- /* Legacy functions for old PEM */
-
- int (*old_priv_decode)(EVP_PKEY *pkey, const uint8_t **pder,
- int derlen);
-
- /* Converting parameters to/from AlgorithmIdentifier (X509_ALGOR). */
- int (*digest_verify_init_from_algorithm)(EVP_MD_CTX *ctx,
- X509_ALGOR *algor,
- EVP_PKEY *pkey);
- evp_digest_sign_algorithm_result_t (*digest_sign_algorithm)(
- EVP_MD_CTX *ctx,
- X509_ALGOR *algor);
-
} /* EVP_PKEY_ASN1_METHOD */;
diff --git a/crypto/evp/p_dsa_asn1.c b/crypto/evp/p_dsa_asn1.c
index 09f69090..1f022f1a 100644
--- a/crypto/evp/p_dsa_asn1.c
+++ b/crypto/evp/p_dsa_asn1.c
@@ -55,16 +55,11 @@
#include <openssl/evp.h>
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
#include <openssl/digest.h>
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/dsa.h>
#include <openssl/err.h>
-#include <openssl/mem.h>
-#include <openssl/obj.h>
-#include <openssl/x509.h>
#include "internal.h"
@@ -111,10 +106,11 @@ static int dsa_pub_encode(CBB *out, const EVP_PKEY *key) {
const int has_params = dsa->p != NULL && dsa->q != NULL && dsa->g != NULL;
/* See RFC 5480, section 2. */
- CBB spki, algorithm, key_bitstring;
+ CBB spki, algorithm, oid, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&algorithm, NID_dsa) ||
+ !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
+ !CBB_add_bytes(&oid, dsa_asn1_meth.oid, dsa_asn1_meth.oid_len) ||
(has_params &&
!DSA_marshal_parameters(&algorithm, dsa)) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
@@ -177,11 +173,12 @@ static int dsa_priv_encode(CBB *out, const EVP_PKEY *key) {
}
/* See PKCS#11, v2.40, section 2.5. */
- CBB pkcs8, algorithm, private_key;
+ CBB pkcs8, algorithm, oid, private_key;
if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
!CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&algorithm, NID_dsa) ||
+ !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
+ !CBB_add_bytes(&oid, dsa_asn1_meth.oid, dsa_asn1_meth.oid_len) ||
!DSA_marshal_parameters(&algorithm, dsa) ||
!CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
!BN_marshal_asn1(&private_key, dsa->priv_key) ||
@@ -245,157 +242,17 @@ static int dsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
static void int_dsa_free(EVP_PKEY *pkey) { DSA_free(pkey->pkey.dsa); }
-static void update_buflen(const BIGNUM *b, size_t *pbuflen) {
- size_t i;
-
- if (!b) {
- return;
- }
- i = BN_num_bytes(b);
- if (*pbuflen < i) {
- *pbuflen = i;
- }
-}
-
-static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype) {
- uint8_t *m = NULL;
- int ret = 0;
- size_t buf_len = 0;
- const char *ktype = NULL;
-
- const BIGNUM *priv_key, *pub_key;
-
- priv_key = NULL;
- if (ptype == 2) {
- priv_key = x->priv_key;
- }
-
- pub_key = NULL;
- if (ptype > 0) {
- pub_key = x->pub_key;
- }
-
- ktype = "DSA-Parameters";
- if (ptype == 2) {
- ktype = "Private-Key";
- } else if (ptype == 1) {
- ktype = "Public-Key";
- }
-
- update_buflen(x->p, &buf_len);
- update_buflen(x->q, &buf_len);
- update_buflen(x->g, &buf_len);
- update_buflen(priv_key, &buf_len);
- update_buflen(pub_key, &buf_len);
-
- m = OPENSSL_malloc(buf_len + 10);
- if (m == NULL) {
- OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (priv_key) {
- if (!BIO_indent(bp, off, 128) ||
- BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0) {
- goto err;
- }
- }
-
- if (!ASN1_bn_print(bp, "priv:", priv_key, m, off) ||
- !ASN1_bn_print(bp, "pub: ", pub_key, m, off) ||
- !ASN1_bn_print(bp, "P: ", x->p, m, off) ||
- !ASN1_bn_print(bp, "Q: ", x->q, m, off) ||
- !ASN1_bn_print(bp, "G: ", x->g, m, off)) {
- goto err;
- }
- ret = 1;
-
-err:
- OPENSSL_free(m);
- return ret;
-}
-
-static int dsa_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx) {
- return do_dsa_print(bp, pkey->pkey.dsa, indent, 0);
-}
-
-static int dsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx) {
- return do_dsa_print(bp, pkey->pkey.dsa, indent, 1);
-}
-
-static int dsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx) {
- return do_dsa_print(bp, pkey->pkey.dsa, indent, 2);
-}
-
-static int old_dsa_priv_decode(EVP_PKEY *pkey, const uint8_t **pder,
- int derlen) {
- DSA *dsa;
- dsa = d2i_DSAPrivateKey(NULL, pder, derlen);
- if (dsa == NULL) {
- OPENSSL_PUT_ERROR(EVP, ERR_R_DSA_LIB);
- return 0;
- }
- EVP_PKEY_assign_DSA(pkey, dsa);
- return 1;
-}
-
-static int dsa_sig_print(BIO *bp, const X509_ALGOR *sigalg,
- const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx) {
- DSA_SIG *dsa_sig;
- const uint8_t *p;
-
- if (!sig) {
- return BIO_puts(bp, "\n") > 0;
- }
-
- p = sig->data;
- dsa_sig = d2i_DSA_SIG(NULL, &p, sig->length);
- if (dsa_sig == NULL) {
- return X509_signature_dump(bp, sig, indent);
- }
-
- int rv = 0;
- size_t buf_len = 0;
- uint8_t *m = NULL;
-
- update_buflen(dsa_sig->r, &buf_len);
- update_buflen(dsa_sig->s, &buf_len);
- m = OPENSSL_malloc(buf_len + 10);
- if (m == NULL) {
- OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (BIO_write(bp, "\n", 1) != 1 ||
- !ASN1_bn_print(bp, "r: ", dsa_sig->r, m, indent) ||
- !ASN1_bn_print(bp, "s: ", dsa_sig->s, m, indent)) {
- goto err;
- }
- rv = 1;
-
-err:
- OPENSSL_free(m);
- DSA_SIG_free(dsa_sig);
- return rv;
-}
-
const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = {
EVP_PKEY_DSA,
- 0,
-
- "DSA",
+ /* 1.2.840.10040.4.1 */
+ {0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01}, 7,
dsa_pub_decode,
dsa_pub_encode,
dsa_pub_cmp,
- dsa_pub_print,
dsa_priv_decode,
dsa_priv_encode,
- dsa_priv_print,
NULL /* pkey_opaque */,
NULL /* pkey_supports_digest */,
@@ -406,12 +263,6 @@ const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = {
dsa_missing_parameters,
dsa_copy_parameters,
dsa_cmp_parameters,
- dsa_param_print,
- dsa_sig_print,
int_dsa_free,
- old_dsa_priv_decode,
-
- NULL /* digest_verify_init_from_algorithm */,
- NULL /* digest_sign_algorithm */,
};
diff --git a/crypto/evp/p_ec.c b/crypto/evp/p_ec.c
index 49521827..f92c87cf 100644
--- a/crypto/evp/p_ec.c
+++ b/crypto/evp/p_ec.c
@@ -66,7 +66,7 @@
#include <openssl/ecdsa.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include "internal.h"
#include "../ec/internal.h"
diff --git a/crypto/evp/p_ec_asn1.c b/crypto/evp/p_ec_asn1.c
index 14f38396..8d44dcdc 100644
--- a/crypto/evp/p_ec_asn1.c
+++ b/crypto/evp/p_ec_asn1.c
@@ -55,16 +55,12 @@
#include <openssl/evp.h>
-#include <openssl/asn1t.h>
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/ec.h>
#include <openssl/ec_key.h>
#include <openssl/ecdsa.h>
#include <openssl/err.h>
-#include <openssl/mem.h>
-#include <openssl/obj.h>
-#include <openssl/x509.h>
#include "internal.h"
@@ -72,19 +68,15 @@
static int eckey_pub_encode(CBB *out, const EVP_PKEY *key) {
const EC_KEY *ec_key = key->pkey.ec;
const EC_GROUP *group = EC_KEY_get0_group(ec_key);
- int curve_nid = EC_GROUP_get_curve_name(group);
- if (curve_nid == NID_undef) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE);
- return 0;
- }
const EC_POINT *public_key = EC_KEY_get0_public_key(ec_key);
/* See RFC 5480, section 2. */
- CBB spki, algorithm, key_bitstring;
+ CBB spki, algorithm, oid, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&algorithm, NID_X9_62_id_ecPublicKey) ||
- !OBJ_nid2cbb(&algorithm, curve_nid) ||
+ !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
+ !CBB_add_bytes(&oid, ec_asn1_meth.oid, ec_asn1_meth.oid_len) ||
+ !EC_KEY_marshal_curve_name(&algorithm, group) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
!EC_POINT_point2cbb(&key_bitstring, group, public_key,
@@ -101,31 +93,33 @@ static int eckey_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
/* See RFC 5480, section 2. */
/* The parameters are a named curve. */
- CBS named_curve;
- if (!CBS_get_asn1(params, &named_curve, CBS_ASN1_OBJECT) ||
- CBS_len(params) != 0) {
+ EC_POINT *point = NULL;
+ EC_KEY *eckey = NULL;
+ EC_GROUP *group = EC_KEY_parse_curve_name(params);
+ if (group == NULL || CBS_len(params) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
- return 0;
+ goto err;
}
- EC_KEY *eckey = EC_KEY_new_by_curve_name(OBJ_cbs2nid(&named_curve));
- if (eckey == NULL) {
- return 0;
+ eckey = EC_KEY_new();
+ if (eckey == NULL || !EC_KEY_set_group(eckey, group)) {
+ goto err;
}
- EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(eckey));
+ point = EC_POINT_new(group);
if (point == NULL ||
- !EC_POINT_oct2point(EC_KEY_get0_group(eckey), point, CBS_data(key),
- CBS_len(key), NULL) ||
+ !EC_POINT_oct2point(group, point, CBS_data(key), CBS_len(key), NULL) ||
!EC_KEY_set_public_key(eckey, point)) {
goto err;
}
+ EC_GROUP_free(group);
EC_POINT_free(point);
EVP_PKEY_assign_EC_KEY(out, eckey);
return 1;
err:
+ EC_GROUP_free(group);
EC_POINT_free(point);
EC_KEY_free(eckey);
return 0;
@@ -169,11 +163,6 @@ static int eckey_priv_decode(EVP_PKEY *out, CBS *params, CBS *key) {
static int eckey_priv_encode(CBB *out, const EVP_PKEY *key) {
const EC_KEY *ec_key = key->pkey.ec;
- int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
- if (curve_nid == NID_undef) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE);
- return 0;
- }
/* Omit the redundant copy of the curve name. This contradicts RFC 5915 but
* aligns with PKCS #11. SEC 1 only says they may be omitted if known by other
@@ -182,12 +171,13 @@ static int eckey_priv_encode(CBB *out, const EVP_PKEY *key) {
unsigned enc_flags = EC_KEY_get_enc_flags(ec_key) | EC_PKEY_NO_PARAMETERS;
/* See RFC 5915. */
- CBB pkcs8, algorithm, private_key;
+ CBB pkcs8, algorithm, oid, private_key;
if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
!CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&algorithm, NID_X9_62_id_ecPublicKey) ||
- !OBJ_nid2cbb(&algorithm, curve_nid) ||
+ !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
+ !CBB_add_bytes(&oid, ec_asn1_meth.oid, ec_asn1_meth.oid_len) ||
+ !EC_KEY_marshal_curve_name(&algorithm, EC_KEY_get0_group(ec_key)) ||
!CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
!EC_KEY_marshal_private_key(&private_key, ec_key, enc_flags) ||
!CBB_flush(out)) {
@@ -237,153 +227,21 @@ static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
static void int_ec_free(EVP_PKEY *pkey) { EC_KEY_free(pkey->pkey.ec); }
-static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype) {
- uint8_t *buffer = NULL;
- const char *ecstr;
- size_t buf_len = 0, i;
- int ret = 0, reason = ERR_R_BIO_LIB;
- BN_CTX *ctx = NULL;
- const EC_GROUP *group;
- const EC_POINT *public_key;
- const BIGNUM *priv_key;
- uint8_t *pub_key_bytes = NULL;
- size_t pub_key_bytes_len = 0;
-
- if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) {
- reason = ERR_R_PASSED_NULL_PARAMETER;
- goto err;
- }
-
- ctx = BN_CTX_new();
- if (ctx == NULL) {
- reason = ERR_R_MALLOC_FAILURE;
- goto err;
- }
-
- if (ktype > 0) {
- public_key = EC_KEY_get0_public_key(x);
- if (public_key != NULL) {
- pub_key_bytes_len = EC_POINT_point2oct(
- group, public_key, EC_KEY_get_conv_form(x), NULL, 0, ctx);
- if (pub_key_bytes_len == 0) {
- reason = ERR_R_MALLOC_FAILURE;
- goto err;
- }
- pub_key_bytes = OPENSSL_malloc(pub_key_bytes_len);
- if (pub_key_bytes == NULL) {
- reason = ERR_R_MALLOC_FAILURE;
- goto err;
- }
- pub_key_bytes_len =
- EC_POINT_point2oct(group, public_key, EC_KEY_get_conv_form(x),
- pub_key_bytes, pub_key_bytes_len, ctx);
- if (pub_key_bytes_len == 0) {
- reason = ERR_R_MALLOC_FAILURE;
- goto err;
- }
- buf_len = pub_key_bytes_len;
- }
- }
-
- if (ktype == 2) {
- priv_key = EC_KEY_get0_private_key(x);
- if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len) {
- buf_len = i;
- }
- } else {
- priv_key = NULL;
- }
-
- if (ktype > 0) {
- buf_len += 10;
- if ((buffer = OPENSSL_malloc(buf_len)) == NULL) {
- reason = ERR_R_MALLOC_FAILURE;
- goto err;
- }
- }
- if (ktype == 2) {
- ecstr = "Private-Key";
- } else if (ktype == 1) {
- ecstr = "Public-Key";
- } else {
- ecstr = "ECDSA-Parameters";
- }
-
- if (!BIO_indent(bp, off, 128)) {
- goto err;
- }
- const BIGNUM *order = EC_GROUP_get0_order(group);
- if (BIO_printf(bp, "%s: (%d bit)\n", ecstr, BN_num_bits(order)) <= 0) {
- goto err;
- }
-
- if ((priv_key != NULL) &&
- !ASN1_bn_print(bp, "priv:", priv_key, buffer, off)) {
- goto err;
- }
- if (pub_key_bytes != NULL) {
- BIO_hexdump(bp, pub_key_bytes, pub_key_bytes_len, off);
- }
- /* TODO(fork): implement */
- /*
- if (!ECPKParameters_print(bp, group, off))
- goto err; */
- ret = 1;
-
-err:
- if (!ret) {
- OPENSSL_PUT_ERROR(EVP, reason);
- }
- OPENSSL_free(pub_key_bytes);
- BN_CTX_free(ctx);
- OPENSSL_free(buffer);
- return ret;
-}
-
-static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx) {
- return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0);
-}
-
-static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx) {
- return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1);
-}
-
-
-static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx) {
- return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2);
-}
-
static int eckey_opaque(const EVP_PKEY *pkey) {
return EC_KEY_is_opaque(pkey->pkey.ec);
}
-static int old_ec_priv_decode(EVP_PKEY *pkey, const uint8_t **pder,
- int derlen) {
- EC_KEY *ec;
- if (!(ec = d2i_ECPrivateKey(NULL, pder, derlen))) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
- return 0;
- }
- EVP_PKEY_assign_EC_KEY(pkey, ec);
- return 1;
-}
-
const EVP_PKEY_ASN1_METHOD ec_asn1_meth = {
EVP_PKEY_EC,
- 0,
- "EC",
+ /* 1.2.840.10045.2.1 */
+ {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01}, 7,
eckey_pub_decode,
eckey_pub_encode,
eckey_pub_cmp,
- eckey_pub_print,
eckey_priv_decode,
eckey_priv_encode,
- eckey_priv_print,
eckey_opaque,
0 /* pkey_supports_digest */,
@@ -394,12 +252,6 @@ const EVP_PKEY_ASN1_METHOD ec_asn1_meth = {
ec_missing_parameters,
ec_copy_parameters,
ec_cmp_parameters,
- eckey_param_print,
- 0,
int_ec_free,
- old_ec_priv_decode,
-
- NULL /* digest_verify_init_from_algorithm */,
- NULL /* digest_sign_algorithm */,
};
diff --git a/crypto/evp/p_rsa.c b/crypto/evp/p_rsa.c
index 629c33a6..a2106572 100644
--- a/crypto/evp/p_rsa.c
+++ b/crypto/evp/p_rsa.c
@@ -64,7 +64,7 @@
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/rsa.h>
#include "../rsa/internal.h"
diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c
index 6848cc47..2c4b266d 100644
--- a/crypto/evp/p_rsa_asn1.c
+++ b/crypto/evp/p_rsa_asn1.c
@@ -55,15 +55,12 @@
#include <openssl/evp.h>
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
+#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
#include <openssl/rsa.h>
-#include <openssl/x509.h>
#include "../rsa/internal.h"
#include "internal.h"
@@ -71,10 +68,11 @@
static int rsa_pub_encode(CBB *out, const EVP_PKEY *key) {
/* See RFC 3279, section 2.3.1. */
- CBB spki, algorithm, null, key_bitstring;
+ CBB spki, algorithm, oid, null, key_bitstring;
if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&algorithm, NID_rsaEncryption) ||
+ !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
+ !CBB_add_bytes(&oid, rsa_asn1_meth.oid, rsa_asn1_meth.oid_len) ||
!CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) ||
!CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
!CBB_add_u8(&key_bitstring, 0 /* padding */) ||
@@ -122,11 +120,12 @@ static int rsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
}
static int rsa_priv_encode(CBB *out, const EVP_PKEY *key) {
- CBB pkcs8, algorithm, null, private_key;
+ CBB pkcs8, algorithm, oid, null, private_key;
if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
!CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&algorithm, NID_rsaEncryption) ||
+ !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
+ !CBB_add_bytes(&oid, rsa_asn1_meth.oid, rsa_asn1_meth.oid_len) ||
!CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) ||
!CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
!RSA_marshal_private_key(&private_key, key->pkey.rsa) ||
@@ -177,548 +176,17 @@ static int rsa_bits(const EVP_PKEY *pkey) {
static void int_rsa_free(EVP_PKEY *pkey) { RSA_free(pkey->pkey.rsa); }
-static void update_buflen(const BIGNUM *b, size_t *pbuflen) {
- size_t i;
-
- if (!b) {
- return;
- }
-
- i = BN_num_bytes(b);
- if (*pbuflen < i) {
- *pbuflen = i;
- }
-}
-
-static int do_rsa_print(BIO *out, const RSA *rsa, int off,
- int include_private) {
- char *str;
- const char *s;
- uint8_t *m = NULL;
- int ret = 0, mod_len = 0;
- size_t buf_len = 0;
-
- update_buflen(rsa->n, &buf_len);
- update_buflen(rsa->e, &buf_len);
-
- if (include_private) {
- update_buflen(rsa->d, &buf_len);
- update_buflen(rsa->p, &buf_len);
- update_buflen(rsa->q, &buf_len);
- update_buflen(rsa->dmp1, &buf_len);
- update_buflen(rsa->dmq1, &buf_len);
- update_buflen(rsa->iqmp, &buf_len);
-
- if (rsa->additional_primes != NULL) {
- size_t i;
-
- for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes);
- i++) {
- const RSA_additional_prime *ap =
- sk_RSA_additional_prime_value(rsa->additional_primes, i);
- update_buflen(ap->prime, &buf_len);
- update_buflen(ap->exp, &buf_len);
- update_buflen(ap->coeff, &buf_len);
- }
- }
- }
-
- m = OPENSSL_malloc(buf_len + 10);
- if (m == NULL) {
- OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (rsa->n != NULL) {
- mod_len = BN_num_bits(rsa->n);
- }
-
- if (!BIO_indent(out, off, 128)) {
- goto err;
- }
-
- if (include_private && rsa->d) {
- if (BIO_printf(out, "Private-Key: (%d bit)\n", mod_len) <= 0) {
- goto err;
- }
- str = "modulus:";
- s = "publicExponent:";
- } else {
- if (BIO_printf(out, "Public-Key: (%d bit)\n", mod_len) <= 0) {
- goto err;
- }
- str = "Modulus:";
- s = "Exponent:";
- }
- if (!ASN1_bn_print(out, str, rsa->n, m, off) ||
- !ASN1_bn_print(out, s, rsa->e, m, off)) {
- goto err;
- }
-
- if (include_private) {
- if (!ASN1_bn_print(out, "privateExponent:", rsa->d, m, off) ||
- !ASN1_bn_print(out, "prime1:", rsa->p, m, off) ||
- !ASN1_bn_print(out, "prime2:", rsa->q, m, off) ||
- !ASN1_bn_print(out, "exponent1:", rsa->dmp1, m, off) ||
- !ASN1_bn_print(out, "exponent2:", rsa->dmq1, m, off) ||
- !ASN1_bn_print(out, "coefficient:", rsa->iqmp, m, off)) {
- goto err;
- }
-
- if (rsa->additional_primes != NULL &&
- sk_RSA_additional_prime_num(rsa->additional_primes) > 0) {
- size_t i;
-
- if (BIO_printf(out, "otherPrimeInfos:\n") <= 0) {
- goto err;
- }
- for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes);
- i++) {
- const RSA_additional_prime *ap =
- sk_RSA_additional_prime_value(rsa->additional_primes, i);
-
- if (BIO_printf(out, "otherPrimeInfo (prime %u):\n",
- (unsigned)(i + 3)) <= 0 ||
- !ASN1_bn_print(out, "prime:", ap->prime, m, off) ||
- !ASN1_bn_print(out, "exponent:", ap->exp, m, off) ||
- !ASN1_bn_print(out, "coeff:", ap->coeff, m, off)) {
- goto err;
- }
- }
- }
- }
- ret = 1;
-
-err:
- OPENSSL_free(m);
- return ret;
-}
-
-static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx) {
- return do_rsa_print(bp, pkey->pkey.rsa, indent, 0);
-}
-
-
-static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
- ASN1_PCTX *ctx) {
- return do_rsa_print(bp, pkey->pkey.rsa, indent, 1);
-}
-
-/* Given an MGF1 Algorithm ID decode to an Algorithm Identifier */
-static X509_ALGOR *rsa_mgf1_decode(X509_ALGOR *alg) {
- const uint8_t *p;
- int plen;
-
- if (alg == NULL || alg->parameter == NULL ||
- OBJ_obj2nid(alg->algorithm) != NID_mgf1 ||
- alg->parameter->type != V_ASN1_SEQUENCE) {
- return NULL;
- }
-
- p = alg->parameter->value.sequence->data;
- plen = alg->parameter->value.sequence->length;
- return d2i_X509_ALGOR(NULL, &p, plen);
-}
-
-static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg,
- X509_ALGOR **pmaskHash) {
- const uint8_t *p;
- int plen;
- RSA_PSS_PARAMS *pss;
-
- *pmaskHash = NULL;
-
- if (!alg->parameter || alg->parameter->type != V_ASN1_SEQUENCE) {
- return NULL;
- }
- p = alg->parameter->value.sequence->data;
- plen = alg->parameter->value.sequence->length;
- pss = d2i_RSA_PSS_PARAMS(NULL, &p, plen);
-
- if (!pss) {
- return NULL;
- }
-
- *pmaskHash = rsa_mgf1_decode(pss->maskGenAlgorithm);
-
- return pss;
-}
-
-static int rsa_pss_param_print(BIO *bp, RSA_PSS_PARAMS *pss,
- X509_ALGOR *maskHash, int indent) {
- int rv = 0;
-
- if (!pss) {
- if (BIO_puts(bp, " (INVALID PSS PARAMETERS)\n") <= 0) {
- return 0;
- }
- return 1;
- }
-
- if (BIO_puts(bp, "\n") <= 0 ||
- !BIO_indent(bp, indent, 128) ||
- BIO_puts(bp, "Hash Algorithm: ") <= 0) {
- goto err;
- }
-
- if (pss->hashAlgorithm) {
- if (i2a_ASN1_OBJECT(bp, pss->hashAlgorithm->algorithm) <= 0) {
- goto err;
- }
- } else if (BIO_puts(bp, "sha1 (default)") <= 0) {
- goto err;
- }
-
- if (BIO_puts(bp, "\n") <= 0 ||
- !BIO_indent(bp, indent, 128) ||
- BIO_puts(bp, "Mask Algorithm: ") <= 0) {
- goto err;
- }
-
- if (pss->maskGenAlgorithm) {
- if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0 ||
- BIO_puts(bp, " with ") <= 0) {
- goto err;
- }
-
- if (maskHash) {
- if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0) {
- goto err;
- }
- } else if (BIO_puts(bp, "INVALID") <= 0) {
- goto err;
- }
- } else if (BIO_puts(bp, "mgf1 with sha1 (default)") <= 0) {
- goto err;
- }
- BIO_puts(bp, "\n");
-
- if (!BIO_indent(bp, indent, 128) ||
- BIO_puts(bp, "Salt Length: 0x") <= 0) {
- goto err;
- }
-
- if (pss->saltLength) {
- if (i2a_ASN1_INTEGER(bp, pss->saltLength) <= 0) {
- goto err;
- }
- } else if (BIO_puts(bp, "14 (default)") <= 0) {
- goto err;
- }
- BIO_puts(bp, "\n");
-
- if (!BIO_indent(bp, indent, 128) ||
- BIO_puts(bp, "Trailer Field: 0x") <= 0) {
- goto err;
- }
-
- if (pss->trailerField) {
- if (i2a_ASN1_INTEGER(bp, pss->trailerField) <= 0) {
- goto err;
- }
- } else if (BIO_puts(bp, "BC (default)") <= 0) {
- goto err;
- }
- BIO_puts(bp, "\n");
-
- rv = 1;
-
-err:
- return rv;
-}
-
-static int rsa_sig_print(BIO *bp, const X509_ALGOR *sigalg,
- const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx) {
- if (OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss) {
- int rv;
- RSA_PSS_PARAMS *pss;
- X509_ALGOR *maskHash;
-
- pss = rsa_pss_decode(sigalg, &maskHash);
- rv = rsa_pss_param_print(bp, pss, maskHash, indent);
- RSA_PSS_PARAMS_free(pss);
- X509_ALGOR_free(maskHash);
- if (!rv) {
- return 0;
- }
- } else if (!sig && BIO_puts(bp, "\n") <= 0) {
- return 0;
- }
-
- if (sig) {
- return X509_signature_dump(bp, sig, indent);
- }
- return 1;
-}
-
-static int old_rsa_priv_decode(EVP_PKEY *pkey, const uint8_t **pder,
- int derlen) {
- RSA *rsa = d2i_RSAPrivateKey(NULL, pder, derlen);
- if (rsa == NULL) {
- OPENSSL_PUT_ERROR(EVP, ERR_R_RSA_LIB);
- return 0;
- }
- EVP_PKEY_assign_RSA(pkey, rsa);
- return 1;
-}
-
-/* allocate and set algorithm ID from EVP_MD, default SHA1 */
-static int rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md) {
- if (EVP_MD_type(md) == NID_sha1) {
- return 1;
- }
- *palg = X509_ALGOR_new();
- if (!*palg) {
- return 0;
- }
- X509_ALGOR_set_md(*palg, md);
- return 1;
-}
-
-/* Allocate and set MGF1 algorithm ID from EVP_MD */
-static int rsa_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md) {
- X509_ALGOR *algtmp = NULL;
- ASN1_STRING *stmp = NULL;
- *palg = NULL;
-
- if (EVP_MD_type(mgf1md) == NID_sha1) {
- return 1;
- }
- /* need to embed algorithm ID inside another */
- if (!rsa_md_to_algor(&algtmp, mgf1md) ||
- !ASN1_item_pack(algtmp, ASN1_ITEM_rptr(X509_ALGOR), &stmp)) {
- goto err;
- }
- *palg = X509_ALGOR_new();
- if (!*palg) {
- goto err;
- }
- X509_ALGOR_set0(*palg, OBJ_nid2obj(NID_mgf1), V_ASN1_SEQUENCE, stmp);
- stmp = NULL;
-
-err:
- ASN1_STRING_free(stmp);
- X509_ALGOR_free(algtmp);
- if (*palg) {
- return 1;
- }
-
- return 0;
-}
-
-/* convert algorithm ID to EVP_MD, default SHA1 */
-static const EVP_MD *rsa_algor_to_md(X509_ALGOR *alg) {
- const EVP_MD *md;
- if (!alg) {
- return EVP_sha1();
- }
- md = EVP_get_digestbyobj(alg->algorithm);
- if (md == NULL) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_DIGEST);
- }
- return md;
-}
-
-/* convert MGF1 algorithm ID to EVP_MD, default SHA1 */
-static const EVP_MD *rsa_mgf1_to_md(X509_ALGOR *alg, X509_ALGOR *maskHash) {
- const EVP_MD *md;
- if (!alg) {
- return EVP_sha1();
- }
- /* Check mask and lookup mask hash algorithm */
- if (OBJ_obj2nid(alg->algorithm) != NID_mgf1) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_MASK_ALGORITHM);
- return NULL;
- }
- if (!maskHash) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_MASK_PARAMETER);
- return NULL;
- }
- md = EVP_get_digestbyobj(maskHash->algorithm);
- if (md == NULL) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_MASK_DIGEST);
- return NULL;
- }
- return md;
-}
-
-/* rsa_ctx_to_pss converts EVP_PKEY_CTX in PSS mode into corresponding
- * algorithm parameter, suitable for setting as an AlgorithmIdentifier. */
-static ASN1_STRING *rsa_ctx_to_pss(EVP_PKEY_CTX *pkctx) {
- const EVP_MD *sigmd, *mgf1md;
- RSA_PSS_PARAMS *pss = NULL;
- ASN1_STRING *os = NULL;
- EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(pkctx);
- int saltlen, rv = 0;
-
- if (!EVP_PKEY_CTX_get_signature_md(pkctx, &sigmd) ||
- !EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) ||
- !EVP_PKEY_CTX_get_rsa_pss_saltlen(pkctx, &saltlen)) {
- goto err;
- }
-
- if (saltlen == -1) {
- saltlen = EVP_MD_size(sigmd);
- } else if (saltlen == -2) {
- saltlen = EVP_PKEY_size(pk) - EVP_MD_size(sigmd) - 2;
- if (((EVP_PKEY_bits(pk) - 1) & 0x7) == 0) {
- saltlen--;
- }
- } else {
- goto err;
- }
-
- pss = RSA_PSS_PARAMS_new();
- if (!pss) {
- goto err;
- }
-
- if (saltlen != 20) {
- pss->saltLength = ASN1_INTEGER_new();
- if (!pss->saltLength ||
- !ASN1_INTEGER_set(pss->saltLength, saltlen)) {
- goto err;
- }
- }
-
- if (!rsa_md_to_algor(&pss->hashAlgorithm, sigmd) ||
- !rsa_md_to_mgf1(&pss->maskGenAlgorithm, mgf1md)) {
- goto err;
- }
-
- /* Finally create string with pss parameter encoding. */
- if (!ASN1_item_pack(pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), &os)) {
- goto err;
- }
- rv = 1;
-
-err:
- if (pss) {
- RSA_PSS_PARAMS_free(pss);
- }
- if (rv) {
- return os;
- }
- if (os) {
- ASN1_STRING_free(os);
- }
- return NULL;
-}
-
-/* From PSS AlgorithmIdentifier set public key parameters. */
-static int rsa_pss_to_ctx(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, EVP_PKEY *pkey) {
- int ret = 0;
- int saltlen;
- const EVP_MD *mgf1md = NULL, *md = NULL;
- RSA_PSS_PARAMS *pss;
- X509_ALGOR *maskHash;
- EVP_PKEY_CTX *pkctx;
-
- /* Sanity check: make sure it is PSS */
- if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_SIGNATURE_TYPE);
- return 0;
- }
- /* Decode PSS parameters */
- pss = rsa_pss_decode(sigalg, &maskHash);
- if (pss == NULL) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_PARAMETERS);
- goto err;
- }
-
- mgf1md = rsa_mgf1_to_md(pss->maskGenAlgorithm, maskHash);
- if (!mgf1md) {
- goto err;
- }
- md = rsa_algor_to_md(pss->hashAlgorithm);
- if (!md) {
- goto err;
- }
-
- saltlen = 20;
- if (pss->saltLength) {
- saltlen = ASN1_INTEGER_get(pss->saltLength);
-
- /* Could perform more salt length sanity checks but the main
- * RSA routines will trap other invalid values anyway. */
- if (saltlen < 0) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SALT_LENGTH);
- goto err;
- }
- }
-
- /* low-level routines support only trailer field 0xbc (value 1)
- * and PKCS#1 says we should reject any other value anyway. */
- if (pss->trailerField && ASN1_INTEGER_get(pss->trailerField) != 1) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_TRAILER);
- goto err;
- }
-
- if (!EVP_DigestVerifyInit(ctx, &pkctx, md, NULL, pkey) ||
- !EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING) ||
- !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen) ||
- !EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md)) {
- goto err;
- }
-
- ret = 1;
-
-err:
- RSA_PSS_PARAMS_free(pss);
- if (maskHash) {
- X509_ALGOR_free(maskHash);
- }
- return ret;
-}
-
-/* Customised RSA AlgorithmIdentifier handling. This is called when a signature
- * is encountered requiring special handling. We currently only handle PSS. */
-static int rsa_digest_verify_init_from_algorithm(EVP_MD_CTX *ctx,
- X509_ALGOR *sigalg,
- EVP_PKEY *pkey) {
- /* Sanity check: make sure it is PSS */
- if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_SIGNATURE_TYPE);
- return 0;
- }
- return rsa_pss_to_ctx(ctx, sigalg, pkey);
-}
-
-static evp_digest_sign_algorithm_result_t rsa_digest_sign_algorithm(
- EVP_MD_CTX *ctx, X509_ALGOR *sigalg) {
- int pad_mode;
- EVP_PKEY_CTX *pkctx = ctx->pctx;
- if (!EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode)) {
- return EVP_DIGEST_SIGN_ALGORITHM_ERROR;
- }
- if (pad_mode == RSA_PKCS1_PSS_PADDING) {
- ASN1_STRING *os1 = rsa_ctx_to_pss(pkctx);
- if (!os1) {
- return EVP_DIGEST_SIGN_ALGORITHM_ERROR;
- }
- X509_ALGOR_set0(sigalg, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os1);
- return EVP_DIGEST_SIGN_ALGORITHM_SUCCESS;
- }
-
- /* Other padding schemes use the default behavior. */
- return EVP_DIGEST_SIGN_ALGORITHM_DEFAULT;
-}
-
const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = {
EVP_PKEY_RSA,
- ASN1_PKEY_SIGPARAM_NULL,
-
- "RSA",
+ /* 1.2.840.113549.1.1.1 */
+ {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01}, 9,
rsa_pub_decode,
rsa_pub_encode,
rsa_pub_cmp,
- rsa_pub_print,
rsa_priv_decode,
rsa_priv_encode,
- rsa_priv_print,
rsa_opaque,
rsa_supports_digest,
@@ -726,13 +194,7 @@ const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = {
int_rsa_size,
rsa_bits,
- 0,0,0,0,
+ 0,0,0,
- rsa_sig_print,
int_rsa_free,
-
- old_rsa_priv_decode,
-
- rsa_digest_verify_init_from_algorithm,
- rsa_digest_sign_algorithm,
};
diff --git a/crypto/evp/pbkdf_test.cc b/crypto/evp/pbkdf_test.cc
index a6fe3dc1..438ab644 100644
--- a/crypto/evp/pbkdf_test.cc
+++ b/crypto/evp/pbkdf_test.cc
@@ -15,7 +15,6 @@
#include <stdio.h>
#include <string.h>
-#include <openssl/bio.h>
#include <openssl/crypto.h>
#include <openssl/digest.h>
#include <openssl/err.h>
diff --git a/crypto/evp/print.c b/crypto/evp/print.c
new file mode 100644
index 00000000..56521ec5
--- /dev/null
+++ b/crypto/evp/print.c
@@ -0,0 +1,527 @@
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/evp.h>
+
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/dsa.h>
+#include <openssl/ec.h>
+#include <openssl/ec_key.h>
+#include <openssl/mem.h>
+#include <openssl/rsa.h>
+
+#include "../rsa/internal.h"
+
+
+static int bn_print(BIO *bp, const char *number, const BIGNUM *num,
+ uint8_t *buf, int off) {
+ if (num == NULL) {
+ return 1;
+ }
+
+ if (!BIO_indent(bp, off, 128)) {
+ return 0;
+ }
+ if (BN_is_zero(num)) {
+ if (BIO_printf(bp, "%s 0\n", number) <= 0) {
+ return 0;
+ }
+ return 1;
+ }
+
+ if (BN_num_bytes(num) <= sizeof(long)) {
+ const char *neg = BN_is_negative(num) ? "-" : "";
+ if (BIO_printf(bp, "%s %s%lu (%s0x%lx)\n", number, neg,
+ (unsigned long)num->d[0], neg,
+ (unsigned long)num->d[0]) <= 0) {
+ return 0;
+ }
+ } else {
+ buf[0] = 0;
+ if (BIO_printf(bp, "%s%s", number,
+ (BN_is_negative(num)) ? " (Negative)" : "") <= 0) {
+ return 0;
+ }
+ int n = BN_bn2bin(num, &buf[1]);
+
+ if (buf[1] & 0x80) {
+ n++;
+ } else {
+ buf++;
+ }
+
+ int i;
+ for (i = 0; i < n; i++) {
+ if ((i % 15) == 0) {
+ if (BIO_puts(bp, "\n") <= 0 ||
+ !BIO_indent(bp, off + 4, 128)) {
+ return 0;
+ }
+ }
+ if (BIO_printf(bp, "%02x%s", buf[i], ((i + 1) == n) ? "" : ":") <= 0) {
+ return 0;
+ }
+ }
+ if (BIO_write(bp, "\n", 1) <= 0) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void update_buflen(const BIGNUM *b, size_t *pbuflen) {
+ size_t i;
+
+ if (!b) {
+ return;
+ }
+
+ i = BN_num_bytes(b);
+ if (*pbuflen < i) {
+ *pbuflen = i;
+ }
+}
+
+/* RSA keys. */
+
+static int do_rsa_print(BIO *out, const RSA *rsa, int off,
+ int include_private) {
+ const char *s, *str;
+ uint8_t *m = NULL;
+ int ret = 0, mod_len = 0;
+ size_t buf_len = 0;
+
+ update_buflen(rsa->n, &buf_len);
+ update_buflen(rsa->e, &buf_len);
+
+ if (include_private) {
+ update_buflen(rsa->d, &buf_len);
+ update_buflen(rsa->p, &buf_len);
+ update_buflen(rsa->q, &buf_len);
+ update_buflen(rsa->dmp1, &buf_len);
+ update_buflen(rsa->dmq1, &buf_len);
+ update_buflen(rsa->iqmp, &buf_len);
+
+ if (rsa->additional_primes != NULL) {
+ size_t i;
+
+ for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes);
+ i++) {
+ const RSA_additional_prime *ap =
+ sk_RSA_additional_prime_value(rsa->additional_primes, i);
+ update_buflen(ap->prime, &buf_len);
+ update_buflen(ap->exp, &buf_len);
+ update_buflen(ap->coeff, &buf_len);
+ }
+ }
+ }
+
+ m = (uint8_t *)OPENSSL_malloc(buf_len + 10);
+ if (m == NULL) {
+ OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (rsa->n != NULL) {
+ mod_len = BN_num_bits(rsa->n);
+ }
+
+ if (!BIO_indent(out, off, 128)) {
+ goto err;
+ }
+
+ if (include_private && rsa->d) {
+ if (BIO_printf(out, "Private-Key: (%d bit)\n", mod_len) <= 0) {
+ goto err;
+ }
+ str = "modulus:";
+ s = "publicExponent:";
+ } else {
+ if (BIO_printf(out, "Public-Key: (%d bit)\n", mod_len) <= 0) {
+ goto err;
+ }
+ str = "Modulus:";
+ s = "Exponent:";
+ }
+ if (!bn_print(out, str, rsa->n, m, off) ||
+ !bn_print(out, s, rsa->e, m, off)) {
+ goto err;
+ }
+
+ if (include_private) {
+ if (!bn_print(out, "privateExponent:", rsa->d, m, off) ||
+ !bn_print(out, "prime1:", rsa->p, m, off) ||
+ !bn_print(out, "prime2:", rsa->q, m, off) ||
+ !bn_print(out, "exponent1:", rsa->dmp1, m, off) ||
+ !bn_print(out, "exponent2:", rsa->dmq1, m, off) ||
+ !bn_print(out, "coefficient:", rsa->iqmp, m, off)) {
+ goto err;
+ }
+
+ if (rsa->additional_primes != NULL &&
+ sk_RSA_additional_prime_num(rsa->additional_primes) > 0) {
+ size_t i;
+
+ if (BIO_printf(out, "otherPrimeInfos:\n") <= 0) {
+ goto err;
+ }
+ for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes);
+ i++) {
+ const RSA_additional_prime *ap =
+ sk_RSA_additional_prime_value(rsa->additional_primes, i);
+
+ if (BIO_printf(out, "otherPrimeInfo (prime %u):\n",
+ (unsigned)(i + 3)) <= 0 ||
+ !bn_print(out, "prime:", ap->prime, m, off) ||
+ !bn_print(out, "exponent:", ap->exp, m, off) ||
+ !bn_print(out, "coeff:", ap->coeff, m, off)) {
+ goto err;
+ }
+ }
+ }
+ }
+ ret = 1;
+
+err:
+ OPENSSL_free(m);
+ return ret;
+}
+
+static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_rsa_print(bp, pkey->pkey.rsa, indent, 0);
+}
+
+static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_rsa_print(bp, pkey->pkey.rsa, indent, 1);
+}
+
+
+/* DSA keys. */
+
+static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype) {
+ uint8_t *m = NULL;
+ int ret = 0;
+ size_t buf_len = 0;
+ const char *ktype = NULL;
+
+ const BIGNUM *priv_key, *pub_key;
+
+ priv_key = NULL;
+ if (ptype == 2) {
+ priv_key = x->priv_key;
+ }
+
+ pub_key = NULL;
+ if (ptype > 0) {
+ pub_key = x->pub_key;
+ }
+
+ ktype = "DSA-Parameters";
+ if (ptype == 2) {
+ ktype = "Private-Key";
+ } else if (ptype == 1) {
+ ktype = "Public-Key";
+ }
+
+ update_buflen(x->p, &buf_len);
+ update_buflen(x->q, &buf_len);
+ update_buflen(x->g, &buf_len);
+ update_buflen(priv_key, &buf_len);
+ update_buflen(pub_key, &buf_len);
+
+ m = (uint8_t *)OPENSSL_malloc(buf_len + 10);
+ if (m == NULL) {
+ OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (priv_key) {
+ if (!BIO_indent(bp, off, 128) ||
+ BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0) {
+ goto err;
+ }
+ }
+
+ if (!bn_print(bp, "priv:", priv_key, m, off) ||
+ !bn_print(bp, "pub: ", pub_key, m, off) ||
+ !bn_print(bp, "P: ", x->p, m, off) ||
+ !bn_print(bp, "Q: ", x->q, m, off) ||
+ !bn_print(bp, "G: ", x->g, m, off)) {
+ goto err;
+ }
+ ret = 1;
+
+err:
+ OPENSSL_free(m);
+ return ret;
+}
+
+static int dsa_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_dsa_print(bp, pkey->pkey.dsa, indent, 0);
+}
+
+static int dsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_dsa_print(bp, pkey->pkey.dsa, indent, 1);
+}
+
+static int dsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_dsa_print(bp, pkey->pkey.dsa, indent, 2);
+}
+
+
+/* EC keys. */
+
+static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype) {
+ uint8_t *buffer = NULL;
+ const char *ecstr;
+ size_t buf_len = 0, i;
+ int ret = 0, reason = ERR_R_BIO_LIB;
+ BIGNUM *order = NULL;
+ BN_CTX *ctx = NULL;
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ const BIGNUM *priv_key;
+ uint8_t *pub_key_bytes = NULL;
+ size_t pub_key_bytes_len = 0;
+
+ if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) {
+ reason = ERR_R_PASSED_NULL_PARAMETER;
+ goto err;
+ }
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+
+ if (ktype > 0) {
+ public_key = EC_KEY_get0_public_key(x);
+ if (public_key != NULL) {
+ pub_key_bytes_len = EC_POINT_point2oct(
+ group, public_key, EC_KEY_get_conv_form(x), NULL, 0, ctx);
+ if (pub_key_bytes_len == 0) {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ pub_key_bytes = OPENSSL_malloc(pub_key_bytes_len);
+ if (pub_key_bytes == NULL) {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ pub_key_bytes_len =
+ EC_POINT_point2oct(group, public_key, EC_KEY_get_conv_form(x),
+ pub_key_bytes, pub_key_bytes_len, ctx);
+ if (pub_key_bytes_len == 0) {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ buf_len = pub_key_bytes_len;
+ }
+ }
+
+ if (ktype == 2) {
+ priv_key = EC_KEY_get0_private_key(x);
+ if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len) {
+ buf_len = i;
+ }
+ } else {
+ priv_key = NULL;
+ }
+
+ if (ktype > 0) {
+ buf_len += 10;
+ if ((buffer = OPENSSL_malloc(buf_len)) == NULL) {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ }
+ if (ktype == 2) {
+ ecstr = "Private-Key";
+ } else if (ktype == 1) {
+ ecstr = "Public-Key";
+ } else {
+ ecstr = "ECDSA-Parameters";
+ }
+
+ if (!BIO_indent(bp, off, 128)) {
+ goto err;
+ }
+ order = BN_new();
+ if (order == NULL || !EC_GROUP_get_order(group, order, NULL) ||
+ BIO_printf(bp, "%s: (%d bit)\n", ecstr, BN_num_bits(order)) <= 0) {
+ goto err;
+ }
+
+ if ((priv_key != NULL) &&
+ !bn_print(bp, "priv:", priv_key, buffer, off)) {
+ goto err;
+ }
+ if (pub_key_bytes != NULL) {
+ BIO_hexdump(bp, pub_key_bytes, pub_key_bytes_len, off);
+ }
+ /* TODO(fork): implement */
+ /*
+ if (!ECPKParameters_print(bp, group, off))
+ goto err; */
+ ret = 1;
+
+err:
+ if (!ret) {
+ OPENSSL_PUT_ERROR(EVP, reason);
+ }
+ OPENSSL_free(pub_key_bytes);
+ BN_free(order);
+ BN_CTX_free(ctx);
+ OPENSSL_free(buffer);
+ return ret;
+}
+
+static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0);
+}
+
+static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1);
+}
+
+
+static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2);
+}
+
+
+typedef struct {
+ int type;
+ int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx);
+ int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx);
+ int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx);
+} EVP_PKEY_PRINT_METHOD;
+
+static EVP_PKEY_PRINT_METHOD kPrintMethods[] = {
+ {
+ EVP_PKEY_RSA,
+ rsa_pub_print,
+ rsa_priv_print,
+ NULL /* param_print */,
+ },
+ {
+ EVP_PKEY_DSA,
+ dsa_pub_print,
+ dsa_priv_print,
+ dsa_param_print,
+ },
+ {
+ EVP_PKEY_EC,
+ eckey_pub_print,
+ eckey_priv_print,
+ eckey_param_print,
+ },
+};
+
+static size_t kPrintMethodsLen =
+ sizeof(kPrintMethods) / sizeof(kPrintMethods[0]);
+
+static EVP_PKEY_PRINT_METHOD *find_method(int type) {
+ size_t i;
+ for (i = 0; i < kPrintMethodsLen; i++) {
+ if (kPrintMethods[i].type == type) {
+ return &kPrintMethods[i];
+ }
+ }
+ return NULL;
+}
+
+static int print_unsupported(BIO *out, const EVP_PKEY *pkey, int indent,
+ const char *kstr) {
+ BIO_indent(out, indent, 128);
+ BIO_printf(out, "%s algorithm unsupported\n", kstr);
+ return 1;
+}
+
+int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx) {
+ EVP_PKEY_PRINT_METHOD *method = find_method(pkey->type);
+ if (method != NULL && method->pub_print != NULL) {
+ return method->pub_print(out, pkey, indent, pctx);
+ }
+ return print_unsupported(out, pkey, indent, "Public Key");
+}
+
+int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx) {
+ EVP_PKEY_PRINT_METHOD *method = find_method(pkey->type);
+ if (method != NULL && method->priv_print != NULL) {
+ return method->priv_print(out, pkey, indent, pctx);
+ }
+ return print_unsupported(out, pkey, indent, "Private Key");
+}
+
+int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx) {
+ EVP_PKEY_PRINT_METHOD *method = find_method(pkey->type);
+ if (method != NULL && method->param_print != NULL) {
+ return method->param_print(out, pkey, indent, pctx);
+ }
+ return print_unsupported(out, pkey, indent, "Parameters");
+}
diff --git a/crypto/ex_data.c b/crypto/ex_data.c
index 8fa12402..d67abba2 100644
--- a/crypto/ex_data.c
+++ b/crypto/ex_data.c
@@ -163,7 +163,7 @@ int CRYPTO_get_ex_new_index(CRYPTO_EX_DATA_CLASS *ex_data_class, int *out_index,
ret = 1;
err:
- CRYPTO_STATIC_MUTEX_unlock(&ex_data_class->lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&ex_data_class->lock);
return ret;
}
@@ -217,7 +217,7 @@ static int get_func_pointers(STACK_OF(CRYPTO_EX_DATA_FUNCS) **out,
if (n > 0) {
*out = sk_CRYPTO_EX_DATA_FUNCS_dup(ex_data_class->meth);
}
- CRYPTO_STATIC_MUTEX_unlock(&ex_data_class->lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&ex_data_class->lock);
if (n > 0 && *out == NULL) {
OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE);
diff --git a/crypto/hkdf/hkdf.c b/crypto/hkdf/hkdf.c
index f9cdcb0b..d80834d8 100644
--- a/crypto/hkdf/hkdf.c
+++ b/crypto/hkdf/hkdf.c
@@ -21,22 +21,50 @@
#include <openssl/hmac.h>
-int HKDF(uint8_t *out_key, size_t out_len,
- const EVP_MD *digest,
- const uint8_t *secret, size_t secret_len,
- const uint8_t *salt, size_t salt_len,
- const uint8_t *info, size_t info_len) {
+int HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest,
+ const uint8_t *secret, size_t secret_len, const uint8_t *salt,
+ size_t salt_len, const uint8_t *info, size_t info_len) {
+ /* https://tools.ietf.org/html/rfc5869#section-2 */
+ uint8_t prk[EVP_MAX_MD_SIZE];
+ size_t prk_len;
+
+ if (!HKDF_extract(prk, &prk_len, digest, secret, secret_len, salt,
+ salt_len) ||
+ !HKDF_expand(out_key, out_len, digest, prk, prk_len, info, info_len)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int HKDF_extract(uint8_t *out_key, size_t *out_len, const EVP_MD *digest,
+ const uint8_t *secret, size_t secret_len, const uint8_t *salt,
+ size_t salt_len) {
/* https://tools.ietf.org/html/rfc5869#section-2.2 */
+
+ /* If salt is not given, HashLength zeros are used. However, HMAC does that
+ * internally already so we can ignore it.*/
+ unsigned len;
+ if (HMAC(digest, salt, salt_len, secret, secret_len, out_key, &len) == NULL) {
+ OPENSSL_PUT_ERROR(HKDF, ERR_R_HMAC_LIB);
+ return 0;
+ }
+ *out_len = len;
+ assert(*out_len == EVP_MD_size(digest));
+ return 1;
+}
+
+int HKDF_expand(uint8_t *out_key, size_t out_len, const EVP_MD *digest,
+ uint8_t *prk, size_t prk_len, const uint8_t *info,
+ size_t info_len) {
+ /* https://tools.ietf.org/html/rfc5869#section-2.3 */
const size_t digest_len = EVP_MD_size(digest);
- uint8_t prk[EVP_MAX_MD_SIZE], previous[EVP_MAX_MD_SIZE];
+ uint8_t previous[EVP_MAX_MD_SIZE];
size_t n, done = 0;
- unsigned i, prk_len;
+ unsigned i;
int ret = 0;
HMAC_CTX hmac;
- /* If salt is not given, HashLength zeros are used. However, HMAC does that
- * internally already so we can ignore it.*/
-
/* Expand key material to desired length. */
n = (out_len + digest_len - 1) / digest_len;
if (out_len + digest_len < out_len || n > 255) {
@@ -45,13 +73,6 @@ int HKDF(uint8_t *out_key, size_t out_len,
}
HMAC_CTX_init(&hmac);
-
- /* Extract input keying material into pseudorandom key |prk|. */
- if (HMAC(digest, salt, salt_len, secret, secret_len, prk, &prk_len) == NULL) {
- goto out;
- }
- assert(prk_len == digest_len);
-
if (!HMAC_Init_ex(&hmac, prk, prk_len, digest, NULL)) {
goto out;
}
diff --git a/crypto/hkdf/hkdf_test.c b/crypto/hkdf/hkdf_test.c
index a4abf1c4..a0f75a96 100644
--- a/crypto/hkdf/hkdf_test.c
+++ b/crypto/hkdf/hkdf_test.c
@@ -20,6 +20,8 @@
#include <openssl/err.h>
#include <openssl/hkdf.h>
+#include "../test/test_util.h"
+
typedef struct {
const EVP_MD *(*md_func)(void);
@@ -29,6 +31,8 @@ typedef struct {
const size_t salt_len;
const uint8_t info[80];
const size_t info_len;
+ const uint8_t prk[EVP_MAX_MD_SIZE];
+ const size_t prk_len;
const size_t out_len;
const uint8_t out[82];
} hkdf_test_vector_t;
@@ -48,6 +52,11 @@ static const hkdf_test_vector_t kTests[] = {
{
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
}, 10,
+ {
+ 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, 0x0d, 0xdc, 0x3f, 0x0d,
+ 0xc4, 0x7b, 0xba, 0x63, 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31,
+ 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5,
+ }, 32,
42, {
0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64,
0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
@@ -84,6 +93,11 @@ static const hkdf_test_vector_t kTests[] = {
0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
}, 80,
+ {
+ 0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a, 0x06, 0x10, 0x4c, 0x9c,
+ 0xeb, 0x35, 0xb4, 0x5c, 0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01,
+ 0x4a, 0x19, 0x3f, 0x40, 0xc1, 0x5f, 0xc2, 0x44,
+ }, 32,
82, {
0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c,
0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8,
@@ -106,6 +120,11 @@ static const hkdf_test_vector_t kTests[] = {
{
0,
}, 0,
+ {
+ 0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16, 0x7f, 0x33, 0xa9, 0x1d,
+ 0x6f, 0x64, 0x8b, 0xdf, 0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77,
+ 0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04
+ }, 32,
42, {
0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80, 0x2a,
0x06, 0x3c, 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e,
@@ -125,6 +144,10 @@ static const hkdf_test_vector_t kTests[] = {
{
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
}, 10,
+ {
+ 0x9b, 0x6c, 0x18, 0xc4, 0x32, 0xa7, 0xbf, 0x8f, 0x0e, 0x71, 0xc8, 0xeb,
+ 0x88, 0xf4, 0xb3, 0x0b, 0xaa, 0x2b, 0xa2, 0x43
+ }, 20,
42, {
0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69, 0x33, 0x06, 0x8b, 0x56,
0xef, 0xa5, 0xad, 0x81, 0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15,
@@ -161,6 +184,10 @@ static const hkdf_test_vector_t kTests[] = {
0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
}, 80,
+ {
+ 0x8a, 0xda, 0xe0, 0x9a, 0x2a, 0x30, 0x70, 0x59, 0x47, 0x8d, 0x30, 0x9b,
+ 0x26, 0xc4, 0x11, 0x5a, 0x22, 0x4c, 0xfa, 0xf6,
+ }, 20,
82, {
0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1, 0x2c, 0xd5,
0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19,
@@ -183,6 +210,10 @@ static const hkdf_test_vector_t kTests[] = {
{
0,
}, 0,
+ {
+ 0xda, 0x8c, 0x8a, 0x73, 0xc7, 0xfa, 0x77, 0x28, 0x8e, 0xc6, 0xf5, 0xe7,
+ 0xc2, 0x97, 0x78, 0x6a, 0xa0, 0xd3, 0x2d, 0x01,
+ }, 20,
42, {
0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, 0xd1, 0xe5, 0x52, 0x98,
0xda, 0x9d, 0x05, 0x06, 0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, 0xa3, 0x06,
@@ -202,6 +233,10 @@ static const hkdf_test_vector_t kTests[] = {
{
0,
}, 0,
+ {
+ 0x2a, 0xdc, 0xca, 0xda, 0x18, 0x77, 0x9e, 0x7c, 0x20, 0x77, 0xad, 0x2e,
+ 0xb1, 0x9d, 0x3f, 0x3e, 0x73, 0x13, 0x85, 0xdd,
+ }, 20,
42, {
0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3, 0x50, 0x0d, 0x63, 0x6a,
0x62, 0xf6, 0x4f, 0x0a, 0xb3, 0xba, 0xe5, 0x48, 0xaa, 0x53, 0xd4, 0x23,
@@ -212,13 +247,36 @@ static const hkdf_test_vector_t kTests[] = {
};
int main(void) {
- uint8_t buf[82];
- size_t i;
+ uint8_t buf[82], prk[EVP_MAX_MD_SIZE];
+ size_t i, prk_len;
CRYPTO_library_init();
for (i = 0; i < sizeof(kTests) / sizeof(kTests[0]); i++) {
const hkdf_test_vector_t *test = &kTests[i];
+ if (!HKDF_extract(prk, &prk_len, test->md_func(), test->ikm, test->ikm_len,
+ test->salt, test->salt_len)) {
+ fprintf(stderr, "Call to HKDF_extract failed\n");
+ ERR_print_errors_fp(stderr);
+ return 1;
+ }
+ if (prk_len != test->prk_len ||
+ memcmp(prk, test->prk, test->prk_len) != 0) {
+ fprintf(stderr, "%zu: Resulting PRK does not match test vector\n", i);
+ return 1;
+ }
+ if (!HKDF_expand(buf, test->out_len, test->md_func(), prk, prk_len,
+ test->info, test->info_len)) {
+ fprintf(stderr, "Call to HKDF_expand failed\n");
+ ERR_print_errors_fp(stderr);
+ return 1;
+ }
+ if (memcmp(buf, test->out, test->out_len) != 0) {
+ fprintf(stderr,
+ "%zu: Resulting key material does not match test vector\n", i);
+ return 1;
+ }
+
if (!HKDF(buf, test->out_len, test->md_func(), test->ikm, test->ikm_len,
test->salt, test->salt_len, test->info, test->info_len)) {
fprintf(stderr, "Call to HKDF failed\n");
@@ -226,8 +284,8 @@ int main(void) {
return 1;
}
if (memcmp(buf, test->out, test->out_len) != 0) {
- fprintf(stderr, "%u: Resulting key material does not match test vector\n",
- (unsigned)i);
+ fprintf(stderr,
+ "%zu: Resulting key material does not match test vector\n", i);
return 1;
}
}
diff --git a/crypto/hmac/hmac.c b/crypto/hmac/hmac.c
index be2dccec..bccc5c02 100644
--- a/crypto/hmac/hmac.c
+++ b/crypto/hmac/hmac.c
@@ -59,6 +59,7 @@
#include <assert.h>
#include <string.h>
+#include <openssl/digest.h>
#include <openssl/mem.h>
@@ -115,8 +116,8 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len,
* case. Fix to API to avoid this. */
if (md != ctx->md || key != NULL) {
size_t i;
- uint8_t pad[HMAC_MAX_MD_CBLOCK];
- uint8_t key_block[HMAC_MAX_MD_CBLOCK];
+ uint8_t pad[EVP_MAX_MD_BLOCK_SIZE];
+ uint8_t key_block[EVP_MAX_MD_BLOCK_SIZE];
unsigned key_block_len;
size_t block_size = EVP_MD_block_size(md);
@@ -134,11 +135,11 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len,
key_block_len = (unsigned)key_len;
}
/* Keys are then padded with zeros. */
- if (key_block_len != HMAC_MAX_MD_CBLOCK) {
+ if (key_block_len != EVP_MAX_MD_BLOCK_SIZE) {
memset(&key_block[key_block_len], 0, sizeof(key_block) - key_block_len);
}
- for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++) {
+ for (i = 0; i < EVP_MAX_MD_BLOCK_SIZE; i++) {
pad[i] = 0x36 ^ key_block[i];
}
if (!EVP_DigestInit_ex(&ctx->i_ctx, md, impl) ||
@@ -146,7 +147,7 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len,
return 0;
}
- for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++) {
+ for (i = 0; i < EVP_MAX_MD_BLOCK_SIZE; i++) {
pad[i] = 0x5c ^ key_block[i];
}
if (!EVP_DigestInit_ex(&ctx->o_ctx, md, impl) ||
diff --git a/crypto/internal.h b/crypto/internal.h
index 2229e19e..e35fb7bd 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -123,9 +123,9 @@
#if defined(OPENSSL_NO_THREADS)
#elif defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#else
#include <pthread.h>
#endif
@@ -135,48 +135,6 @@ extern "C" {
#endif
-/* MSVC's C4701 warning about the use of *potentially*--as opposed to
- * *definitely*--uninitialized values sometimes has false positives. Usually
- * the false positives can and should be worked around by simplifying the
- * control flow. When that is not practical, annotate the function containing
- * the code that triggers the warning with
- * OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS after its parameters:
- *
- * void f() OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS {
- * ...
- * }
- *
- * Note that MSVC's control flow analysis seems to operate on a whole-function
- * basis, so the annotation must be placed on the entire function, not just a
- * block within the function. */
-#if defined(_MSC_VER)
-#define OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS \
- __pragma(warning(suppress:4701))
-#else
-#define OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS
-#endif
-
-/* MSVC will sometimes correctly detect unreachable code and issue a warning,
- * which breaks the build since we treat errors as warnings, in some rare cases
- * where we want to allow the dead code to continue to exist. In these
- * situations, annotate the function containing the unreachable code with
- * OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS after its parameters:
- *
- * void f() OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS {
- * ...
- * }
- *
- * Note that MSVC's reachability analysis seems to operate on a whole-function
- * basis, so the annotation must be placed on the entire function, not just a
- * block within the function. */
-#if defined(_MSC_VER)
-#define OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS \
- __pragma(warning(suppress:4702))
-#else
-#define OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS
-#endif
-
-
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) || \
defined(OPENSSL_AARCH64)
/* OPENSSL_cpuid_setup initializes OPENSSL_ia32cap_P. */
@@ -194,6 +152,19 @@ typedef __uint128_t uint128_t;
#endif
+/* buffers_alias returns one if |a| and |b| alias and zero otherwise. */
+static inline int buffers_alias(const uint8_t *a, size_t a_len,
+ const uint8_t *b, size_t b_len) {
+ /* Cast |a| and |b| to integers. In C, pointer comparisons between unrelated
+ * objects are undefined whereas pointer to integer conversions are merely
+ * implementation-defined. We assume the implementation defined it in a sane
+ * way. */
+ uintptr_t a_u = (uintptr_t)a;
+ uintptr_t b_u = (uintptr_t)b;
+ return a_u + a_len > b_u && b_u + b_len > a_u;
+}
+
+
/* Constant-time utility functions.
*
* The following methods return a bitmask of all ones (0xff...f) for true and 0
@@ -336,12 +307,22 @@ static inline int constant_time_select_int(unsigned int mask, int a, int b) {
/* Thread-safe initialisation. */
+/* Android's mingw-w64 has some prototypes for INIT_ONCE, but is missing
+ * others. Work around the missing ones.
+ *
+ * TODO(davidben): Remove this once Android's mingw-w64 is upgraded. See
+ * b/26523949. */
+#if defined(__MINGW32__) && !defined(INIT_ONCE_STATIC_INIT)
+typedef RTL_RUN_ONCE INIT_ONCE;
+#define INIT_ONCE_STATIC_INIT RTL_RUN_ONCE_INIT
+#endif
+
#if defined(OPENSSL_NO_THREADS)
typedef uint32_t CRYPTO_once_t;
#define CRYPTO_ONCE_INIT 0
#elif defined(OPENSSL_WINDOWS)
-typedef volatile LONG CRYPTO_once_t;
-#define CRYPTO_ONCE_INIT 0
+typedef INIT_ONCE CRYPTO_once_t;
+#define CRYPTO_ONCE_INIT INIT_ONCE_STATIC_INIT
#else
typedef pthread_once_t CRYPTO_once_t;
#define CRYPTO_ONCE_INIT PTHREAD_ONCE_INIT
@@ -387,22 +368,19 @@ OPENSSL_EXPORT int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count);
* |CRYPTO_STATIC_MUTEX_INIT|.
*
* |CRYPTO_MUTEX| can appear in public structures and so is defined in
- * thread.h.
- *
- * The global lock is a different type because there's no static initialiser
- * value on Windows for locks, so global locks have to be coupled with a
- * |CRYPTO_once_t| to ensure that the lock is setup before use. This is done
- * automatically by |CRYPTO_STATIC_MUTEX_lock_*|. */
+ * thread.h as a structure large enough to fit the real type. The global lock is
+ * a different type so it may be initialized with platform initializer macros.*/
#if defined(OPENSSL_NO_THREADS)
-struct CRYPTO_STATIC_MUTEX {};
-#define CRYPTO_STATIC_MUTEX_INIT {}
+struct CRYPTO_STATIC_MUTEX {
+ char padding; /* Empty structs have different sizes in C and C++. */
+};
+#define CRYPTO_STATIC_MUTEX_INIT { 0 }
#elif defined(OPENSSL_WINDOWS)
struct CRYPTO_STATIC_MUTEX {
- CRYPTO_once_t once;
- CRITICAL_SECTION lock;
+ SRWLOCK lock;
};
-#define CRYPTO_STATIC_MUTEX_INIT { CRYPTO_ONCE_INIT, { 0 } }
+#define CRYPTO_STATIC_MUTEX_INIT { SRWLOCK_INIT }
#else
struct CRYPTO_STATIC_MUTEX {
pthread_rwlock_t lock;
@@ -415,16 +393,18 @@ struct CRYPTO_STATIC_MUTEX {
OPENSSL_EXPORT void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock);
/* CRYPTO_MUTEX_lock_read locks |lock| such that other threads may also have a
- * read lock, but none may have a write lock. (On Windows, read locks are
- * actually fully exclusive.) */
+ * read lock, but none may have a write lock. */
OPENSSL_EXPORT void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock);
/* CRYPTO_MUTEX_lock_write locks |lock| such that no other thread has any type
* of lock on it. */
OPENSSL_EXPORT void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock);
-/* CRYPTO_MUTEX_unlock unlocks |lock|. */
-OPENSSL_EXPORT void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock);
+/* CRYPTO_MUTEX_unlock_read unlocks |lock| for reading. */
+OPENSSL_EXPORT void CRYPTO_MUTEX_unlock_read(CRYPTO_MUTEX *lock);
+
+/* CRYPTO_MUTEX_unlock_write unlocks |lock| for writing. */
+OPENSSL_EXPORT void CRYPTO_MUTEX_unlock_write(CRYPTO_MUTEX *lock);
/* CRYPTO_MUTEX_cleanup releases all resources held by |lock|. */
OPENSSL_EXPORT void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock);
@@ -443,8 +423,12 @@ OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_lock_read(
OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_lock_write(
struct CRYPTO_STATIC_MUTEX *lock);
-/* CRYPTO_STATIC_MUTEX_unlock unlocks |lock|. */
-OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_unlock(
+/* CRYPTO_STATIC_MUTEX_unlock_read unlocks |lock| for reading. */
+OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_unlock_read(
+ struct CRYPTO_STATIC_MUTEX *lock);
+
+/* CRYPTO_STATIC_MUTEX_unlock_write unlocks |lock| for writing. */
+OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_unlock_write(
struct CRYPTO_STATIC_MUTEX *lock);
diff --git a/crypto/lhash/lhash_test.c b/crypto/lhash/lhash_test.c
index 63748e73..309b765d 100644
--- a/crypto/lhash/lhash_test.c
+++ b/crypto/lhash/lhash_test.c
@@ -152,7 +152,11 @@ int main(int argc, char **argv) {
case 1:
s = rand_string();
lh_insert(lh, (void **)&s1, s);
+#if defined(OPENSSL_WINDOWS)
+ dummy_lh_insert(&dummy_lh, &s2, _strdup(s));
+#else
dummy_lh_insert(&dummy_lh, &s2, strdup(s));
+#endif
if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) {
fprintf(stderr, "lh_insert failure\n");
diff --git a/crypto/md4/md4.c b/crypto/md4/md4.c
index 86a540b4..f79da9fd 100644
--- a/crypto/md4/md4.c
+++ b/crypto/md4/md4.c
@@ -60,6 +60,15 @@
#include <string.h>
+uint8_t *MD4(const uint8_t *data, size_t len, uint8_t *out) {
+ MD4_CTX ctx;
+ MD4_Init(&ctx);
+ MD4_Update(&ctx, data, len);
+ MD4_Final(out, &ctx);
+
+ return out;
+}
+
/* Implemented from RFC1186 The MD4 Message-Digest Algorithm. */
int MD4_Init(MD4_CTX *md4) {
diff --git a/crypto/mem.c b/crypto/mem.c
index df8e0e33..527edd93 100644
--- a/crypto/mem.c
+++ b/crypto/mem.c
@@ -66,9 +66,17 @@
#include <string.h>
#if defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+
+/* Work around a clang-cl bug: SecureZeroMemory() below uses __stosb() but
+ * windows.h only declares that intrinsic and then uses `#pragma intrinsic` for
+ * it. clang-cl doesn't implement `#pragma intrinsic` yet; it instead defines
+ * the function as an always-inline symbol in its intrin.h.
+ * TODO(thakis): Remove this once http://llvm.org/PR19898 is fixed.
+ */
+#include <intrin.h>
+OPENSSL_MSVC_PRAGMA(warning(pop))
#else
#include <strings.h>
#endif
@@ -118,12 +126,11 @@ void OPENSSL_cleanse(void *ptr, size_t len) {
}
int CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len) {
- size_t i;
const uint8_t *a = in_a;
const uint8_t *b = in_b;
uint8_t x = 0;
- for (i = 0; i < len; i++) {
+ for (size_t i = 0; i < len; i++) {
x |= a[i] ^ b[i];
}
@@ -147,8 +154,6 @@ uint32_t OPENSSL_hash32(const void *ptr, size_t len) {
return h;
}
-char *OPENSSL_strdup(const char *s) { return strdup(s); }
-
size_t OPENSSL_strnlen(const char *s, size_t len) {
size_t i;
@@ -163,6 +168,8 @@ size_t OPENSSL_strnlen(const char *s, size_t len) {
#if defined(OPENSSL_WINDOWS)
+char *OPENSSL_strdup(const char *s) { return _strdup(s); }
+
int OPENSSL_strcasecmp(const char *a, const char *b) {
return _stricmp(a, b);
}
@@ -173,6 +180,8 @@ int OPENSSL_strncasecmp(const char *a, const char *b, size_t n) {
#else
+char *OPENSSL_strdup(const char *s) { return strdup(s); }
+
int OPENSSL_strcasecmp(const char *a, const char *b) {
return strcasecmp(a, b);
}
diff --git a/crypto/modes/asm/aesni-gcm-x86_64.pl b/crypto/modes/asm/aesni-gcm-x86_64.pl
index 26135e6c..5d58bbbb 100644
--- a/crypto/modes/asm/aesni-gcm-x86_64.pl
+++ b/crypto/modes/asm/aesni-gcm-x86_64.pl
@@ -41,11 +41,12 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
+# This must be kept in sync with |$avx| in ghash-x86_64.pl; otherwise tags will
+# be computed incorrectly.
+#
# In upstream, this is controlled by shelling out to the compiler to check
# versions, but BoringSSL is intended to be used with pre-generated perlasm
# output, so this isn't useful anyway.
-#
-# TODO(davidben): Enable this after testing. $avx goes up to 2.
$avx = 0;
open OUT,"| \"$^X\" $xlate $flavour $output";
@@ -96,6 +97,23 @@ _aesni_ctr32_ghash_6x:
vpxor $rndkey,$inout3,$inout3
vmovups 0x10-0x80($key),$T2 # borrow $T2 for $rndkey
vpclmulqdq \$0x01,$Hkey,$Z3,$Z2
+
+ # At this point, the current block of 96 (0x60) bytes has already been
+ # loaded into registers. Concurrently with processing it, we want to
+ # load the next 96 bytes of input for the next round. Obviously, we can
+ # only do this if there are at least 96 more bytes of input beyond the
+ # input we're currently processing, or else we'd read past the end of
+ # the input buffer. Here, we set |%r12| to 96 if there are at least 96
+ # bytes of input beyond the 96 bytes we're already processing, and we
+ # set |%r12| to 0 otherwise. In the case where we set |%r12| to 96,
+ # we'll read in the next block so that it is in registers for the next
+ # loop iteration. In the case where we set |%r12| to 0, we'll re-read
+ # the current block and then ignore what we re-read.
+ #
+ # At this point, |$in0| points to the current (already read into
+ # registers) block, and |$end0| points to 2*96 bytes before the end of
+ # the input. Thus, |$in0| > |$end0| means that we do not have the next
+ # 96-byte block to read in, and |$in0| <= |$end0| means we do.
xor %r12,%r12
cmp $in0,$end0
@@ -388,6 +406,9 @@ $code.=<<___;
.align 32
aesni_gcm_decrypt:
xor $ret,$ret
+
+ # We call |_aesni_ctr32_ghash_6x|, which requires at least 96 (0x60)
+ # bytes of input.
cmp \$0x60,$len # minimal accepted length
jb .Lgcm_dec_abort
@@ -442,7 +463,15 @@ $code.=<<___;
vmovdqu 0x50($inp),$Z3 # I[5]
lea ($inp),$in0
vmovdqu 0x40($inp),$Z0
+
+ # |_aesni_ctr32_ghash_6x| requires |$end0| to point to 2*96 (0xc0)
+ # bytes before the end of the input. Note, in particular, that this is
+ # correct even if |$len| is not an even multiple of 96 or 16. XXX: This
+ # seems to require that |$inp| + |$len| >= 2*96 (0xc0); i.e. |$inp| must
+ # not be near the very beginning of the address space when |$len| < 2*96
+ # (0xc0).
lea -0xc0($inp,$len),$end0
+
vmovdqu 0x30($inp),$Z1
shr \$4,$len
xor $ret,$ret
@@ -598,6 +627,10 @@ _aesni_ctr32_6x:
.align 32
aesni_gcm_encrypt:
xor $ret,$ret
+
+ # We call |_aesni_ctr32_6x| twice, each call consuming 96 bytes of
+ # input. Then we call |_aesni_ctr32_ghash_6x|, which requires at
+ # least 96 more bytes of input.
cmp \$0x60*3,$len # minimal accepted length
jb .Lgcm_enc_abort
@@ -647,7 +680,16 @@ $code.=<<___;
.Lenc_no_key_aliasing:
lea ($out),$in0
+
+ # |_aesni_ctr32_ghash_6x| requires |$end0| to point to 2*96 (0xc0)
+ # bytes before the end of the input. Note, in particular, that this is
+ # correct even if |$len| is not an even multiple of 96 or 16. Unlike in
+ # the decryption case, there's no caveat that |$out| must not be near
+ # the very beginning of the address space, because we know that
+ # |$len| >= 3*96 from the check above, and so we know
+ # |$out| + |$len| >= 2*96 (0xc0).
lea -0xc0($out,$len),$end0
+
shr \$4,$len
call _aesni_ctr32_6x
diff --git a/crypto/modes/asm/ghash-x86_64.pl b/crypto/modes/asm/ghash-x86_64.pl
index e42ca321..5a11fb94 100644
--- a/crypto/modes/asm/ghash-x86_64.pl
+++ b/crypto/modes/asm/ghash-x86_64.pl
@@ -90,11 +90,12 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
+# This must be kept in sync with |$avx| in aesni-gcm-x86_64.pl; otherwise tags
+# will be computed incorrectly.
+#
# In upstream, this is controlled by shelling out to the compiler to check
# versions, but BoringSSL is intended to be used with pre-generated perlasm
# output, so this isn't useful anyway.
-#
-# TODO(davidben): Enable this after testing. $avx goes up to 2.
$avx = 0;
open OUT,"| \"$^X\" $xlate $flavour $output";
diff --git a/crypto/modes/cfb.c b/crypto/modes/cfb.c
index c58614ba..51b883e8 100644
--- a/crypto/modes/cfb.c
+++ b/crypto/modes/cfb.c
@@ -57,14 +57,13 @@
OPENSSL_COMPILE_ASSERT((16 % sizeof(size_t)) == 0, bad_size_t_size);
void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
- const void *key, uint8_t ivec[16], int *num, int enc,
- block128_f block) {
- unsigned int n;
+ const void *key, uint8_t ivec[16], unsigned *num,
+ int enc, block128_f block) {
size_t l = 0;
assert(in && out && key && ivec && num);
- n = *num;
+ unsigned n = *num;
if (enc) {
while (n && len) {
@@ -199,7 +198,7 @@ static void cfbr_encrypt_block(const uint8_t *in, uint8_t *out, unsigned nbits,
/* N.B. This expects the input to be packed, MS bit first */
void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits,
- const void *key, uint8_t ivec[16], int *num,
+ const void *key, uint8_t ivec[16], unsigned *num,
int enc, block128_f block) {
size_t n;
uint8_t c[1], d[1];
@@ -217,7 +216,7 @@ void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits,
void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out,
size_t length, const void *key,
- unsigned char ivec[16], int *num, int enc,
+ unsigned char ivec[16], unsigned *num, int enc,
block128_f block) {
size_t n;
diff --git a/crypto/modes/ctr.c b/crypto/modes/ctr.c
index 0baed5d4..b84e72c5 100644
--- a/crypto/modes/ctr.c
+++ b/crypto/modes/ctr.c
@@ -59,17 +59,13 @@
/* increment counter (128-bit int) by 1 */
static void ctr128_inc(uint8_t *counter) {
- uint32_t n = 16;
- uint8_t c;
+ uint32_t n = 16, c = 1;
do {
--n;
- c = counter[n];
- ++c;
- counter[n] = c;
- if (c) {
- return;
- }
+ c += counter[n];
+ counter[n] = (uint8_t) c;
+ c >>= 8;
} while (n);
}
@@ -104,7 +100,7 @@ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
}
#if STRICT_ALIGNMENT
- if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+ if (((size_t)in | (size_t)out | (size_t)ecount_buf) % sizeof(size_t) != 0) {
size_t l = 0;
while (l < len) {
if (n == 0) {
@@ -124,7 +120,7 @@ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
while (len >= 16) {
(*block)(ivec, ecount_buf, key);
ctr128_inc(ivec);
- for (; n < 16; n += sizeof(size_t)) {
+ for (n = 0; n < 16; n += sizeof(size_t)) {
*(size_t *)(out + n) = *(const size_t *)(in + n) ^
*(const size_t *)(ecount_buf + n);
}
@@ -146,17 +142,13 @@ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
/* increment upper 96 bits of 128-bit counter by 1 */
static void ctr96_inc(uint8_t *counter) {
- uint32_t n = 12;
- uint8_t c;
+ uint32_t n = 12, c = 1;
do {
--n;
- c = counter[n];
- ++c;
- counter[n] = c;
- if (c) {
- return;
- }
+ c += counter[n];
+ counter[n] = (uint8_t) c;
+ c >>= 8;
} while (n);
}
diff --git a/crypto/modes/gcm.c b/crypto/modes/gcm.c
index 8cc138dc..b8571313 100644
--- a/crypto/modes/gcm.c
+++ b/crypto/modes/gcm.c
@@ -55,6 +55,7 @@
#include <openssl/cpu.h>
#include "internal.h"
+#include "../internal.h"
#if !defined(OPENSSL_NO_ASM) && \
@@ -337,7 +338,18 @@ void gcm_ghash_clmul(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
#else
void gcm_init_avx(u128 Htable[16], const uint64_t Xi[2]);
void gcm_gmult_avx(uint64_t Xi[2], const u128 Htable[16]);
-void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, size_t len);
+void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *in,
+ size_t len);
+#define AESNI_GCM
+static int aesni_gcm_enabled(GCM128_CONTEXT *ctx, ctr128_f stream) {
+ return stream == aesni_ctr32_encrypt_blocks &&
+ ctx->ghash == gcm_ghash_avx;
+}
+
+size_t aesni_gcm_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], uint64_t *Xi);
+size_t aesni_gcm_decrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], uint64_t *Xi);
#endif
#if defined(OPENSSL_X86)
@@ -380,14 +392,14 @@ void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
static int neon_capable(void) {
return 0;
}
-void gcm_init_neon(u128 Htable[16], const uint64_t Xi[2]) {
+static void gcm_init_neon(u128 Htable[16], const uint64_t Xi[2]) {
abort();
}
-void gcm_gmult_neon(uint64_t Xi[2], const u128 Htable[16]) {
+static void gcm_gmult_neon(uint64_t Xi[2], const u128 Htable[16]) {
abort();
}
-void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
- size_t len) {
+static void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16],
+ const uint8_t *inp, size_t len) {
abort();
}
#endif
@@ -405,17 +417,6 @@ void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
#endif
#endif
-GCM128_CONTEXT *CRYPTO_gcm128_new(const void *key, block128_f block) {
- GCM128_CONTEXT *ret;
-
- ret = OPENSSL_malloc(sizeof(GCM128_CONTEXT));
- if (ret != NULL) {
- CRYPTO_gcm128_init(ret, key, block);
- }
-
- return ret;
-}
-
void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, const void *key,
block128_f block) {
const union {
@@ -991,12 +992,6 @@ int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key,
ctx->ares = 0;
}
- if (is_endian.little) {
- ctr = GETU32(ctx->Yi.c + 12);
- } else {
- ctr = ctx->Yi.d[3];
- }
-
n = ctx->mres;
if (n) {
while (n && len) {
@@ -1011,6 +1006,24 @@ int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key,
return 1;
}
}
+
+#if defined(AESNI_GCM)
+ if (aesni_gcm_enabled(ctx, stream)) {
+ /* |aesni_gcm_encrypt| may not process all the input given to it. It may
+ * not process *any* of its input if it is deemed too small. */
+ size_t bulk = aesni_gcm_encrypt(in, out, len, key, ctx->Yi.c, ctx->Xi.u);
+ in += bulk;
+ out += bulk;
+ len -= bulk;
+ }
+#endif
+
+ if (is_endian.little) {
+ ctr = GETU32(ctx->Yi.c + 12);
+ } else {
+ ctr = ctx->Yi.d[3];
+ }
+
#if defined(GHASH)
while (len >= GHASH_CHUNK) {
(*stream)(in, out, GHASH_CHUNK / 16, key, ctx->Yi.c);
@@ -1100,12 +1113,6 @@ int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key,
ctx->ares = 0;
}
- if (is_endian.little) {
- ctr = GETU32(ctx->Yi.c + 12);
- } else {
- ctr = ctx->Yi.d[3];
- }
-
n = ctx->mres;
if (n) {
while (n && len) {
@@ -1122,6 +1129,24 @@ int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key,
return 1;
}
}
+
+#if defined(AESNI_GCM)
+ if (aesni_gcm_enabled(ctx, stream)) {
+ /* |aesni_gcm_decrypt| may not process all the input given to it. It may
+ * not process *any* of its input if it is deemed too small. */
+ size_t bulk = aesni_gcm_decrypt(in, out, len, key, ctx->Yi.c, ctx->Xi.u);
+ in += bulk;
+ out += bulk;
+ len -= bulk;
+ }
+#endif
+
+ if (is_endian.little) {
+ ctr = GETU32(ctx->Yi.c + 12);
+ } else {
+ ctr = ctx->Yi.d[3];
+ }
+
#if defined(GHASH)
while (len >= GHASH_CHUNK) {
GHASH(ctx, in, GHASH_CHUNK);
@@ -1235,13 +1260,6 @@ void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, unsigned char *tag, size_t len) {
memcpy(tag, ctx->Xi.c, len <= sizeof(ctx->Xi.c) ? len : sizeof(ctx->Xi.c));
}
-void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx) {
- if (ctx) {
- OPENSSL_cleanse(ctx, sizeof(*ctx));
- OPENSSL_free(ctx);
- }
-}
-
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
int crypto_gcm_clmul_enabled(void) {
#ifdef GHASH_ASM
diff --git a/crypto/modes/gcm_test.c b/crypto/modes/gcm_test.c
index 9414ac6e..19c295b5 100644
--- a/crypto/modes/gcm_test.c
+++ b/crypto/modes/gcm_test.c
@@ -282,8 +282,8 @@ static int decode_hex(uint8_t **out, size_t *out_len, const char *in,
uint8_t v, v2;
if (!from_hex(&v, in[i]) ||
!from_hex(&v2, in[i+1])) {
- fprintf(stderr, "%u: invalid hex digit in %s around offset %u.\n",
- test_num, description, (unsigned)i);
+ fprintf(stderr, "%u: invalid hex digit in %s around offset %zu.\n",
+ test_num, description, i);
goto err;
}
buf[i/2] = (v << 4) | v2;
@@ -336,7 +336,7 @@ static int run_test_case(unsigned test_num, const struct test_case *test) {
}
out = OPENSSL_malloc(plaintext_len);
- if (out == NULL) {
+ if (plaintext_len != 0 && out == NULL) {
goto out;
}
if (AES_set_encrypt_key(key, key_len*8, &aes_key)) {
diff --git a/crypto/modes/internal.h b/crypto/modes/internal.h
index 7255a7ca..430d0401 100644
--- a/crypto/modes/internal.h
+++ b/crypto/modes/internal.h
@@ -121,9 +121,9 @@ extern "C" {
#endif
#elif defined(_MSC_VER)
#if _MSC_VER >= 1300
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <intrin.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma intrinsic(_byteswap_uint64, _byteswap_ulong)
#define BSWAP8(x) _byteswap_uint64((uint64_t)(x))
#define BSWAP4(x) _byteswap_ulong((uint32_t)(x))
@@ -179,16 +179,6 @@ struct gcm128_context {
block128_f block;
};
-struct ccm128_context {
- union {
- uint64_t u[2];
- uint8_t c[16];
- } nonce, cmac;
- uint64_t blocks;
- block128_f block;
- void *key;
-};
-
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
/* crypto_gcm_clmul_enabled returns one if the CLMUL implementation of GCM is
* used. */
@@ -210,7 +200,7 @@ typedef void (*ctr128_f)(const uint8_t *in, uint8_t *out, size_t blocks,
* incremented by this function. */
void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
const void *key, uint8_t ivec[16],
- uint8_t ecount_buf[16], unsigned int *num,
+ uint8_t ecount_buf[16], unsigned *num,
block128_f block);
/* CRYPTO_ctr128_encrypt_ctr32 acts like |CRYPTO_ctr128_encrypt| but takes
@@ -219,7 +209,7 @@ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
* function. */
void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, size_t len,
const void *key, uint8_t ivec[16],
- uint8_t ecount_buf[16], unsigned int *num,
+ uint8_t ecount_buf[16], unsigned *num,
ctr128_f ctr);
@@ -232,11 +222,6 @@ void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, size_t len,
typedef struct gcm128_context GCM128_CONTEXT;
-/* CRYPTO_gcm128_new allocates a fresh |GCM128_CONTEXT| and calls
- * |CRYPTO_gcm128_init|. It returns the new context, or NULL on error. */
-OPENSSL_EXPORT GCM128_CONTEXT *CRYPTO_gcm128_new(const void *key,
- block128_f block);
-
/* CRYPTO_gcm128_init initialises |ctx| to use |block| (typically AES) with
* the given key. */
OPENSSL_EXPORT void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, const void *key,
@@ -297,9 +282,6 @@ OPENSSL_EXPORT int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag,
OPENSSL_EXPORT void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, uint8_t *tag,
size_t len);
-/* CRYPTO_gcm128_release clears and frees |ctx|. */
-OPENSSL_EXPORT void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx);
-
/* CBC. */
@@ -331,7 +313,7 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
* call. */
void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out,
size_t len, const void *key, uint8_t ivec[16],
- int *num, block128_f block);
+ unsigned *num, block128_f block);
/* CFB. */
@@ -341,21 +323,21 @@ void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out,
* |len| be a multiple of any value and any partial blocks are stored in |ivec|
* and |*num|, the latter must be zero before the initial call. */
void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
- const void *key, uint8_t ivec[16], int *num, int enc,
- block128_f block);
+ const void *key, uint8_t ivec[16], unsigned *num,
+ int enc, block128_f block);
/* CRYPTO_cfb128_8_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes
* from |in| to |out| using |block| in CFB-8 mode. Prior to the first call
* |num| should be set to zero. */
void CRYPTO_cfb128_8_encrypt(const uint8_t *in, uint8_t *out, size_t len,
- const void *key, uint8_t ivec[16], int *num,
+ const void *key, uint8_t ivec[16], unsigned *num,
int enc, block128_f block);
/* CRYPTO_cfb128_1_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes
* from |in| to |out| using |block| in CFB-1 mode. Prior to the first call
* |num| should be set to zero. */
void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits,
- const void *key, uint8_t ivec[16], int *num,
+ const void *key, uint8_t ivec[16], unsigned *num,
int enc, block128_f block);
size_t CRYPTO_cts128_encrypt_block(const uint8_t *in, uint8_t *out, size_t len,
@@ -363,6 +345,12 @@ size_t CRYPTO_cts128_encrypt_block(const uint8_t *in, uint8_t *out, size_t len,
block128_f block);
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64))
+void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks,
+ const void *key, const uint8_t *ivec);
+#endif
+
#if defined(__cplusplus)
} /* extern C */
#endif
diff --git a/crypto/modes/ofb.c b/crypto/modes/ofb.c
index 63c3165a..2c5bdc9a 100644
--- a/crypto/modes/ofb.c
+++ b/crypto/modes/ofb.c
@@ -56,13 +56,11 @@
OPENSSL_COMPILE_ASSERT((16 % sizeof(size_t)) == 0, bad_size_t_size);
void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
- const void *key, uint8_t ivec[16], int *num,
+ const void *key, uint8_t ivec[16], unsigned *num,
block128_f block) {
- unsigned int n;
-
assert(in && out && key && ivec && num);
- n = *num;
+ unsigned n = *num;
while (n && len) {
*(out++) = *(in++) ^ ivec[n];
diff --git a/crypto/newhope/CMakeLists.txt b/crypto/newhope/CMakeLists.txt
new file mode 100644
index 00000000..0f080f8c
--- /dev/null
+++ b/crypto/newhope/CMakeLists.txt
@@ -0,0 +1,42 @@
+add_library(
+ newhope
+
+ OBJECT
+
+ error_correction.c
+ newhope.c
+ ntt.c
+ poly.c
+ precomp.c
+ reduce.c
+)
+
+if(ENABLE_TESTS)
+add_executable(
+ newhope_test
+
+ newhope_test.cc
+ $<TARGET_OBJECTS:test_support>
+)
+
+add_executable(
+ newhope_statistical_test
+
+ newhope_statistical_test.cc
+ $<TARGET_OBJECTS:test_support>
+)
+
+add_executable(
+ newhope_vectors_test
+
+ newhope_vectors_test.cc
+ $<TARGET_OBJECTS:test_support>
+)
+
+target_link_libraries(newhope_test crypto)
+target_link_libraries(newhope_statistical_test crypto)
+target_link_libraries(newhope_vectors_test crypto)
+add_dependencies(all_tests newhope_test)
+add_dependencies(all_tests newhope_statistical_test)
+add_dependencies(all_tests newhope_vectors_test)
+endif()
diff --git a/crypto/newhope/error_correction.c b/crypto/newhope/error_correction.c
new file mode 100644
index 00000000..2b822b0b
--- /dev/null
+++ b/crypto/newhope/error_correction.c
@@ -0,0 +1,131 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <string.h>
+
+#include <openssl/base.h>
+#include <openssl/rand.h>
+
+#include "internal.h"
+
+
+/* See paper for details on the error reconciliation */
+
+static int32_t abs_32(int32_t v) {
+ int32_t mask = v >> 31;
+ return (v ^ mask) - mask;
+}
+
+static int32_t f(int32_t* v0, int32_t* v1, int32_t x) {
+ int32_t xit, t, r, b;
+
+ /* Next 6 lines compute t = x/PARAM_Q */
+ b = x * 2730;
+ t = b >> 25;
+ b = x - t * 12289;
+ b = 12288 - b;
+ b >>= 31;
+ t -= b;
+
+ r = t & 1;
+ xit = (t >> 1);
+ *v0 = xit + r; /* v0 = round(x/(2*PARAM_Q)) */
+
+ t -= 1;
+ r = t & 1;
+ *v1 = (t >> 1) + r;
+
+ return abs_32(x - ((*v0) * 2 * PARAM_Q));
+}
+
+static int32_t g(int32_t x) {
+ int32_t t, c, b;
+
+ /* Next 6 lines compute t = x/(4*PARAM_Q); */
+ b = x * 2730;
+ t = b >> 27;
+ b = x - t * 49156;
+ b = 49155 - b;
+ b >>= 31;
+ t -= b;
+
+ c = t & 1;
+ t = (t >> 1) + c; /* t = round(x/(8*PARAM_Q)) */
+
+ t *= 8 * PARAM_Q;
+
+ return abs_32(t - x);
+}
+
+static int16_t LDDecode(int32_t xi0, int32_t xi1, int32_t xi2, int32_t xi3) {
+ int32_t t;
+
+ t = g(xi0);
+ t += g(xi1);
+ t += g(xi2);
+ t += g(xi3);
+
+ t -= 8 * PARAM_Q;
+ t >>= 31;
+ return t & 1;
+}
+
+void newhope_helprec(NEWHOPE_POLY* c, const NEWHOPE_POLY* v,
+ const uint8_t rand[32]) {
+ int32_t v0[4], v1[4], v_tmp[4], k;
+ uint8_t rbit;
+ unsigned i;
+
+ for (i = 0; i < 256; i++) {
+ rbit = (rand[i >> 3] >> (i & 7)) & 1;
+
+ k = f(v0 + 0, v1 + 0, 8 * v->coeffs[0 + i] + 4 * rbit);
+ k += f(v0 + 1, v1 + 1, 8 * v->coeffs[256 + i] + 4 * rbit);
+ k += f(v0 + 2, v1 + 2, 8 * v->coeffs[512 + i] + 4 * rbit);
+ k += f(v0 + 3, v1 + 3, 8 * v->coeffs[768 + i] + 4 * rbit);
+
+ k = (2 * PARAM_Q - 1 - k) >> 31;
+
+ v_tmp[0] = ((~k) & v0[0]) ^ (k & v1[0]);
+ v_tmp[1] = ((~k) & v0[1]) ^ (k & v1[1]);
+ v_tmp[2] = ((~k) & v0[2]) ^ (k & v1[2]);
+ v_tmp[3] = ((~k) & v0[3]) ^ (k & v1[3]);
+
+ c->coeffs[0 + i] = (v_tmp[0] - v_tmp[3]) & 3;
+ c->coeffs[256 + i] = (v_tmp[1] - v_tmp[3]) & 3;
+ c->coeffs[512 + i] = (v_tmp[2] - v_tmp[3]) & 3;
+ c->coeffs[768 + i] = (-k + 2 * v_tmp[3]) & 3;
+ }
+}
+
+void newhope_reconcile(uint8_t* key, const NEWHOPE_POLY* v,
+ const NEWHOPE_POLY* c) {
+ int i;
+ int32_t tmp[4];
+
+ memset(key, 0, NEWHOPE_KEY_LENGTH);
+
+ for (i = 0; i < 256; i++) {
+ tmp[0] = 16 * PARAM_Q + 8 * (int32_t)v->coeffs[0 + i] -
+ PARAM_Q * (2 * c->coeffs[0 + i] + c->coeffs[768 + i]);
+ tmp[1] = 16 * PARAM_Q + 8 * (int32_t)v->coeffs[256 + i] -
+ PARAM_Q * (2 * c->coeffs[256 + i] + c->coeffs[768 + i]);
+ tmp[2] = 16 * PARAM_Q + 8 * (int32_t)v->coeffs[512 + i] -
+ PARAM_Q * (2 * c->coeffs[512 + i] + c->coeffs[768 + i]);
+ tmp[3] = 16 * PARAM_Q + 8 * (int32_t)v->coeffs[768 + i] -
+ PARAM_Q * (c->coeffs[768 + i]);
+
+ key[i >> 3] |= LDDecode(tmp[0], tmp[1], tmp[2], tmp[3]) << (i & 7);
+ }
+}
diff --git a/crypto/newhope/internal.h b/crypto/newhope/internal.h
new file mode 100644
index 00000000..eb170c06
--- /dev/null
+++ b/crypto/newhope/internal.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_NEWHOPE_INTERNAL_H
+#define OPENSSL_HEADER_NEWHOPE_INTERNAL_H
+
+#include <openssl/newhope.h>
+#include <openssl/sha.h>
+
+#include "../internal.h"
+
+
+/* The number of polynomial coefficients. */
+#define PARAM_N 1024
+
+/* The width the noise distribution. */
+#define PARAM_K 16
+
+/* Modulus. */
+#define PARAM_Q 12289
+
+/* Polynomial coefficients in unpacked form. */
+struct newhope_poly_st {
+ uint16_t coeffs[PARAM_N];
+};
+
+/* SEED_LENGTH is the length of the AES-CTR seed used to derive a polynomial. */
+#define SEED_LENGTH 32
+
+/* newhope_poly_uniform generates the polynomial |a| using AES-CTR mode with the
+ * seed
+ * |seed|. (In the reference implementation this was done with SHAKE-128.) */
+void newhope_poly_uniform(NEWHOPE_POLY* a, const uint8_t* seed);
+
+void newhope_helprec(NEWHOPE_POLY* c, const NEWHOPE_POLY* v,
+ const uint8_t rbits[32]);
+
+/* newhope_reconcile performs the error-reconciliation step using the input |v|
+ * and
+ * reconciliation data |c|, writing the resulting key to |key|. */
+void newhope_reconcile(uint8_t* key, const NEWHOPE_POLY* v,
+ const NEWHOPE_POLY* c);
+
+/* newhope_poly_invntt performs the inverse of NTT(r) in-place. */
+void newhope_poly_invntt(NEWHOPE_POLY* r);
+
+void newhope_poly_add(NEWHOPE_POLY* r, const NEWHOPE_POLY* a,
+ const NEWHOPE_POLY* b);
+void newhope_poly_pointwise(NEWHOPE_POLY* r, const NEWHOPE_POLY* a,
+ const NEWHOPE_POLY* b);
+
+uint16_t newhope_montgomery_reduce(uint32_t a);
+uint16_t newhope_barrett_reduce(uint16_t a);
+
+void newhope_bitrev_vector(uint16_t* poly);
+void newhope_mul_coefficients(uint16_t* poly, const uint16_t* factors);
+void newhope_ntt(uint16_t* poly, const uint16_t* omegas);
+
+
+#endif /* OPENSSL_HEADER_NEWHOPE_INTERNAL_H */
diff --git a/crypto/newhope/newhope.c b/crypto/newhope/newhope.c
new file mode 100644
index 00000000..7edb7eb7
--- /dev/null
+++ b/crypto/newhope/newhope.c
@@ -0,0 +1,174 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <string.h>
+
+#include <openssl/mem.h>
+#include <openssl/rand.h>
+
+#include "internal.h"
+
+
+NEWHOPE_POLY *NEWHOPE_POLY_new(void) {
+ return (NEWHOPE_POLY *)OPENSSL_malloc(sizeof(NEWHOPE_POLY));
+}
+
+void NEWHOPE_POLY_free(NEWHOPE_POLY *p) { OPENSSL_free(p); }
+
+/* Encodes reconciliation data from |c| into |r|. */
+static void encode_rec(const NEWHOPE_POLY *c, uint8_t *r) {
+ int i;
+ for (i = 0; i < PARAM_N / 4; i++) {
+ r[i] = c->coeffs[4 * i] | (c->coeffs[4 * i + 1] << 2) |
+ (c->coeffs[4 * i + 2] << 4) | (c->coeffs[4 * i + 3] << 6);
+ }
+}
+
+/* Decodes reconciliation data from |r| into |c|. */
+static void decode_rec(const uint8_t *r, NEWHOPE_POLY *c) {
+ int i;
+ for (i = 0; i < PARAM_N / 4; i++) {
+ c->coeffs[4 * i + 0] = r[i] & 0x03;
+ c->coeffs[4 * i + 1] = (r[i] >> 2) & 0x03;
+ c->coeffs[4 * i + 2] = (r[i] >> 4) & 0x03;
+ c->coeffs[4 * i + 3] = (r[i] >> 6);
+ }
+}
+
+void NEWHOPE_offer(uint8_t *offermsg, NEWHOPE_POLY *s) {
+ NEWHOPE_POLY_noise_ntt(s);
+
+ /* The first part of the offer message is the seed, which compactly encodes
+ * a. */
+ NEWHOPE_POLY a;
+ uint8_t *seed = &offermsg[NEWHOPE_POLY_LENGTH];
+ RAND_bytes(seed, SEED_LENGTH);
+ newhope_poly_uniform(&a, seed);
+
+ NEWHOPE_POLY e;
+ NEWHOPE_POLY_noise_ntt(&e);
+
+ /* The second part of the offer message is the polynomial pk = a*s+e */
+ NEWHOPE_POLY pk;
+ NEWHOPE_offer_computation(&pk, s, &e, &a);
+ NEWHOPE_POLY_tobytes(offermsg, &pk);
+}
+
+int NEWHOPE_accept(uint8_t key[SHA256_DIGEST_LENGTH],
+ uint8_t acceptmsg[NEWHOPE_ACCEPTMSG_LENGTH],
+ const uint8_t offermsg[NEWHOPE_OFFERMSG_LENGTH],
+ size_t msg_len) {
+ if (msg_len != NEWHOPE_OFFERMSG_LENGTH) {
+ return 0;
+ }
+
+ /* Decode the |offermsg|, generating the same |a| as the peer, from the peer's
+ * seed. */
+ NEWHOPE_POLY pk, a;
+ NEWHOPE_offer_frommsg(&pk, &a, offermsg);
+
+ /* Generate noise polynomials used to generate our key. */
+ NEWHOPE_POLY sp, ep, epp;
+ NEWHOPE_POLY_noise_ntt(&sp);
+ NEWHOPE_POLY_noise_ntt(&ep);
+ NEWHOPE_POLY_noise(&epp); /* intentionally not NTT */
+
+ /* Generate random bytes used for reconciliation. (The reference
+ * implementation calls ChaCha20 here.) */
+ uint8_t rand[32];
+ RAND_bytes(rand, sizeof(rand));
+
+ /* Encode |bp| and |c| as the |acceptmsg|. */
+ NEWHOPE_POLY bp, c;
+ uint8_t k[NEWHOPE_KEY_LENGTH];
+ NEWHOPE_accept_computation(k, &bp, &c, &sp, &ep, &epp, rand, &pk, &a);
+ NEWHOPE_POLY_tobytes(acceptmsg, &bp);
+ encode_rec(&c, &acceptmsg[NEWHOPE_POLY_LENGTH]);
+
+ SHA256_CTX ctx;
+ if (!SHA256_Init(&ctx) ||
+ !SHA256_Update(&ctx, k, NEWHOPE_KEY_LENGTH) ||
+ !SHA256_Final(key, &ctx)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int NEWHOPE_finish(uint8_t key[SHA256_DIGEST_LENGTH], const NEWHOPE_POLY *sk,
+ const uint8_t acceptmsg[NEWHOPE_ACCEPTMSG_LENGTH],
+ size_t msg_len) {
+ if (msg_len != NEWHOPE_ACCEPTMSG_LENGTH) {
+ return 0;
+ }
+
+ /* Decode the accept message into |bp| and |c|. */
+ NEWHOPE_POLY bp, c;
+ NEWHOPE_POLY_frombytes(&bp, acceptmsg);
+ decode_rec(&acceptmsg[NEWHOPE_POLY_LENGTH], &c);
+
+ uint8_t k[NEWHOPE_KEY_LENGTH];
+ NEWHOPE_finish_computation(k, sk, &bp, &c);
+ SHA256_CTX ctx;
+ if (!SHA256_Init(&ctx) ||
+ !SHA256_Update(&ctx, k, NEWHOPE_KEY_LENGTH) ||
+ !SHA256_Final(key, &ctx)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+void NEWHOPE_offer_computation(NEWHOPE_POLY *out_pk,
+ const NEWHOPE_POLY *s, const NEWHOPE_POLY *e,
+ const NEWHOPE_POLY *a) {
+ NEWHOPE_POLY r;
+ newhope_poly_pointwise(&r, s, a);
+ newhope_poly_add(out_pk, e, &r);
+}
+
+void NEWHOPE_accept_computation(
+ uint8_t k[NEWHOPE_KEY_LENGTH], NEWHOPE_POLY *bp,
+ NEWHOPE_POLY *reconciliation,
+ const NEWHOPE_POLY *sp, const NEWHOPE_POLY *ep, const NEWHOPE_POLY *epp,
+ const uint8_t rand[32],
+ const NEWHOPE_POLY *pk, const NEWHOPE_POLY *a) {
+ /* bp = a*s' + e' */
+ newhope_poly_pointwise(bp, a, sp);
+ newhope_poly_add(bp, bp, ep);
+
+ /* v = pk * s' + e'' */
+ NEWHOPE_POLY v;
+ newhope_poly_pointwise(&v, pk, sp);
+ newhope_poly_invntt(&v);
+ newhope_poly_add(&v, &v, epp);
+ newhope_helprec(reconciliation, &v, rand);
+ newhope_reconcile(k, &v, reconciliation);
+}
+
+void NEWHOPE_finish_computation(uint8_t k[NEWHOPE_KEY_LENGTH],
+ const NEWHOPE_POLY *sk, const NEWHOPE_POLY *bp,
+ const NEWHOPE_POLY *reconciliation) {
+ NEWHOPE_POLY v;
+ newhope_poly_pointwise(&v, sk, bp);
+ newhope_poly_invntt(&v);
+ newhope_reconcile(k, &v, reconciliation);
+}
+
+void NEWHOPE_offer_frommsg(NEWHOPE_POLY *out_pk, NEWHOPE_POLY *out_a,
+ const uint8_t offermsg[NEWHOPE_OFFERMSG_LENGTH]) {
+ NEWHOPE_POLY_frombytes(out_pk, offermsg);
+ const uint8_t *seed = offermsg + NEWHOPE_POLY_LENGTH;
+ newhope_poly_uniform(out_a, seed);
+}
diff --git a/crypto/newhope/newhope_statistical_test.cc b/crypto/newhope/newhope_statistical_test.cc
new file mode 100644
index 00000000..44fac48a
--- /dev/null
+++ b/crypto/newhope/newhope_statistical_test.cc
@@ -0,0 +1,156 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <string>
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/crypto.h>
+#include <openssl/rand.h>
+
+#include "../test/scoped_types.h"
+#include "internal.h"
+
+
+static const unsigned kNumTests = 1000;
+
+static bool TestNoise(void) {
+ printf("noise distribution:\n");
+
+ size_t buckets[1 + 2 * PARAM_K];
+ memset(buckets, 0, sizeof(buckets));
+ for (size_t i = 0; i < kNumTests; i++) {
+ NEWHOPE_POLY s;
+ NEWHOPE_POLY_noise(&s);
+ for (int j = 0; j < PARAM_N; j++) {
+ uint16_t value = (s.coeffs[j] + PARAM_K) % PARAM_Q;
+ buckets[value]++;
+ }
+ }
+
+ int64_t sum = 0, square_sum = 0;
+ for (int64_t i = 0; i < 1 + 2 * PARAM_K; i++) {
+ sum += (i - PARAM_K) * (int64_t) buckets[i];
+ square_sum += (i - PARAM_K) * (i - PARAM_K) * (int64_t) buckets[i];
+ }
+ double mean = double(sum) / double(PARAM_N * kNumTests);
+
+ double expected_variance = 0.5 * 0.5 * double(PARAM_K * 2);
+ double variance = double(square_sum) / double(PARAM_N * kNumTests) - mean * mean;
+
+ for (size_t i = 0; i < 1 + 2 * PARAM_K; i++) {
+ std::string dots;
+ for (size_t j = 0; j < 79 * buckets[i] / buckets[PARAM_K]; j++) {
+ dots += "+";
+ }
+ printf("%+zd\t%zd\t%s\n", i - PARAM_K, buckets[i], dots.c_str());
+ }
+ printf("mean: got %f, want %f\n", mean, 0.0);
+ printf("variance: got %f, want %f\n", variance, expected_variance);
+ printf("\n");
+
+ if (mean < -0.5 || 0.5 < mean) {
+ fprintf(stderr, "mean out of range: %f\n", mean);
+ return false;
+ }
+
+ if (variance < expected_variance - 1.0 || expected_variance + 1.0 < variance) {
+ fprintf(stderr, "variance out of range: got %f, want %f\n", variance,
+ expected_variance);
+ return false;
+ }
+ return true;
+}
+
+static int Hamming32(const uint8_t key[NEWHOPE_KEY_LENGTH]) {
+ static int kHamming[256] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
+ };
+
+ int r = 0;
+ for(int i = 0; i < NEWHOPE_KEY_LENGTH; i++) {
+ r += kHamming[key[i]];
+ }
+ return r;
+}
+
+static bool TestKeys(void) {
+ printf("keys (prior to whitening):\n");
+
+ uint8_t key[NEWHOPE_KEY_LENGTH];
+ uint8_t offermsg[NEWHOPE_OFFERMSG_LENGTH];
+
+ ScopedNEWHOPE_POLY sk(NEWHOPE_POLY_new()), pk(NEWHOPE_POLY_new()),
+ sp(NEWHOPE_POLY_new()), ep(NEWHOPE_POLY_new()), epp(NEWHOPE_POLY_new()),
+ a(NEWHOPE_POLY_new()), bp(NEWHOPE_POLY_new()), rec(NEWHOPE_POLY_new());
+
+ int ones = 0;
+ for (size_t i = 0; i < kNumTests; i++) {
+ NEWHOPE_offer(offermsg, sk.get());
+ NEWHOPE_offer_frommsg(pk.get(), a.get(), offermsg);
+
+ NEWHOPE_POLY_noise_ntt(sp.get());
+ NEWHOPE_POLY_noise_ntt(ep.get());
+ NEWHOPE_POLY_noise(epp.get()); /* intentionally not NTT */
+
+ uint8_t rand[32];
+ RAND_bytes(rand, 32);
+
+ NEWHOPE_accept_computation(key, bp.get(), rec.get(),
+ sp.get(), ep.get(), epp.get(), rand,
+ pk.get(), a.get());
+ ones += Hamming32(key);
+ }
+
+ int bits = NEWHOPE_KEY_LENGTH * 8 * kNumTests;
+ int diff = bits - 2 * ones;
+ double fraction = (double) abs(diff) / bits;
+ printf("ones: %d\n", ones);
+ printf("zeroes: %d\n", (bits - ones));
+ printf("diff: got %d (%f), want 0\n", diff, fraction);
+ printf("\n");
+
+ if (fraction > 0.01) {
+ fprintf(stderr, "key bias is too high (%f)\n", fraction);
+ return false;
+ }
+
+ return true;
+}
+
+int main(void) {
+ if (!TestKeys() ||
+ !TestNoise()) {
+ return 1;
+ }
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/newhope/newhope_test.cc b/crypto/newhope/newhope_test.cc
new file mode 100644
index 00000000..6637393f
--- /dev/null
+++ b/crypto/newhope/newhope_test.cc
@@ -0,0 +1,142 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/crypto.h>
+#include <openssl/rand.h>
+
+#include "../test/scoped_types.h"
+#include "internal.h"
+
+
+// Set to 10 for quick execution. Tested up to 1,000,000.
+static const int kNumTests = 10;
+
+static bool TestKeys(void) {
+ // Alice generates a public key.
+ ScopedNEWHOPE_POLY sk(NEWHOPE_POLY_new());
+ uint8_t offer_msg[NEWHOPE_OFFERMSG_LENGTH];
+ NEWHOPE_offer(offer_msg, sk.get());
+
+ // Bob derives a secret key and creates a response.
+ uint8_t accept_msg[NEWHOPE_ACCEPTMSG_LENGTH];
+ uint8_t accept_key[SHA256_DIGEST_LENGTH];
+ if (!NEWHOPE_accept(accept_key, accept_msg, offer_msg, sizeof(offer_msg))) {
+ fprintf(stderr, "ERROR accept key exchange failed\n");
+ return false;
+ }
+
+ // Alice uses Bob's response to get her secret key.
+ uint8_t offer_key[SHA256_DIGEST_LENGTH];
+ if (!NEWHOPE_finish(offer_key, sk.get(), accept_msg, sizeof(accept_msg))) {
+ fprintf(stderr, "ERROR finish key exchange failed\n");
+ return false;
+ }
+
+ if (memcmp(offer_key, accept_key, SHA256_DIGEST_LENGTH) != 0) {
+ fprintf(stderr, "ERROR keys did not agree\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestInvalidSK(void) {
+ // Alice generates a public key.
+ uint8_t offer_msg[NEWHOPE_OFFERMSG_LENGTH];
+ ScopedNEWHOPE_POLY sk(NEWHOPE_POLY_new());
+ NEWHOPE_offer(offer_msg, sk.get());
+
+ // Bob derives a secret key and creates a response.
+ uint8_t accept_key[SHA256_DIGEST_LENGTH];
+ uint8_t accept_msg[NEWHOPE_ACCEPTMSG_LENGTH];
+ if (!NEWHOPE_accept(accept_key, accept_msg, offer_msg, sizeof(offer_msg))) {
+ fprintf(stderr, "ERROR accept key exchange failed\n");
+ return false;
+ }
+
+ // Corrupt the secret key. It turns out that you need to corrupt a lot of
+ // bits to ensure that the key exchange always fails!
+ sk->coeffs[PARAM_N - 1] = 0;
+ sk->coeffs[PARAM_N - 2] = 0;
+ sk->coeffs[PARAM_N - 3] = 0;
+ sk->coeffs[PARAM_N - 4] = 0;
+
+ // Alice uses Bob's response to get her secret key.
+ uint8_t offer_key[SHA256_DIGEST_LENGTH];
+ if (!NEWHOPE_finish(offer_key, sk.get(), accept_msg, sizeof(accept_msg))) {
+ fprintf(stderr, "ERROR finish key exchange failed\n");
+ return false;
+ }
+
+ if (memcmp(offer_key, accept_key, SHA256_DIGEST_LENGTH) == 0) {
+ fprintf(stderr, "ERROR keys agreed despite corrupt sk\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestInvalidAcceptMsg(void) {
+ // Alice generates a public key.
+ ScopedNEWHOPE_POLY sk(NEWHOPE_POLY_new());
+ uint8_t offer_msg[NEWHOPE_OFFERMSG_LENGTH];
+ NEWHOPE_offer(offer_msg, sk.get());
+
+ // Bob derives a secret key and creates a response.
+ uint8_t accept_key[SHA256_DIGEST_LENGTH];
+ uint8_t accept_msg[NEWHOPE_ACCEPTMSG_LENGTH];
+ if (!NEWHOPE_accept(accept_key, accept_msg, offer_msg, sizeof(offer_msg))) {
+ fprintf(stderr, "ERROR accept key exchange failed\n");
+ return false;
+ }
+
+ // Corrupt the (polynomial part of the) accept message. It turns out that
+ // you need to corrupt a lot of bits to ensure that the key exchange always
+ // fails!
+ accept_msg[PARAM_N - 1] = 0;
+ accept_msg[PARAM_N - 2] = 0;
+ accept_msg[PARAM_N - 3] = 0;
+ accept_msg[PARAM_N - 4] = 0;
+
+ // Alice uses Bob's response to get her secret key.
+ uint8_t offer_key[SHA256_DIGEST_LENGTH];
+ if (!NEWHOPE_finish(offer_key, sk.get(), accept_msg, sizeof(accept_msg))) {
+ fprintf(stderr, "ERROR finish key exchange failed\n");
+ return false;
+ }
+
+ if (!memcmp(offer_key, accept_key, SHA256_DIGEST_LENGTH)) {
+ fprintf(stderr, "ERROR keys agreed despite corrupt accept message\n");
+ return false;
+ }
+
+ return true;
+}
+
+int main(void) {
+ for (int i = 0; i < kNumTests; i++) {
+ if (!TestKeys() ||
+ !TestInvalidSK() ||
+ !TestInvalidAcceptMsg()) {
+ return 1;
+ }
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/newhope/newhope_tests.txt b/crypto/newhope/newhope_tests.txt
new file mode 100644
index 00000000..20d9c037
--- /dev/null
+++ b/crypto/newhope/newhope_tests.txt
@@ -0,0 +1,206 @@
+# These vectors were generated by the reference implementation, lightly modified
+# to emit the arguments expected by BoringSSL's implementation. Most important,
+# this bypasses the random number generation and key whitening steps, which
+# differ between the two implementations, and focuses on the common and
+# interoperable part.
+
+InRandA = 420c3c6b581c9f4466cd807170629a84b681aa1063a341062aa37956d70ae68befe87727d99fc92e7c29e215c5f13b722587c0d675d79190096a280a192aa4f4e65f982a59130f9266d22e4e8cd9ef195b45813cc8233a253f8a752548529b463226d3ebcf422870739095d567e7f6a512630c6766aa2668e8477a78865849e0b16bd0e4919d1d7da0c5d8005104e6e4d6b6855590e5c6a4e649dc4a0ef5b5ae140251c26b8c32001ed7ad13cda56b94c3294010c84ab54fba1888686384d40e310eb6363b9b23057782805f62e378c27ab98f223324add836772c3e81b8212bdae3c864a59c6e63a72327c42e69711ffcb3b6d04c00293e91d76c50ef9fdf33fd382c769835e0bd4821f65e66797075915f138a6b49051ec406ea750d50384d5d4ce2c9c536d45d3f7a704c6cae8d82f07bc5590f908b308d8c1b8d5e9ee3931d2d55145236f10688ae192f531755b310ccaf3891125af5decb1adbaa85224c47b73c3c8d7fa92ae1635d03d64d73c600486b336c8a511a7e1675a3dec9fcde711601ab73fc4d788d9de3d9f8fe185b87e920550d705f89f3188d1a69f9efc036666d7f5321d71b7eb5436f9bbab400884c08c59bd0a9458fe1e2b7b73d1e2a5ca4b21be5d48125613f0884d15eea9393a4dbb225bb66e5da5d3d98fb20c10761fe0efa5cf00498b29a662df8f8f17a4de3851fa425552aca9544aa89c89981d0f85636f67a862ee4eb844579f5c0f1b9bc0d647b15223aaf0c9edce88815273a0b064772b46dfc933a4dd8db90aa585097b2c6c0564ca90164a43d798403426544bb66637597dcf92a747b7b5ce1f7ba266f5c482d73e8f8b27920a627d1e9154ea745c213988f405ac2a19ec0a37388f8f67cbd9bd7c64222bd14a664eb5146a0645ccb542c21bde65bd2093a9b7622158a9504b0f230276ae1afd7ba6d7267a546e8c08dbdf168be439fe9263427752658d225a2062202ad567235685ab76585b04151f65a63016c9981a635116ab7766789a066d40d122805178f6840ec225e22dc5147d09ed9a53d8582e0e15b25b9a163178314205722adad9e9798c1306adcc002ab59e146302f0e08124945a18bfb10666c6b429124c5f5e61b98e2e8e6defd58b0dd377924f6a8d788c5887c306cf5864931b171936ae80f4911d483ccc804c112a0bc88a80621b0a1a9f8dd9f44f4f84687c54b533b4614d82741fb78006cdd137c422e5441c4513de3ae8a4cf4db9c679fb90c986f97abe8e1060d0392b668de010a0f9f1447445557c2f069f76e285a94f257ed368a70ae2922926c9452c01fa1fad6aac2db43daa67d68b31f3889acd8649a0c7389336d5d6904715984020470493a18fc84aa2bc61e352184714d0f5f46df0e3fa5a3a8a852f981135399d5df8d44b46abd6bfc164c4587e2a79ae255dadd09f964809c57e753105e2575bc987d924f3d7b9bd90747d1b61ce06a56ba60f1813463c418a3ad09821846b6c2b5057aca1939f255acca579b310fc91d112b6669088a66299fb227a7ca15c686604bf47c10d6c4aa1b56d03a7fe23217294866ea820646c372579955ccc16471159b83d8ba016c114c10c961221c28a956fce40806780e043883349d8e8baf8f308610be18c6103a454c8f30cb9465cc9d3be2935e347fc691a503b4c92d311d29abba18497283e646c3ab030a1dcfd295a29bc6517dde0cb295ea89639824c7fa99a968dd7a1aeb1983925258f3d7853517d6b5db4060783b27c949b80989561303d95cea8059e5e7fa520c2d3141fec406d88535d7060b1f4ebbd08cc7687e3d83040c97005d450f4405c557c9e0b71f047ffac98aa6ffea1f5598223163ea918ad5319bb919d9633254156aae2c527521664a6e54abae312e704b0fd335014a66ad8d22bc9862a0d239a9deb2a011553fe38f0100be4705f0a25580ade9b4b24705264326030b06d512f2d4c815ed36827d1078c57882369c1c2129ee1e1f8d51d45ab0d573820f9618fc2a45c25769f99ca51554efa5d086d039655b6a23874e18d02bb3b28a2d43a293b7e0b32d5c5000a222ddb92f945f0bc40a49427d8ab084de1e89cf9c70c9d39e1f902844811bca5775ad2f73ca884314846d474ef957a4d98eb4c98eb94f9cc6b6edd101b78d9a4b5986626752363b3e2c030bc5b0eb49e558d55ebaa92e1627cc166790aba847725bb487d08930714922d764eeae45c2a4157311ae4fdf4995c7781559cd149124a86843682df807d60ee922471be84d830e1cbed3055e281a19b855121977435f057000329a9a0458e51fca4dac4fa36303c02967d7551759b153f653ca653f7016d427ed7bdc6c49896741853148338688a62745e144c2840cb2fd22aabacbd6e7378074da23a68689664d5e804307beeaaef7454101d34c28441ee8456384a752992494ec2c4d4381c3ba3441357d8c545baec472eac58ca0f665992d64e1e1342c639863a09779e88349afa0418f667aebc22b92e7722e956793653992ab5768c170e8e564
+InNoiseS = 2e6f8b71cc4ab67f9816984bce92458263794396bd66ec320565045122d1a427408678dc565386f2f993fb14e1422366ade64536811cf943271a185b747eb2d62d13b6d5028b755179d538f915bce3fd7b1e4a2d6d4e6bf29d06554a010502a70a516fd7c6564b323723eb2a8570ceb98603208a349c685ddc1366b55da84b801ec8a5ea3882c6668a394d98b4a1036946ad618f1cf427a9a05676dbc615acb25c53cb83a117964065618b213f1e4851dcf2663638315859704a44b5785bcff0f7fd2a6eff292c2950fc817d5a4b7bccd014d95c4565abf86a6e8cd2b32e9594482e46e505e57932d30ed6639853c74ff2138b122fc46f54c183f11858ebdb2b871ca916109922ea7e3556e63d95028c62d2652c0b9f35af121da795121d5872043711b6a56639e169eb41d9780f6462d140cc7ddeabaed49d9c4e4284d07132d92fc39b98a5c5cd278023e3a1fdfd8875e0a7a2effe4dd3e2897be58520d99c36308caead22987d959a480db2cb76488cf14e4c9bc92887d5107c6df91ab69abd9a11a50a91b41138c22ed8281c58ae49a512c5c203f563bc7950147ded01a7078f8ebeb324e6e305295522df6eb91035ace84be894fa824fe6415b664e1873f3a4ace6f2f5aaad6d121a489688d3c7d307ab2414b79822305f8842339540f42e089df2c1bf0620ec7a306f36b2d4b27c72439875109d6dfbcbc43358f068108555e0f7e2b047140a589cc4be815227c9a29eaf7914e381513e5d9d00fd3296ee894c9641d2b00e79f62f2f62d8b5ade28bdc26fc6e3711c2fe3694ec9c461e28b5524c59fd2a0ff2ff599c04d8b882f23a5ecf917d080130214c262d3826a616f093acfb64fc6c9c82c36708a628c652cbf0ec8911e902caa2e805268b8144e595f1bbfcccbdb8b7a64af5e101fb113e8abec686c1ee7c2a539593b6f80549be9d8b814f360d71d6bbeb569db2e94d52405b8895da9a02495a01ac93ce9847503e107f6b81fa598c539409a7873af606315f82b9eac49b68a6b9f214a84d58083e067edd52d167d1ea65969cb7a40299062a732d2fbfb26139570c97151187741b9d020113651e2ed0cc279893348b2592531a6a1874c317ec638b42339890205705a52099aebb745f2689c54954f32620598048557aafd940650451b5a0e246f683e507d72080ac8b92ea399023f4ca93dbfb54637cd0301171d124d34a48f0db1a2c5f5ae5725271249a1198347b724b22817f649fcc4b02ec374b10b0524e08a9a41771741c2234d6324856c1aad86051d831e62333162aa2a32905d618e76c353a496829e3cc7a07a66b975364907e6da5d983e65004a392b1b8ce692ce1b24030a6756d60f6972a2e8aefef7d761e15645043d7720d1d756d1713b06c16712716f9204e29b2f8a45172b0498328a0d1b8a7a664079123b9851059add99e2209b4911359f42659e24def8cda7bd4da1ae34fa7669f8218d786b8b9ca16520ad54b5553b92cc99541e6f51caec0176729687977979c4726abf5321344edd66f0e03bea512c6dd54b9d6c80f932d4e58e75f8bf97b3e0e15e412704b691334d10541cb7037eb653f084d96afa4c3ab78d2468e4242fbdb24b05db81815280ef458871dbad0c938719a855d80c3392506ac313b755e13e6d587d0e9c11775e8d588cb048f60c64c564024570b474ab83d9a8d2fc7a0eb465803aa2b643a15c59e3f156ad133aca6c9c968d1493d601fa59591c8d0aea49a697a2e7426c36d24f343b292ed2201bb1f2638a2923c8220e0321f081cf465f98b5f69ff3ab78574646e828487f40c6f4d7c28be30391f083e78640a28f7066ab9aac6138a106dc9c3497c38efbcf007062de29a4b7a38397d0305a04b5fca5f51ddf6b026dd9aa1ef88a394aea54f20be3800d488af630522dfbe8306a10f7178ce06c097a3d7ca62b7169365486b4a23c52c1017fd4513268e4a20c5702b8d624d028098bed550389ad8b987c26a0a0bca7478f3c8b5a4c926a2c10c34662de11b7a260539727e75304c0c28b15e7cc6105da18ab6ba720eb6e0bfce3b220f7f68bcbd845ac8c7d166a837c46714721c227b5bd263d2a6fd54c7a7f26267597953943ef22cb9607f65eb829b5e4ae84b1a263c69a77b16827a7dda44bad604831dee420100d2ab45d822cca55378fffc7377d57c381dd92661eb2271599a68f4a5c4811ad16f27c16103ee9e7a802e9011f7fa542f4799d65c448245424c9698fd3d10cde7cbcf6885f6d630e1a7248ca7ab16b6cd8d262e1cc20243d46c5e1c2aa508c22b6aacfa0a4b8c60e2056bc3365c5f3acc45c61b2d12778bdbaac7744423af4b32f52eafd9a7835400ae42d424d8a46c0c03acefe9a684f903f5c8761616cc82e05de264cb7278529f3c3255b8095f64a2f3f5299b3365efb356d856b04731a8c77845336db8c1952a6ee91b64578d620af6052a700989a2338041e767098c996ce97a6f9907c284bd4acd688937617003afb95af11447629d71222919bcd5b4204a
+InNoiseE = ec87b3c754016deb580970f1a4368e1befd757ba3720cfb430599d152515761942bd92cad5a6aaefbe10888f6cb7d4112044c2c1e973a9376cab5d17e746ade95e0ae29cceb213494a98e9985409452d91a0794ecbd947039459aed8227cdad69a175666302007ba6f195968c8244c251bc84e8aaf8298654c71b852e253ab286d74d95c934344c85123b44c59ac7772e5baa0b827b197b0b6763016e1765381bb0127f478989c7ab95ad88b5a3c5480a35b16ca8c1fe061727398120c774a8b13307804f06aac48d8b1867265275143d1a126694bf6e5d25b25850e4428593f2cee882b2dc914c7158a6604de4ff643db6a9c286a585710e004b83e63049ef0c902585d55ba708cf292576430b77a86ace85bcd72a95856af4491674a750b438860c7805ea177ac98f1980e98bc1f92a3c4d284e5414689f26d265d23f02322d0a0c8eb60a4f31227e4c5467494a850dc027ea59616135c2db689294ab033201a4298fd02126866a38d814b959bee0a1bd045ca6f47f57a663019196ae7124c357364cc1140213b1a0c9c3651f882f050fb450948710211bb520b3c27d4a078e8bbe4b4c829b1e11199ae5d9ce441ad9c4d456664ca38d15607afcd66b0dc1635e6f0a744c8a0710bba49d00a860a46e3180bed85d8a134a7676ea65d420122e14488d21190092da666a225721213da7cce85ee51ad303e418bdda631d96e94958d749994699bafc6586c652d82e3a2e8d5e9a836606e265ffa5b292db623b8cc3690a90f81d8c59ef1097eb2fe5144d26f3fb30b2253e9d39d708c887665ca2ea9d9415b2aee7adb12794a420c21752a2068bd98ba55276405030684eb3dad424707f7e95b552a8f1aa6696560822f4e4ac551855d4a8d65b334a1174adce5b941a5249ba3e5393fd099cd9dd5589761100ae40c275c344b4d9fd7e95136bb8609f6e458ac04ef59fd22a7d23b6ca3f5b0ede97ee8c1f2c70bee77c213f611a1899d191c302606c61e09d562a3f8e6899398ef3918c259d6950da390aa57e9112652035a03772a422359fe570ce6168374ed3e1ccf299633ba0adde0eec22129bb354fccb7974600ae8232b698492acbe28024671a7f03a0a196bf790ec3d217bb279eb4f6ea041b62d054e19a39658cc671bf15b9d4af6a5a482c49ab18419630afa2b714528ab02326633f70008c8ad77a2a8e4cad9ee226b8ca58f8189508a199129b097d90603536412eec9af1327bc46efac7ffc42894837de833993562616f61cfc8557b5f04b2e5e56ea0e5fb2106e834b70bdd6a1d45a19c020190fd069e950fdd13982994f841f6a4563a470ad65659984dbda7802209dac690ec1d33a099c676d0c0b6866de62b35250683bd363e38804ab077a61944529bb022926c228cbad041f0bbd8de4de790d01dd651ce133d641f45109d3099b82b905fb66aef2111929609e8f4a228262596524be270408c1f7a4d0db3ccc44c78ecbea76fadf63599018f22e99645b07847ee187e71ef72216d52427ac20858efafa1d89cc834bdd8b7f102ca3a08a331f8a2896d148bab795f8d098122d2c640a58221297a536b262bd0e9d4b184d81465ef9b2ae12ab0a71fb2b94bf097db1a2feb7be25de709c1e7e5ceb72c401f0713501cef040c5bccb64146c2cc48b6010496868b10a8fc9ac5438b34ba6970af8cbcf59ae07a72c0a5b0d31663f7212faa22954611abb43380cdb3e8e91ee2194d81efcf20a37b9c5e2f457babe49200772deb96d00857c06d3c8412c844d28654a1a77e2885c044c32581a438df44a1c7f567086687f0fc795fc20e7861b5fe26cb10d2b329ccad97e858e0720233844368ca503a58fc48ac3712bc1c01490c64b37a2f1f9f65a78c983b628568c025c83031e222895bf00decc3d99503887c9080a6269de9ae332a09e2f6be0c8ae34d70ef695b5f17b9f4f6a60443945e6ae69ea4750f65302d9d6a7cee8ae01ba54207645ed0e4e556badf3ac1d82c2a8e0042734c7a275c2a61c00f728eaf90830bcbc5737c22d17842252cfb8570f55ed18eaf5218825a7d81bb00eee79cfe92ee82189712665bfc593ebbb84d420ca07d0594ceb400e75be3774eac5e4925967c5a2e04625f69f5a8a5981dd1173af8a8f42671e73d7684feeec1658f147a09569825e90993bd5cf15491cc06ef6de889dd78bd1d22fcb874843ef6e59766095610d5d247f9be1ab709e621b476923a2647fca9f53da8c78b6d08c179b1be2c2d0a304960922d6ac8e2f61f9c08600bcca591f8de995519ee355a53ba7108f44a6297d2b931d07a96c9c0866c44843f06814b8ae00c5a598f03cd3a5fe5a9f615de8da4f0c4d6d6e2242a62e776033b2061e6af2468fd65a580854afbea8c82c549a0276ee0723bc5233ba4c506b365709b9d15403522ce98de9d3aaf8da8813b7111582b75fab1115d9cedbeba735e3c8de4a7730aac543b0aacf39620a00b686f79b5b48c63a54005c5010b92e980a8e275ac24ab163a14b8acd16a41c7da648f
+OutPK = bc8dcdf734ed3f2091a723a0b57fd80c53ba783e9b8f285214dc9805d528f47a6d622c54e160405fcd098ee293f34936927e9e33c7845d33e4d511c4ec8569af4d3af4f3c8165d9262993ef68dc74f2e0a963561320b6c40bbd639526201c952dc5f6e56c3975dccbb6968a566a35629f4867c88700a774dc26025302062db4d391bc4c8adfa270bb609122c45e35dd7cdf25e7b09170891fc0662e5b254731473a4ec5945177d817ad769670a4c6537839e720256b5cd5c8548c3de36d38a543a4f225ee2d526738436afdd80fc6aec16529853a20b1494a1c4589535d89eb9eb9c0008ae519e5d101ef4239c8f78d96746d196568c528bda9d9895b61633cbdc99a44fe794b43b600b4116bd617bb95e935b798a212a305f6e608bdcd09bd725ac7999784f06a05cf156ee93a78ad9c5af0e593be56af5677eb70195f025a87822c443d2a041ad4ae7e37a4a65651a056e3a667c720cd504dfe4ad4d54ba89a5c41e545f13ce34e614bd32029939a2ad98bacb066c71a01a462c45ec9564884649a1671797641895ab0c69d3664e4e42af843d5a7ae8ceb369f2405e6c111f70d7356c57a98086d9996650d0e89a64e003454c5857dc0183cbc4b305a24a5f8c8d8cc8c8b54ee9a2d73a2daa96a9c2eb3ba6298594d5a9ba58a587ce1cc4f34afebcfaee9858112d222106030b5d2923780df294ecd589df9039b2aeac35e640ac90d4b10d1e6b6f903df28898c84f759d3c9830aa6e4934f2a88f5bec4488a6021440271b986d44764825a1c7a62bac0e6812a0f64c10e21a1810ee19f36f931742747ec9997741cbec6def679364c1919307d4361aae1a880706061710417e144a1495f13e372268e2ba017a99d3c9025883445d8f148da36fd55a311e9f8104a974cf993c87029ca7d5ae1fb5cf0d4e6fc985fa6a5839d3d7addacd1c75cc5f903358c01e2c4f72499bfa58646a26e13c152b27e8acf3aa85adfc53b5009459b6b6e6e6311bc9732b823e084708938516d6b9451d4b1799f3a1c2ac60f70cfb8b92c55eb8d81b06bca5a64393a6d7386e1f1e20530310d8ab3f6d0d5bf06a7715ce157a9f622f164d6b1566ba82abaec91be9ac3ebe5a8b75f349600ee12e2685d505548cb66008b8318705c890810e4d04e784c2913c026642344647f8b97ea6ff7a0376b135dd1f9332887316e42da8ed32b42b1a42e4c5b4160457b2d898cd41b5df0ffa970183a59b26272002b2836866d32f696623a768116c2691d1666ac882b974e3cdd0d08e5e7d210db2f5d7349c5b130038e09e0a8fad2db1111d731944b3d6692671490a6af15cc69c1a29863b22e8a6de87239539ce0ceca541e6c4515821af61103ede0e3156ac71d3a29e3a8e4b84f4850b20d193ea55dc073a9d83c846ce3f55dc083ae93612c02f72117a4693a4c023f8e824b5500f61509094a89bab8d531ec8aef5291ac9ebd44cb0a2c9413274007488f32b12f459c5e10b849004902ac03273ce86a7a91a17ab46590ace5b4bd5333d8f5481e4e05fc94b5e68db79e30e6c08dd3c0578ec4fc0c55d6850313c8215b052a22d2f778dace1e33441406d5772a28a7ed892b867dd4c9e2818ff259e115bd4026437cffd7ef65dc4044e9830e64149e34cb695cddde34336b8bb40c00c15bfbdaded1593293a6d166ad39d8336b1178ed121bb13a98ea31a46d9f4817b3d8454e26bf405a32f51c15d1d419112ccd2af006e415bd5e3cfb67aa9d5ec64fc599b026934f7dbba1f4c120558364057a5cc5f901b2c0d411dcbe02342bfe32416277e1937e69a3e87f6ea0f214534f278a022231354653e3537e72b75923be4472a1275cb3cad4cf361dfe6be8c6fec69bd824f2a4d84878acac5e97287805279bdd92f48e8d1342f1a3cd8c711f837be0f188ed54071f9441b2b11b0acbc0c3510b4c4c5beababd27c7176f00c2396a3b81ecd9135e1f0171cd97976415671b28d63cb67996626f088f2de42125989581086dd29e87c6f4ee507537e2c9ac8e0f9827b9454770add19de3c3f8c093e85a93e9aeba6e157e38d8a42cb8893efc9ac78d79b9a02fc0500e4466a2942109de0f351ae313a534db4762802220ec7efd5bdc62ec04810e950dc16dc9f0ccafb6eb4a75db6f412ad3575094e8175290e70688f6780be7388846fc98a394c28ce11f51bc8b1cf54df58f06d4aebe2e185b2b48dd2d39483fe584b56dc1509c26ca5f89aacd27ba102232695a74e0613f91ceba0b385a0c59e60f24fce013b0646ba4d1e38e86a0962b065227b1f2a82e9d594e4125fa7660e7683a9a6d5f8ca7f9fc11f98828ab5f0edf94370e951c5e044190d367e4056ee54b97199d067505258aa5684db9dd24ea1ad52cc8744f5b2683584c131d244311a55985bf09c75d7237ab0607e334d6626278fb21a0150ebaa7ab0b78081bd43c706731ea3ccf9678822ade40320d51c040c9f1072c42562d18c894725ee7105da06e5b694420a639d67f8a1062491620238b0199b1a917b219049
+
+InPK = bc8dcdf734ed3f2091a723a0b57fd80c53ba783e9b8f285214dc9805d528f47a6d622c54e160405fcd098ee293f34936927e9e33c7845d33e4d511c4ec8569af4d3af4f3c8165d9262993ef68dc74f2e0a963561320b6c40bbd639526201c952dc5f6e56c3975dccbb6968a566a35629f4867c88700a774dc26025302062db4d391bc4c8adfa270bb609122c45e35dd7cdf25e7b09170891fc0662e5b254731473a4ec5945177d817ad769670a4c6537839e720256b5cd5c8548c3de36d38a543a4f225ee2d526738436afdd80fc6aec16529853a20b1494a1c4589535d89eb9eb9c0008ae519e5d101ef4239c8f78d96746d196568c528bda9d9895b61633cbdc99a44fe794b43b600b4116bd617bb95e935b798a212a305f6e608bdcd09bd725ac7999784f06a05cf156ee93a78ad9c5af0e593be56af5677eb70195f025a87822c443d2a041ad4ae7e37a4a65651a056e3a667c720cd504dfe4ad4d54ba89a5c41e545f13ce34e614bd32029939a2ad98bacb066c71a01a462c45ec9564884649a1671797641895ab0c69d3664e4e42af843d5a7ae8ceb369f2405e6c111f70d7356c57a98086d9996650d0e89a64e003454c5857dc0183cbc4b305a24a5f8c8d8cc8c8b54ee9a2d73a2daa96a9c2eb3ba6298594d5a9ba58a587ce1cc4f34afebcfaee9858112d222106030b5d2923780df294ecd589df9039b2aeac35e640ac90d4b10d1e6b6f903df28898c84f759d3c9830aa6e4934f2a88f5bec4488a6021440271b986d44764825a1c7a62bac0e6812a0f64c10e21a1810ee19f36f931742747ec9997741cbec6def679364c1919307d4361aae1a880706061710417e144a1495f13e372268e2ba017a99d3c9025883445d8f148da36fd55a311e9f8104a974cf993c87029ca7d5ae1fb5cf0d4e6fc985fa6a5839d3d7addacd1c75cc5f903358c01e2c4f72499bfa58646a26e13c152b27e8acf3aa85adfc53b5009459b6b6e6e6311bc9732b823e084708938516d6b9451d4b1799f3a1c2ac60f70cfb8b92c55eb8d81b06bca5a64393a6d7386e1f1e20530310d8ab3f6d0d5bf06a7715ce157a9f622f164d6b1566ba82abaec91be9ac3ebe5a8b75f349600ee12e2685d505548cb66008b8318705c890810e4d04e784c2913c026642344647f8b97ea6ff7a0376b135dd1f9332887316e42da8ed32b42b1a42e4c5b4160457b2d898cd41b5df0ffa970183a59b26272002b2836866d32f696623a768116c2691d1666ac882b974e3cdd0d08e5e7d210db2f5d7349c5b130038e09e0a8fad2db1111d731944b3d6692671490a6af15cc69c1a29863b22e8a6de87239539ce0ceca541e6c4515821af61103ede0e3156ac71d3a29e3a8e4b84f4850b20d193ea55dc073a9d83c846ce3f55dc083ae93612c02f72117a4693a4c023f8e824b5500f61509094a89bab8d531ec8aef5291ac9ebd44cb0a2c9413274007488f32b12f459c5e10b849004902ac03273ce86a7a91a17ab46590ace5b4bd5333d8f5481e4e05fc94b5e68db79e30e6c08dd3c0578ec4fc0c55d6850313c8215b052a22d2f778dace1e33441406d5772a28a7ed892b867dd4c9e2818ff259e115bd4026437cffd7ef65dc4044e9830e64149e34cb695cddde34336b8bb40c00c15bfbdaded1593293a6d166ad39d8336b1178ed121bb13a98ea31a46d9f4817b3d8454e26bf405a32f51c15d1d419112ccd2af006e415bd5e3cfb67aa9d5ec64fc599b026934f7dbba1f4c120558364057a5cc5f901b2c0d411dcbe02342bfe32416277e1937e69a3e87f6ea0f214534f278a022231354653e3537e72b75923be4472a1275cb3cad4cf361dfe6be8c6fec69bd824f2a4d84878acac5e97287805279bdd92f48e8d1342f1a3cd8c711f837be0f188ed54071f9441b2b11b0acbc0c3510b4c4c5beababd27c7176f00c2396a3b81ecd9135e1f0171cd97976415671b28d63cb67996626f088f2de42125989581086dd29e87c6f4ee507537e2c9ac8e0f9827b9454770add19de3c3f8c093e85a93e9aeba6e157e38d8a42cb8893efc9ac78d79b9a02fc0500e4466a2942109de0f351ae313a534db4762802220ec7efd5bdc62ec04810e950dc16dc9f0ccafb6eb4a75db6f412ad3575094e8175290e70688f6780be7388846fc98a394c28ce11f51bc8b1cf54df58f06d4aebe2e185b2b48dd2d39483fe584b56dc1509c26ca5f89aacd27ba102232695a74e0613f91ceba0b385a0c59e60f24fce013b0646ba4d1e38e86a0962b065227b1f2a82e9d594e4125fa7660e7683a9a6d5f8ca7f9fc11f98828ab5f0edf94370e951c5e044190d367e4056ee54b97199d067505258aa5684db9dd24ea1ad52cc8744f5b2683584c131d244311a55985bf09c75d7237ab0607e334d6626278fb21a0150ebaa7ab0b78081bd43c706731ea3ccf9678822ade40320d51c040c9f1072c42562d18c894725ee7105da06e5b694420a639d67f8a1062491620238b0199b1a917b219049
+InA = 420c3c6b581c9f4466cd807170629a84b681aa1063a341062aa37956d70ae68befe87727d99fc92e7c29e215c5f13b722587c0d675d79190096a280a192aa4f4e65f982a59130f9266d22e4e8cd9ef195b45813cc8233a253f8a752548529b463226d3ebcf422870739095d567e7f6a512630c6766aa2668e8477a78865849e0b16bd0e4919d1d7da0c5d8005104e6e4d6b6855590e5c6a4e649dc4a0ef5b5ae140251c26b8c32001ed7ad13cda56b94c3294010c84ab54fba1888686384d40e310eb6363b9b23057782805f62e378c27ab98f223324add836772c3e81b8212bdae3c864a59c6e63a72327c42e69711ffcb3b6d04c00293e91d76c50ef9fdf33fd382c769835e0bd4821f65e66797075915f138a6b49051ec406ea750d50384d5d4ce2c9c536d45d3f7a704c6cae8d82f07bc5590f908b308d8c1b8d5e9ee3931d2d55145236f10688ae192f531755b310ccaf3891125af5decb1adbaa85224c47b73c3c8d7fa92ae1635d03d64d73c600486b336c8a511a7e1675a3dec9fcde711601ab73fc4d788d9de3d9f8fe185b87e920550d705f89f3188d1a69f9efc036666d7f5321d71b7eb5436f9bbab400884c08c59bd0a9458fe1e2b7b73d1e2a5ca4b21be5d48125613f0884d15eea9393a4dbb225bb66e5da5d3d98fb20c10761fe0efa5cf00498b29a662df8f8f17a4de3851fa425552aca9544aa89c89981d0f85636f67a862ee4eb844579f5c0f1b9bc0d647b15223aaf0c9edce88815273a0b064772b46dfc933a4dd8db90aa585097b2c6c0564ca90164a43d798403426544bb66637597dcf92a747b7b5ce1f7ba266f5c482d73e8f8b27920a627d1e9154ea745c213988f405ac2a19ec0a37388f8f67cbd9bd7c64222bd14a664eb5146a0645ccb542c21bde65bd2093a9b7622158a9504b0f230276ae1afd7ba6d7267a546e8c08dbdf168be439fe9263427752658d225a2062202ad567235685ab76585b04151f65a63016c9981a635116ab7766789a066d40d122805178f6840ec225e22dc5147d09ed9a53d8582e0e15b25b9a163178314205722adad9e9798c1306adcc002ab59e146302f0e08124945a18bfb10666c6b429124c5f5e61b98e2e8e6defd58b0dd377924f6a8d788c5887c306cf5864931b171936ae80f4911d483ccc804c112a0bc88a80621b0a1a9f8dd9f44f4f84687c54b533b4614d82741fb78006cdd137c422e5441c4513de3ae8a4cf4db9c679fb90c986f97abe8e1060d0392b668de010a0f9f1447445557c2f069f76e285a94f257ed368a70ae2922926c9452c01fa1fad6aac2db43daa67d68b31f3889acd8649a0c7389336d5d6904715984020470493a18fc84aa2bc61e352184714d0f5f46df0e3fa5a3a8a852f981135399d5df8d44b46abd6bfc164c4587e2a79ae255dadd09f964809c57e753105e2575bc987d924f3d7b9bd90747d1b61ce06a56ba60f1813463c418a3ad09821846b6c2b5057aca1939f255acca579b310fc91d112b6669088a66299fb227a7ca15c686604bf47c10d6c4aa1b56d03a7fe23217294866ea820646c372579955ccc16471159b83d8ba016c114c10c961221c28a956fce40806780e043883349d8e8baf8f308610be18c6103a454c8f30cb9465cc9d3be2935e347fc691a503b4c92d311d29abba18497283e646c3ab030a1dcfd295a29bc6517dde0cb295ea89639824c7fa99a968dd7a1aeb1983925258f3d7853517d6b5db4060783b27c949b80989561303d95cea8059e5e7fa520c2d3141fec406d88535d7060b1f4ebbd08cc7687e3d83040c97005d450f4405c557c9e0b71f047ffac98aa6ffea1f5598223163ea918ad5319bb919d9633254156aae2c527521664a6e54abae312e704b0fd335014a66ad8d22bc9862a0d239a9deb2a011553fe38f0100be4705f0a25580ade9b4b24705264326030b06d512f2d4c815ed36827d1078c57882369c1c2129ee1e1f8d51d45ab0d573820f9618fc2a45c25769f99ca51554efa5d086d039655b6a23874e18d02bb3b28a2d43a293b7e0b32d5c5000a222ddb92f945f0bc40a49427d8ab084de1e89cf9c70c9d39e1f902844811bca5775ad2f73ca884314846d474ef957a4d98eb4c98eb94f9cc6b6edd101b78d9a4b5986626752363b3e2c030bc5b0eb49e558d55ebaa92e1627cc166790aba847725bb487d08930714922d764eeae45c2a4157311ae4fdf4995c7781559cd149124a86843682df807d60ee922471be84d830e1cbed3055e281a19b855121977435f057000329a9a0458e51fca4dac4fa36303c02967d7551759b153f653ca653f7016d427ed7bdc6c49896741853148338688a62745e144c2840cb2fd22aabacbd6e7378074da23a68689664d5e804307beeaaef7454101d34c28441ee8456384a752992494ec2c4d4381c3ba3441357d8c545baec472eac58ca0f665992d64e1e1342c639863a09779e88349afa0418f667aebc22b92e7722e956793653992ab5768c170e8e564
+InNoiseSP = b1e6653ab5f2447f5ca626e751a87a4b61dbcc0637a84ff2a9eb2d26e99d642bb6d18b0f0c7f4b29a2a671a88f3723ec76fce25f3ac5c681d1de5909d68ca63991af658c4d1e6ea18df2e97675e4840fc5667c353d8d11a92f6da0aad1e4a104066bb3c82ea9fca43d9c837741010924e5cfc3a235045edf4bf2a5187861fa974dbaca44873e93f9b498f2129111978a7d841e1da8362110c1ba1cd9467b7e664d6485b63a0fa2555e51bbc126b811f19dca151df2bbe8675e992bfc4dac16c207044234120c36b94fbe9fccccd2d6ac293497260de16d0843d2679201520208705b9f1be4debb05893b4622bd9a56c0922bb72508b7ee4278f6410300ae47bba8b086c54a6fcb0202563b42ce667ce869cfa00e3041dc09f08d1a926cad88f5d88037081a2c98053aab975868fa5e4c3ba6febc2f469462ef95a05a8ea492c24615fb4b20699c187718065ae3a6ce3fe3ddcdf257661093d8a712a91aaefe6b17083dacb09011f580b23e6c05cf56457195aa2465bd32769c86d19146062a7a26a756233a301e3e31ccf33268003871e44549df44ba2f025f5a95f8356185e6935df047f3e05f585e515531653255770402ee467e696ec5992a24be84aa5dbffc081c118d865a03016eb2abe0b3ae9413e51971503f1ce58b88f194c1ac7378b7c62a48155c18355d4ea50f4d49a8756399a17717d68a76592d7c02024c7cdd13075b61b98d6055fc64990d36de2769e220b902544fff89bd3a6fcc930be2975c36c25dfe4a38243c95209b2784010a8ea5ae3af906058c563f51ca99b892d523f4a4fa79942a38539b6656d95582901cccb28d63ee45c4c13ef9c22429bd1c1727cd7b203f1936fcefe8d9da9016c58c8ba916e5624d2bb151249527a31f9a866cd278bce94791cfb1263fcd3a15e03a1e50420b157e0478818ae5968d06746ac14352740e258715f1a7a54c5d9849f61204bdb50d55ea545df435fa6efa575e2157b7eb5df2305512c4a91112422824c50411b1b4c5a670e9bb848c395f6d09215b30d954280a0ea720706f8bcc6ed6983ebcf95650d1ed163e3505693abb788879047fb088eabb80e99443120d6a2f166c136bda3e825292c815a668dfd74ea013e62da1a8e036c2c077b11a591a9ec195d3c02258fa817a5ee1d94b0fc4be254387069784b7358f0888dbba567a1db5372c24a7d66a315be8f16f65a46a08986191668b2249ad6d3d87240c4047d59f648a790a7536b9e145c95997058db3679ce3a3691b8f528c36f8269686835deaf32a080dc45fd8fbc1a260998fe9c58c832d52923649954efe60f2d059bc119e07b41917a60eb2a7ad1b84cc9c8a5df830f4a16bc7abad4ab0d5246c9fc2c2d0cd120657d25a3ace31e653aed39b822ea9cc37e6d67c2168c64cb63ade7016ee4a1679c25d1a947901bf4100dc6d1eb69ef88ba9cfd309a385af4baefbc8bb48861199bc810390446367b127921e7f70071cb36775a054d327d71b9d9879e82d1721a686118faf08b400316514d9008248b6375245464d89a6fd8be7725ee1bc6e51963a1a20181ad6eb54a76c019e2fe0c9a981381818d2f6de38011a2bdf2b7391b19ee37f1485e1715a17a3b9b65843470aa3d766f0b4b48a0a566ee8962fcd46c2dfbca77e003b5bccc45a53d874633e899363d497741282a33b66cd01bc306b310d442968121914d9c715f00c1809cc84460fb23c00a9c4b6cc6806cbe3198a9721bfb4d10f14572aa9406023abe1f2282d2cf6c1791a88810b5f8568b123e84144b6aab07657c1d57a473d53e54dccd32aeea0210e7f50ee098dd797b079eddd236ad0675698949f50ce5899dda92611df2b0002e043eba7f05a447e20f2d673c5d0e29b758ebf7959b168e1cb0ad218fe80861a4eb1c665aa7618c09014e893cac6d9487d0d5c8a090035f8c549a80af46158f90de1891579d50839384c4b3bdb66263463c7ca03257acbdfe5a233b98db00c412371bc32788bb9b536f27dc24c2e328f85287acbe2d28add4f4e4908b177b54e994521e53001b63dad66f82ca476612a47f690c09d1109cac06f510d684132c8764e88b0ea5525509472cc27d696412c2172996af3495285ebcbf0499396211d9a1183910262c267d020cf70a09097df20cc41a4d79acb536051b65ad12122e2586028547a6bc2420e97d6f4b6123c42229fec6775bd6fb6c51140bff9b2d19388a5554aa83316556109a544eb67e403a9d59a3619fafbce218b3e47d73829c65a196c87d66ba16079151887d9667abe006646ff1ea7b65ddb2ba39d7a6899fe82b6e8112509ea09fab937be208e6015029143688513836cb1016a12572348b997ac4a52384c60b05933e91650697203106467088d451e145ba368bdda6808d36f7d99120fb349300d949bcd8a18c5001eab4488dbc6ce5beb47733609429e9c895e749141238d044fe08a0d1b662b9e767a65a53767e6924d2d1a88eaab2b6e902309036a6b87bc0a7d9d1e81f8d56b9fac7361e2b837
+InNoiseEP = ec67edf27a627e3d6101bbf3f07462e567d1fb24819f549b56922c94641e03c5a90a9e4ded6385f1dea354a97571acc95144eccf6341f42cb8001ddbd2152e5fe9375b6cc01ff0a8ee6545dd1ebe834c6bd860565da3ff58bbdc4ad502de4b7f795ac8de9236822cafe0819d9a7a721c845a9133aff25ef3e75789927214aa0ce6b52591a0f1a104c5da1ebc4e96a65a5d00b4b65365a2e586519f641d17aae4041cea14573b448bda8688588f8495daeb90e1b704a6786ecfb4968682782947bae6847868ace2e111396fc3da551160d56ea6545ab825aaa53a282c2166842b710fbe331a65438b139d9b79815d6660081091f565d1cd65944b9d99429a9198aa2874818b86fb0bd07e16ee14980d79215d958a4ba4385a130c14f8871090deacfb4aa43a9242a09fa8549c19ef5b7139132c62d05128904d0e96e80e54c54a8627bb1b36e6aeb507fc49a8e98671727bc9bb932a7e0bc39e7e81e69e48f596cba6fc4984501a2d49a5be0309d8e434584669af04230797ec7aff98425b4f6a78f78c8455f97273b95e4f97681c11e35ffa533f887cebd95406887a4d78e9594694622d828ffa58516e986ae41f06b004adcaa4db09cf1e3829943859b50d6f5386e31643f210e3ab017b6c3d3de2699aa1a5c47e01907284ff5a194c2f0a743a6888041217e6d2c4584f6050f6665da7782a4a63bc580d1d421248f18940526d45c59e143c835e44e83c6a41b806840725ad43b208496a9ab14667598c97006c00ce0f8a71ad51051840f4c5a2b5ac240af17671d806181b9a6a831a209c52a4b1df3d7f591abd87e6ba422ba8fc77393ea2eb5ed786b6eea749e084dbee8519b5846530da1d0054d683591fda950c99de294471855c0bc774801a2debe19de54ae6a9da175d92fa809152e41ed5d521b57fd1e79a9cb8bb1ee678b4d204524ed97e093f3da40399a24ab468392403769947693182181c0b0c467f0329d7517292240c4a5616db815cdc82f929140d0a511b19407a22a7c2a1caa9783c5985d5947a6bfa5241631182eff0164b9f14602d7a13925146913f70083109e7b4582914821e532841e539ce5e826ad0683b62ee2ca51bca3cc88f1f27c5be927220c0c3495e7bd958ff10effe94d59fe1fadc5a5923e1301b1f4a125fabd6c4dcc4618ddfbf7b5f0ab37d9769a029c90f738a4c949b082a2f6276aa911a1a21cda9c2a2806c35abea606faab2b189420a7b3c48806d2393c9fe67176681490b4a9e340aa68b4dd4aafadd01c4d88c360019aa90ce59612cc30f6004da46ed40acd4a53aa1369687799f150516dee99820044e2a87683b12454afbab7a649498796f00d23314b062bae57a995ab27eafde22e3a4a240be4560821bb64551279b62f326a62adf55d8da21644b68dc93a8a5ab21e10304de99a17c666c1ae81a18d927ecdb9708b3c1dbf9ca21e55af3c3aab449ec089fd672fa3c3d38b82f8186ddf17ec5944c21de687ecae803c7a32a1c5f1546f6387eb32d1c75d006cd6e8b9c6d399c402c6c65e9e512628272e930a4c240989f0bb7fadad62dd4a9e4a4b9ca0c106a1cd8e7842ac8c0dc2a26f6b3f96b484861be2f0981cbf07b6a9598601285885924506d0b8b693a0f590b12a71de0674c2ebb85a094806c57b338b026253b881a34b5915f22d62ca0f231732a851c51295a66f6453865de154323960bc66f7e60c79a2615db49a2b7ad80647e007a909b129750581c1ba4eff7e79675311d3b0961ca335c9a9e54b59911894cef01bace82a6259643c3725d5f6eafc7de7225324e14035adc9f43dc586334dc1c1952ca861939a6f8cdb1f47f321d9be91372989d50b79dce772741870b8fbd1140f812a342b1606b6921bb8d3986d816197e1959c156318ca2c0eda96ba84f7cd2df147a2d3eee5472c548b066665b3a173e2c33970df3c3e25e043542585206f4250ec54978c398731983736165da2628c6d19a035a0e6e8e6147a59055ded74c146655309a28dce3b6cc5c1a6d18c52be99f74abe2f5534832451494647b4e2ed9931fc2fc2d530101ef97d92670cfd5d1d9b95412595a9e6871202e70ada42698aa52b181beb5fe260306271c8b6c5eaa3f257f5080f5866159f9b2470c0a83eda50745d02be4016414979a80be53da68a172882003b788b28a6abf4d1de8c850325f25c309e12c27d2a1464bfcac812e61960130bdbae3907904b6ba3d1ee35b7734428e3a86f6b1b6a079896622c171b29a87a899e12dc929dce6d669630276dba5ebe4636e36e940ea65fc7a2978e4f6d4660c532608f6707c81b15ae7c9787948ad1c6481e978100208497c19d69924e741393722b1880ddd94c2eb75b65b2fce25d63451eb1f0068debd8fa25383462f4295b3ee17b094693dca876e75091a019368388175f025594c8fd2f8a81244868f4229926fb2d4992519eca660accb71739dab701052929c8c375ad8f8763d58611ad8b4e394422d1aadc88055c43decce2a907fc8bdde6b5a5759bd9a
+InNoiseEPP = fbafff0b0003000180fffbff0a00038000b0ffeebffd2f0130000800fe2f00100000c00100000000030000b0002000ecbf03c0fffbfff2bf0240fefbffeebf040000f0fff6bf0180ffdbff060006c0000000fcbffe2f0000000300ffafff4b000000ff2f015000fcbf0600003c0008000600002000fcbf01c0ff0b000700007000f0ff06000340ff6b0008000440ff0b000400008000f0ff0a00014000000000c00200000c001400fc2f000c00fbbffeafff1b00fcbf0440ff1b000c000140002000fcbffe2f00bcff0a00fc2fff0b000300ffefff0b0004000180ff2b00f8bf0100003c000800ffefff1b000400000000ecff0e0000b0002000100001000000000c000070fffbff06000300007000f8bf0070010000fbbf00b0000000fcbf00f0ff0b00070006c001200000c00280002000000000f000100004000030001c000800ffefff3b001000f92f00c0fff6bf044000f0ff120005c0ff5b00f4bf0300001c0000000080fffbff020002c0fffbff06000400010000f0bfff6f000000fcbf0000020000f8bf007000f0ff0e0000c0ff0b000400004000c0fffebf01c0ff0b00f4bf007000000003c005c000100004000000000000140000c0004000f4bf0500004c00180005c00040000000020000300000c00180ff0b00fcbf04800100001c0000400000000b0000c0ff1b00ecbf003001300010000030004c00000003800010000400028000f0ff0e000140ff9bff06000540fedbff02c00380001000f8bffe6f00a0ff02c00080ff0b00fbbfff6f004000f0bf0040ffebfffabf01c0fffbff12000040ffdbff0200000000000000c0003000d0fffebf05c0ff0b000b000030ffdbfff2bf028000f0ff0e0003400020000c00ff2f00ccff120000f0ffdbff06000100ff5b0000c001000000000400fe2f00000014000180ff4b00fcbf00b0fffbff0200020001200000c0fbaf00c0ff0a00030000fcff020000c0ff0b001b00fcef000000040000c0ffdbff06000380fffbfffebf000000fcff0e0000b0000000f0bf01c00050000400fd2fff0b000f00040000f0ff02000100011000080002c000300000000200000c0000c0ff2fff0b000f0008c0000000100007c0ff0b00f7bffdef008000f4bf0280ff3b000400feefff0b000800ff2f013000180000b0ff0b000f0001c0001000000000b0ff2b00100002000120000800003000ecff060000c0ffebfffabf02400000000c0000c000000003c0fe2f00f0fff6bf00000000000b000280fffbff02c00030fffbff020002c0ff0b00f7bf0200ffbbff060000b0ff0b00f7bffe6fffdbff02c0faaf0000000c0004c000100010000080ffebfffebf003000ecfffabf05c0fefbff1e00f96f00500004000080ff2b000400010001000003c0038001e0ff1200ffef00c0fffebf0100ff2b00f4bffd6f00d0ff02c000000000000400030000e0ff020007c0ff0b000000fe2f01200000c0fd6f00e0fff6bf0070004000040001400020000c000100002c00f0bf03400030000800038000e0ff020000f0ff0b00fcbf000000ecff02c0ffafff4b0004000140ff6b00f4bf00800020000800000000fcfff6bf02800020000400020000f0ff02c0048000300008000070ff2b000400020000c0fffebffd2f00e0ff0e0000f0ffcbff02c00240000000040002c0ff3b0000000100003c00fcbfff2f000c00f8bf0600004c00080000f00000000800004000e0ffeebfffafff1b000000fe2f004000080002c000c0ff0600fd2f0180000000fd6f002000080000c0ff6b000400040000ccff1200ffef00f0ff02000140002000000002000100000b0000700010000000ff2f00ecff0200fd6f00f0ff0200003001000003c0000001100010000140ff5b00040002c0ff0b000b00ff2f0000000f00ff2f002c00f4bfff2f004000fcbf018000000000000500000c000000034001000018000480fffbfffabf007001e0fffebf050000e0ff0a00000000c0ff1600ff2f002c000400024000f0fffebf0030fffbfff6bf03800010000c0000c0ff1b0000000300001c0000c00280fffbff0600014000000003c0fdafff3b000400fb2f00f0ff020000c0ffdbfff2bf00300010000400060000fcfffebf004000300004000080ff0b00efbf02c00120000400ffafff5b0000c0044000e0ff1a00008001e0ff0e00034000f0ff0a0000b0ff0b00f7bf018000000003000340004000fcbf0030000c0000c0038000d0ff0600fe2f0100000b00feaf004000f8bf0100001000000008c000f0ff0e00000000c0fffebf0280fffbff12000080ffdbff06000380ff4b00f4bf0100000c00f0bf04000200001000ffaf000000f8bf030000fcff02c0007000d0fffebf0380000000fcbfffafff7b000c00028000000004000200002c00fcbfffef002000fcbf02400030000c00fd2f00fcff0a00030000e0ff0a0003c0ffabffeebf0240000000f3bffd2f00ecff16000140ffbbff0a00010001f0ff0600ffefff2b001000
+InRand = 51c3483b5f31a30d7cc8457959f83f0d3848d0d82a9af0371d9e54519ccc6e45
+OutPK = ac839551f2d26b42e6bab93668afac931834e5d0230e84f450cb25ae52a0e32850da5f44d42cda563e95a64f0e18636a43c50e0d79a7d69a15c5a43a9d2d8db99bd0a43d3d60cecd0ae499aa5c2280daa1ca09b927a8e84abd068e684d0f025d606f60632d85f70e7301444d1495351d018c690aa2ac9e8da8d598dafc87d4921adb9eec3818d91e981da53a9be7fb9053f5a0b107225bff688e01eb1dd0245d30fb2680b2baad0e81495bd21a0d5cf24b96b830b12971a0478902bd6277104e3b11e138b523e5d9d8d6bb4d099c66e92693371558b2ee3222f58db087a1ba2953c8a147b8b21714ece87242d47523c004071306b6eb14358be901b0a88d9e12ccc682d204533a2fe87b578b449bd88a6af1a1c0787a8914dc85ee81ae6cbd53a0f0cbbb3d7aa8965bd7c34c6507d3709211129d802c2eab3e3e1a589948130665b4ff9cb9a050701a0aa3dc62b4999b29a4b604205c0f995d27411260bd93abc5d2566a4b9141c75ba03e28e3223ed9a661bfa9589826a10d525b5332b59f6163ce559ac3cb9cb0352b55d633d5517885c0bb9ea5aeef9f0a586fc0a171ae5b5bf7f6576caa6067b76ab5682a8260d0be3c80219ec7746a9accc6ad47d2994615cae6590214b29f230cb881ec7d59c29be2c5380e3c15ef34a3543dc751e2182a4e397c6d02b0df746741cebc41e6d59f045e8a71086140c212aae224d53eda4812d3ee2c120ceaf7d82814a163dd23682f6902320372e3dacd1cdd4b2d835d493300ec572944d44ee0892d712c144c4706ac47a5307abc08f9f0fd905a6b26af28c050232fe707e08c8217774612e9d5e9206697b8612bf2bff7d50282683ca6d3ecb088bd3eb917e37e4a449a294c6bfa5b6519a0dca0101872c10efed1d9607b102cdacdd893c72e804a96781ad08c89966fb07591696a389948363450bbda9b903aec4d47be629143d7ba1b2f260b88dcd182d345aec4a928766c5bd89b35980fcddae4b80f322e9d2b87d0dd9539330d82c930b15e0bd9b05a73fe6426e9da685b540e3c1d35448aa4a0119bfa30c6326877abf850ed1822ae000132b1501a69865329c74a2b03eea490f6fd1891214d73ba6a4ca5e0db87c70c63a619f7075d348969eb46bb9f5d34926df75586fa49f3cc3975053eba33107a714d627075883bc44f6267ce16971ac5f0ad3c481f421afc9c1a12aef556392d2497ef884abc7a8b8fde85229d42896abbe913b23ec32a136ae3117fdbeca943f91db8c5c41d0037e8a7bf42eba1df45295ed7cc876cda4b07e25106f97435614200e2a74c5781987770c2d0157e558cb64c20029d6774853e2c5da3da0a0973d4bd53e35f96c171002e4312fa6c518fc909690b8fd06436e5b8da9dc297c8cdb7146daa29ad15eefb0f2168b8a3a6c7243a8714106d35adaa29206ad2509ee61f082c5739385d9fcb0b2ab0f5fc8dab55dc670484871c69fcd361987ff1cb6797ae3e51d9974ca6b5087f9a229519e9008ccbef4ab6daa24fcae95be3c4a1167b5e1c460da56b642362e7ed8c7eba8100d793e52bab2082b40e3d8340905dd4dbf660119081160739b281cd16f7a8bd020f69e06aa79505870771fa4219008b9d1ca1b0bd28afe029f299e037dd82c0aa17781009591ce628242f74a0ba1526c100e26caba892868da9680b07904545aeda84154384886a4d55118e7948fa2cdaa586f29c25e4fa317ecd3a995c793921106a7d8dc3b2fe3432214bb339614a579661dbbbf07104afa6ad0201ad4b6fd80e90427e6102eb1c02c4d62fbc25464760b6368da0fcb26cb5903eadf6d284328d9867ce610a026d65c1f80a4c7482799e1d3827f945dc6f4a49d6e6667ac5ade72d8804a81830d49c85bd9c431d38372a90198463d2f17a10f1961aa01d0495bf6e8c098248ae5d0740d7c7b266481438e49bf44edf5f9ef345920339a60495c70613aa2ce2988ca67e66572267dcb1aeeaa6146a2a6e69bbe60243fbe2141a6ff802bd581a4d8b351558608ad1db2f0a818c7fea8b49d3e3b17779ce6b5a84a100f368826b15462f0b9f466a947171ac8c0f214f5e25d2c9fe3374e4b121c82d26b45a6fd122662880966b07ca3ea54d1a6c98ae4071866a2c028bd745fd5c91eec2164bb00c1d19131769d196b8f513cec2dbdc562ca2d82261860115d693e232ada6f8446c073e4c1529d34479a5640c648b0b74d1da3a480941ea584d42608bb8e7ddceaed49a9d81d30654866abb70e1924db0c615932f463b749253a4981050ea498ada4edd6728a44538f7982e1b6927d637da0ebb593aa5fa1813c7834027309d1212c7fa29f7204d1da46de261250ad8c0bb725f46742c14f0881d88702fa43efa706406e7c5082bd82a03c92240a01c115a6faef5830ab109491aeadb01ec562b67fc5ac3c529a9db48369788369013d4d298ac375ed33e44371a31b21585c7112c85aae85ea7206c28ee48a7c253561efd56d7652da8b72d082ed40ebc595d6bd2942440ae674804016a6e5d
+OutRec = 0040001000040001c00010000c0000800020000c000180001000040003c0001000080001800030000c000300002000040000400030000c0001400010000c0001c00020000000034000000000000000002000080000000030000c00018000300000000140001000080001c000200004000380001000000001c00000000c00008000200008000080003000080003c00030000400014000100004000280000000000002800020000000030000000000000000002000040000400000000c00010000000008000040003000080000c00000000c000180002000000002c00010000c0003400020000000004000200000000300002000000001c00000000c00004000300008000000000000080003c0003000000002000010000c000340002000040002c00000000000038000100004000280002000000000c00030000400034000200008000280001000080003c0002000080003400000000c0000800010000c0001c0003000080003c0000000040003800000000c000280002000040002000020000c00000000000000000100001000080001000000000c000340000000000003c00020000000030000000008000040001000040001c00010000c0002c0003000080002800020000c0001400000000400004000200008000380000000040001800000000400014000000000000040003000080001000020000c0002800020000c0000c0003000000001000030000c0001c00030000c000280002000080000000030000c0000c000200004000200000000000001c00000000c0001c000300000000140002000080000400000000400010000000004000300003000040002c00020000c0003c000000008000280001000080003400000000000038000300004000380001000080000c0001000040000c00010000c00028000200008000340001000040000800020000c00024000000004000380000000000001c000300008000300001000000000c00010000c0003c0002000000003c000000008000280003000040003000020000400034000000008000300003000040001800000000c000300000000000003400010000c0003400020000c0002400010000c000140000000000003400000000c0001400030000c0000c00020000c0001400020000c000300003000000003c00000000c0000000030000c0000800020000400028000300000000240003000080003c00000000c00008000000004000100001000080002c0001000040003000020000c000280001000000001000020000c0001800000000c0000400010000c00030000100004000080002000080001800030000c0002c00030000c0002000030000c0000c0000000080003c0001000080001c0003000000000800020000c00018000000004000040000000000003c000200008000380000000000000000020000c0001000030000c0000c00020000c0003800010000800004000100008000380002000000003800010000c0002800020000000008000300008000340003000000002c00010000c000300001000080003c0003000040001c0003000040002000010000400010000100000000140001000080003c000200008000100001000000001c000100008000380000000000001400010000400020000100000000300001000040002800010000800000000200008000040003000040002800010000c0000400030000c000200001000000002c000100008000080000000000003000010000c0002800020000c0001000010000c0002800000000000038000200000000080001000040000800020000c0003000000000000010000300004000100001000000000800000000c00008000200004000040001000040002400030000400038000000000000140001000000002000010000c0002400000000000008000200000000280002000000001c0001000040001800020000c00038000100008000040003000040002c0003000040002000020000800030000200004000340002000040001c000200008000300003000040003800030000400008000100000000100001000000000c0002000040003400020000c000100002000080002c00020000000014000200004000000000000080002c0001000040000c0001000000000c000100004000340000000080001c00010000c0000c000300004000180003000000003800020000c000080003000040001000000000c0001400010000000010000100004000240000000000003c0003000000001400020000c0003c000300008000100003000080003c00010000800038000200008000380000000040002c0001000080000c000300004000280002000000001400030000c000040000000000000400000000c000140000000000002800030000c0001c00000000c000300001000000001800020000000018000300000000000001000080003400020000c0000c0003000000002400010000000008000000008000380001000080000400010000c00
+Key = 11e452a7b206e159ac85ea8b6553d01e246d084cad52fb7b29028d79962091dd
+
+InNoiseS = 2e6f8b71cc4ab67f9816984bce92458263794396bd66ec320565045122d1a427408678dc565386f2f993fb14e1422366ade64536811cf943271a185b747eb2d62d13b6d5028b755179d538f915bce3fd7b1e4a2d6d4e6bf29d06554a010502a70a516fd7c6564b323723eb2a8570ceb98603208a349c685ddc1366b55da84b801ec8a5ea3882c6668a394d98b4a1036946ad618f1cf427a9a05676dbc615acb25c53cb83a117964065618b213f1e4851dcf2663638315859704a44b5785bcff0f7fd2a6eff292c2950fc817d5a4b7bccd014d95c4565abf86a6e8cd2b32e9594482e46e505e57932d30ed6639853c74ff2138b122fc46f54c183f11858ebdb2b871ca916109922ea7e3556e63d95028c62d2652c0b9f35af121da795121d5872043711b6a56639e169eb41d9780f6462d140cc7ddeabaed49d9c4e4284d07132d92fc39b98a5c5cd278023e3a1fdfd8875e0a7a2effe4dd3e2897be58520d99c36308caead22987d959a480db2cb76488cf14e4c9bc92887d5107c6df91ab69abd9a11a50a91b41138c22ed8281c58ae49a512c5c203f563bc7950147ded01a7078f8ebeb324e6e305295522df6eb91035ace84be894fa824fe6415b664e1873f3a4ace6f2f5aaad6d121a489688d3c7d307ab2414b79822305f8842339540f42e089df2c1bf0620ec7a306f36b2d4b27c72439875109d6dfbcbc43358f068108555e0f7e2b047140a589cc4be815227c9a29eaf7914e381513e5d9d00fd3296ee894c9641d2b00e79f62f2f62d8b5ade28bdc26fc6e3711c2fe3694ec9c461e28b5524c59fd2a0ff2ff599c04d8b882f23a5ecf917d080130214c262d3826a616f093acfb64fc6c9c82c36708a628c652cbf0ec8911e902caa2e805268b8144e595f1bbfcccbdb8b7a64af5e101fb113e8abec686c1ee7c2a539593b6f80549be9d8b814f360d71d6bbeb569db2e94d52405b8895da9a02495a01ac93ce9847503e107f6b81fa598c539409a7873af606315f82b9eac49b68a6b9f214a84d58083e067edd52d167d1ea65969cb7a40299062a732d2fbfb26139570c97151187741b9d020113651e2ed0cc279893348b2592531a6a1874c317ec638b42339890205705a52099aebb745f2689c54954f32620598048557aafd940650451b5a0e246f683e507d72080ac8b92ea399023f4ca93dbfb54637cd0301171d124d34a48f0db1a2c5f5ae5725271249a1198347b724b22817f649fcc4b02ec374b10b0524e08a9a41771741c2234d6324856c1aad86051d831e62333162aa2a32905d618e76c353a496829e3cc7a07a66b975364907e6da5d983e65004a392b1b8ce692ce1b24030a6756d60f6972a2e8aefef7d761e15645043d7720d1d756d1713b06c16712716f9204e29b2f8a45172b0498328a0d1b8a7a664079123b9851059add99e2209b4911359f42659e24def8cda7bd4da1ae34fa7669f8218d786b8b9ca16520ad54b5553b92cc99541e6f51caec0176729687977979c4726abf5321344edd66f0e03bea512c6dd54b9d6c80f932d4e58e75f8bf97b3e0e15e412704b691334d10541cb7037eb653f084d96afa4c3ab78d2468e4242fbdb24b05db81815280ef458871dbad0c938719a855d80c3392506ac313b755e13e6d587d0e9c11775e8d588cb048f60c64c564024570b474ab83d9a8d2fc7a0eb465803aa2b643a15c59e3f156ad133aca6c9c968d1493d601fa59591c8d0aea49a697a2e7426c36d24f343b292ed2201bb1f2638a2923c8220e0321f081cf465f98b5f69ff3ab78574646e828487f40c6f4d7c28be30391f083e78640a28f7066ab9aac6138a106dc9c3497c38efbcf007062de29a4b7a38397d0305a04b5fca5f51ddf6b026dd9aa1ef88a394aea54f20be3800d488af630522dfbe8306a10f7178ce06c097a3d7ca62b7169365486b4a23c52c1017fd4513268e4a20c5702b8d624d028098bed550389ad8b987c26a0a0bca7478f3c8b5a4c926a2c10c34662de11b7a260539727e75304c0c28b15e7cc6105da18ab6ba720eb6e0bfce3b220f7f68bcbd845ac8c7d166a837c46714721c227b5bd263d2a6fd54c7a7f26267597953943ef22cb9607f65eb829b5e4ae84b1a263c69a77b16827a7dda44bad604831dee420100d2ab45d822cca55378fffc7377d57c381dd92661eb2271599a68f4a5c4811ad16f27c16103ee9e7a802e9011f7fa542f4799d65c448245424c9698fd3d10cde7cbcf6885f6d630e1a7248ca7ab16b6cd8d262e1cc20243d46c5e1c2aa508c22b6aacfa0a4b8c60e2056bc3365c5f3acc45c61b2d12778bdbaac7744423af4b32f52eafd9a7835400ae42d424d8a46c0c03acefe9a684f903f5c8761616cc82e05de264cb7278529f3c3255b8095f64a2f3f5299b3365efb356d856b04731a8c77845336db8c1952a6ee91b64578d620af6052a700989a2338041e767098c996ce97a6f9907c284bd4acd688937617003afb95af11447629d71222919bcd5b4204a
+InPK = ac839551f2d26b42e6bab93668afac931834e5d0230e84f450cb25ae52a0e32850da5f44d42cda563e95a64f0e18636a43c50e0d79a7d69a15c5a43a9d2d8db99bd0a43d3d60cecd0ae499aa5c2280daa1ca09b927a8e84abd068e684d0f025d606f60632d85f70e7301444d1495351d018c690aa2ac9e8da8d598dafc87d4921adb9eec3818d91e981da53a9be7fb9053f5a0b107225bff688e01eb1dd0245d30fb2680b2baad0e81495bd21a0d5cf24b96b830b12971a0478902bd6277104e3b11e138b523e5d9d8d6bb4d099c66e92693371558b2ee3222f58db087a1ba2953c8a147b8b21714ece87242d47523c004071306b6eb14358be901b0a88d9e12ccc682d204533a2fe87b578b449bd88a6af1a1c0787a8914dc85ee81ae6cbd53a0f0cbbb3d7aa8965bd7c34c6507d3709211129d802c2eab3e3e1a589948130665b4ff9cb9a050701a0aa3dc62b4999b29a4b604205c0f995d27411260bd93abc5d2566a4b9141c75ba03e28e3223ed9a661bfa9589826a10d525b5332b59f6163ce559ac3cb9cb0352b55d633d5517885c0bb9ea5aeef9f0a586fc0a171ae5b5bf7f6576caa6067b76ab5682a8260d0be3c80219ec7746a9accc6ad47d2994615cae6590214b29f230cb881ec7d59c29be2c5380e3c15ef34a3543dc751e2182a4e397c6d02b0df746741cebc41e6d59f045e8a71086140c212aae224d53eda4812d3ee2c120ceaf7d82814a163dd23682f6902320372e3dacd1cdd4b2d835d493300ec572944d44ee0892d712c144c4706ac47a5307abc08f9f0fd905a6b26af28c050232fe707e08c8217774612e9d5e9206697b8612bf2bff7d50282683ca6d3ecb088bd3eb917e37e4a449a294c6bfa5b6519a0dca0101872c10efed1d9607b102cdacdd893c72e804a96781ad08c89966fb07591696a389948363450bbda9b903aec4d47be629143d7ba1b2f260b88dcd182d345aec4a928766c5bd89b35980fcddae4b80f322e9d2b87d0dd9539330d82c930b15e0bd9b05a73fe6426e9da685b540e3c1d35448aa4a0119bfa30c6326877abf850ed1822ae000132b1501a69865329c74a2b03eea490f6fd1891214d73ba6a4ca5e0db87c70c63a619f7075d348969eb46bb9f5d34926df75586fa49f3cc3975053eba33107a714d627075883bc44f6267ce16971ac5f0ad3c481f421afc9c1a12aef556392d2497ef884abc7a8b8fde85229d42896abbe913b23ec32a136ae3117fdbeca943f91db8c5c41d0037e8a7bf42eba1df45295ed7cc876cda4b07e25106f97435614200e2a74c5781987770c2d0157e558cb64c20029d6774853e2c5da3da0a0973d4bd53e35f96c171002e4312fa6c518fc909690b8fd06436e5b8da9dc297c8cdb7146daa29ad15eefb0f2168b8a3a6c7243a8714106d35adaa29206ad2509ee61f082c5739385d9fcb0b2ab0f5fc8dab55dc670484871c69fcd361987ff1cb6797ae3e51d9974ca6b5087f9a229519e9008ccbef4ab6daa24fcae95be3c4a1167b5e1c460da56b642362e7ed8c7eba8100d793e52bab2082b40e3d8340905dd4dbf660119081160739b281cd16f7a8bd020f69e06aa79505870771fa4219008b9d1ca1b0bd28afe029f299e037dd82c0aa17781009591ce628242f74a0ba1526c100e26caba892868da9680b07904545aeda84154384886a4d55118e7948fa2cdaa586f29c25e4fa317ecd3a995c793921106a7d8dc3b2fe3432214bb339614a579661dbbbf07104afa6ad0201ad4b6fd80e90427e6102eb1c02c4d62fbc25464760b6368da0fcb26cb5903eadf6d284328d9867ce610a026d65c1f80a4c7482799e1d3827f945dc6f4a49d6e6667ac5ade72d8804a81830d49c85bd9c431d38372a90198463d2f17a10f1961aa01d0495bf6e8c098248ae5d0740d7c7b266481438e49bf44edf5f9ef345920339a60495c70613aa2ce2988ca67e66572267dcb1aeeaa6146a2a6e69bbe60243fbe2141a6ff802bd581a4d8b351558608ad1db2f0a818c7fea8b49d3e3b17779ce6b5a84a100f368826b15462f0b9f466a947171ac8c0f214f5e25d2c9fe3374e4b121c82d26b45a6fd122662880966b07ca3ea54d1a6c98ae4071866a2c028bd745fd5c91eec2164bb00c1d19131769d196b8f513cec2dbdc562ca2d82261860115d693e232ada6f8446c073e4c1529d34479a5640c648b0b74d1da3a480941ea584d42608bb8e7ddceaed49a9d81d30654866abb70e1924db0c615932f463b749253a4981050ea498ada4edd6728a44538f7982e1b6927d637da0ebb593aa5fa1813c7834027309d1212c7fa29f7204d1da46de261250ad8c0bb725f46742c14f0881d88702fa43efa706406e7c5082bd82a03c92240a01c115a6faef5830ab109491aeadb01ec562b67fc5ac3c529a9db48369788369013d4d298ac375ed33e44371a31b21585c7112c85aae85ea7206c28ee48a7c253561efd56d7652da8b72d082ed40ebc595d6bd2942440ae674804016a6e5d
+InRec = 0040001000040001c00010000c0000800020000c000180001000040003c0001000080001800030000c000300002000040000400030000c0001400010000c0001c00020000000034000000000000000002000080000000030000c00018000300000000140001000080001c000200004000380001000000001c00000000c00008000200008000080003000080003c00030000400014000100004000280000000000002800020000000030000000000000000002000040000400000000c00010000000008000040003000080000c00000000c000180002000000002c00010000c0003400020000000004000200000000300002000000001c00000000c00004000300008000000000000080003c0003000000002000010000c000340002000040002c00000000000038000100004000280002000000000c00030000400034000200008000280001000080003c0002000080003400000000c0000800010000c0001c0003000080003c0000000040003800000000c000280002000040002000020000c00000000000000000100001000080001000000000c000340000000000003c00020000000030000000008000040001000040001c00010000c0002c0003000080002800020000c0001400000000400004000200008000380000000040001800000000400014000000000000040003000080001000020000c0002800020000c0000c0003000000001000030000c0001c00030000c000280002000080000000030000c0000c000200004000200000000000001c00000000c0001c000300000000140002000080000400000000400010000000004000300003000040002c00020000c0003c000000008000280001000080003400000000000038000300004000380001000080000c0001000040000c00010000c00028000200008000340001000040000800020000c00024000000004000380000000000001c000300008000300001000000000c00010000c0003c0002000000003c000000008000280003000040003000020000400034000000008000300003000040001800000000c000300000000000003400010000c0003400020000c0002400010000c000140000000000003400000000c0001400030000c0000c00020000c0001400020000c000300003000000003c00000000c0000000030000c0000800020000400028000300000000240003000080003c00000000c00008000000004000100001000080002c0001000040003000020000c000280001000000001000020000c0001800000000c0000400010000c00030000100004000080002000080001800030000c0002c00030000c0002000030000c0000c0000000080003c0001000080001c0003000000000800020000c00018000000004000040000000000003c000200008000380000000000000000020000c0001000030000c0000c00020000c0003800010000800004000100008000380002000000003800010000c0002800020000000008000300008000340003000000002c00010000c000300001000080003c0003000040001c0003000040002000010000400010000100000000140001000080003c000200008000100001000000001c000100008000380000000000001400010000400020000100000000300001000040002800010000800000000200008000040003000040002800010000c0000400030000c000200001000000002c000100008000080000000000003000010000c0002800020000c0001000010000c0002800000000000038000200000000080001000040000800020000c0003000000000000010000300004000100001000000000800000000c00008000200004000040001000040002400030000400038000000000000140001000000002000010000c0002400000000000008000200000000280002000000001c0001000040001800020000c00038000100008000040003000040002c0003000040002000020000800030000200004000340002000040001c000200008000300003000040003800030000400008000100000000100001000000000c0002000040003400020000c000100002000080002c00020000000014000200004000000000000080002c0001000040000c0001000000000c000100004000340000000080001c00010000c0000c000300004000180003000000003800020000c000080003000040001000000000c0001400010000000010000100004000240000000000003c0003000000001400020000c0003c000300008000100003000080003c00010000800038000200008000380000000040002c0001000080000c000300004000280002000000001400030000c000040000000000000400000000c000140000000000002800030000c0001c00000000c000300001000000001800020000000018000300000000000001000080003400020000c0000c0003000000002400010000000008000000008000380001000080000400010000c00
+Key = 11e452a7b206e159ac85ea8b6553d01e246d084cad52fb7b29028d79962091dd
+
+InRandA = 16598e075b0e7c09cd899080a945dbe249066492b8c9829f42e7d131c5017540839464989c68ba38dd2365e97c6b03c83f2fa68c84cb8c70a05e961772ccaf358dbbea4f043fa5d8db73c062932cce55f07ec98cfd84b1b2d13c33e94d94a616318b1e400f42b7424e256655d1d810114842d92882dd4d286a2f9ae8e065bac291bb133d462c531c4b902a664d5d31817828ae784b9dd1cdf193824f5578345a33b34a07e7add5246d933330f9a25b72c79f57920da7be25408b26b42a142248c4bec048ada2ff02fbd9414ac16c490ca636082e27c7e502a3a027c822b0bc558d0a48680d89ace313195b8bbd5e7d144d394890594a07e8a6f266562c628744a1e85492e97bd9444d7a69dc74c3005053d81ce2f358d54c84159f48c0f26c3e58aa2a3fc012fa5ada92e0ee63a39c189b61b129fea5ea2243e077e598f9e2dc95a8e31c632ab1b975740685e5d389b785cb95e572e6951f11e401d598b359464a0645882375c667e416c4b2b684269235a29890d85cf6c16c554501f709d09654a6001ac7a2ae52e3c3f275e01eb0366ff80bc34d96a6a877a925690ead51da259710bbcc1c4675b9a97ce6e8b93b4a4c93e7d95ba2ca42adc3a0a5431b05b0e818a04a655db5986514d3b9b905e50c0e9919818efa1d867ab90e190b0fd55704f18791143822a771711289a7009d2c0eff5e09f99c520ce791ba00c8046a0f5e2f30af489c565229f99bc66a42608345769a353f4079906d6d27334a5b11eee821a398b56ab310791d86d5b2925c62ed2d17e28fb89720d180654c394de526dc1558545a796807d33f86ae96953d06dd2a5913a0b9a99846960ac6f6453a125eaa0f4e475a82149485569bd5261084e76dca5291548ccd22f4a2f218d5084342387c1a78a04403c1b8215a9899859e5c1c75e359cace8069e4c85aa8b6a846218a4338ac58447758cd2807c8b1cedbf0319fba190d49dcc554788558c943c65ab65edb113e3656ca1ba6c6344910d26a441f41426afd7bfa103353037057396ad70237d854ee80661a406d0b85c29bca460cb44b5e90e500d10c9dd106d1a10d49b4046178ce003b18eac14517c5aeb2854ef8fcd6362a0e3513cfd24c1f151045f0f1a7fb1554283a5682ed6e75f1a0edbad88f822632b90be8d458c6dcbe1f865f4b265ab27e2fc4bec75eee311261e3f52264014656094205b193315be6a3e5114663429e8823697d504b71fa9ad615acdd36625720ab40956501d998a3fe8037c7bb75032a4d53767b701ab3c150179bd50aa5553a4a272e48c71539d7da256e041ddd9a85b0a8d9dcdbcbdff94d80a4d8e5cefd292fe938f04cad77ba2ac86b57dc5660ee05f7220812ba6a70a2ca1cbc5f1736a5cf293f1acf96268df65e3e92362843d81337c88053aeed7ab2831b98f8494190eff3272d687c171af50468c49578a05a7be6c237460f93f9ab7553981761d483064233e7d4fad5104f5b001ac03ede1776ec0096ba323b765ea74a8c2d9a0d91e130ac9a4807dc6a8376fc362f4645d614d80f3f55e2cb49866a62ada62ae74d9288160bd5cc1d49b88a3326c5f447f9d47405a1b8b9eb23bd03c03e207c09cb59cd4dab8755d8d016bd198e45d1d5ec6017a61fed12b719970fda2a89874662a7e16ea11b185377c37977a1ed0af78fa3042dc17e192e4b3b2f7212964e36d357555d445348c2759d8e3bc1ba94d9e047ad8a40a05bae9f918187039bed17086ea457d1954d4c5575e9ca58040c129bc6fef20fe628d6d8eddead751729fa7d710802db77c1cdc47176512b098fc524024448230e4e95880fb5e375fa7f8300ff67b05861b605636aa04c167b4700b50656054c4ca323534921679aebb3be185412cd9ec0218046e224cd1b886d6a74d0e4479fe502d7038ea08a9a67da97eaf09e59046f6efa65348085d80d1832ed720eefc294365dad860b4afb412a0d7109e90f224cf87fc84338e15ad99e4d523651e0202aca201e98c9e440a4a07274c8dc95146a2e37a8841b6b6d48431f88373ecb7ff13b2c1c366aacf477e58a33af37c3ad1e8e708a10e5685878ce5db4074838b68907176239b6bfba643d88aac92bde285cf142952a135fce2308d9bcfcdb21955eb0342b6f9f18caf8b6f408c6c15cb976108097ba52ca2af509b489d379b27deb0470e6c40cd62021a74cedaae3dda546f6b86c1e5271d011d9145c55d407b359141d5cfeab5c820f221d199764fa369242efdae1210dd7e4cc66c3deb0ba8442bbd27c0e688415f2ddb961e72044b8846c911816b87384260dc81b717a5eed06724e8d5334008fcce70985b3c29166cd5f01e2901f44ce0f75ce0038d48353c2e7512bbc5acce012b90984d2558386a2a33a2e69a3c68e3daf841876a4a668f25cb061b1dc289c863b050351a0ddd787e3f9711d92e61037f180b0820adab8afd5a5fd2e7f198e6e1b9c8291012ef543585371128c62917167ba43a96aa42b296958753a91d16f5cba922d58cd8d2d1621922d
+InNoiseS = 819fc864be3149721adb2aafc882e380dcf06d756412c8a01283e20e6ac1a396c0e14228016352fab19a6b41009a054ebc5ad9a4dbb34014e1df2a7388be6d9593d71860109479801ea9c464ba476edb713664a3245822999c2d8490db2aa7874aaaaf4cc0a1a3fc4617ed5c86f25985078fe7d6f791984d55944621aa86fa6d07763f2e57122e50d89235b3a5ad9bc47684b5f1a0d9005b059b70038f319e31137bc116d7229cab130a331403eaa76aa2a5225b7c9e7f57470b029ebd8a402f55a83e10d6290c391cb90c549c1de65bf83ac64253674c2804701c5bb1e616bc806b72224d8d1c43e049ca146cae42c75569c6797073dcde9028345ce38021a535daa7288018e56b16406a4e8869bbc656070e2699625d14ba996e81431a2d0a14e2405a082e40e13fa2b37a1ecf9a3923a68e1d990b812a1ffe9a674df40029747d846ffc894238b9279901c21489b975aa670448a4766a484918ed7551f9ee7a66bc26b88b002c7bd8f51f9b8c42a8e3ba214815bd687648459f10f2a391856ec3c5bc1a358980b1aea10ab26e430663ecc38018323f2c36daafaa1ce252774913ac30b6d27564c5c20e11e74606b1c1075ba60e451756591d443ec60ce49398d7b4ba3dd000630aab95b8111652e0c110fc04059a68a5c17c5e0a8382f3a32de475f01082a2fe62264b6841a44da669475348dbfda93a9304c502abf4b1710a5b27cc39a8f0e705a4633c5fc65951e4c7f86525c0d760079a75aa587a32ff0e9b82ccfb324a7e8abe9eadb940e10da2ce00f82362b26e8447a1eba21643c0b0e02a2d1190ef51db4a5969aa5c50d2bbe64d8fce2186f2647dff4aea76b78d33fbdf7d74bfca0cb20125eb5a74b1b26d68e3531db09f634bd134603438492df7c4d1a7402f7559e0a4ac8b8e0c417569478eae95226a747d7ead94390c5633041b27559d1e27bfe9104209897e3700edeba72d6f496cd87b7d446a1569b490dd8abadea4096b67396ec8c269bbb7f264bc9d9af9423829a149c3433b215528a90bb1a44878a2c84a35e23220eace1072dbb03c7c1f6059da627e9ca408c572b03ba1ee726739d8b32229f4ebc87c9b7fddff1652a24d02868c50f7cca61da9fdcabf6e733a1d90fa49d66fe8e73d80b0b6a567ace5b62b4e12cf1c5e738199881795ceabe2a517ab2009a90999ac002a40147ec93511e5b484b38213b09200549e1e386b9aad924605721498c0c2105a5129c0877aefdc25319380735eaa680a97c0b51abca6605a9af4d9167e87cb14a6c7424b4d427fe4db4e5fe9867004833a159069a3f6592c232a4e2db38512bee2a9b991d415352b26d83115e92d6567e0d943c67f8ae7b694c1e6beb1e857267311310426713a842e46aec68c0b4e9825a3133273c76475804aed47f31c36f8eba860a600967953152372cc1cdf893e325ec92d14ca45a9135a9c5b5cab4413fdac9f90cbd74be6beeacb6b248d328f081efbe6f268672cc244c04fd6509f2df12628b4a1c9e614eb1c6157d8981e9a6a019e2cd745733765582e92a518b2785056c7e932fc860f162c4c62e738baef86e588e3155515e0fedb0bcd997094d93b122d7d54c01296704e38b4ee47d0b67d5cc784f95a3b845969c1cf9ae3364a314f8aab0a19279c1784f6dfdc77c4e65fe5f43a77a8cabed319cd69ce96ebe04b254465da81e561103b242a2ca971927371d985327b850c998965327d18273f66c4f98281070e940ddbe46e8a4dac8130c4690b561f7193b3518cc464f096e720097dab1a17b4d4bb2ad6abf84b39246f470fe4589410a52888c6c00163d16df7c2225ea8071b9154a0fa340a29cc4bae8a37640c86f9ee7ebb1fda52040b09979a85a1b09f5432c884296191167e1802949857d1490c862ebaf40104a9cd22425338a27de46c08e34299090679fb115d473947831052dd883805d70625944e1723de9217857ab05aa2f70461982527d7d07db403b960800991fa06d7299a77447043eacdb52036082403867f0a182031179cedf1de9d0a5da71782718d6c874dd359be309f7090a94835e10f732c9dc9dff59abe1ed8441680117811f2d909d53a29a26bf47756444424f548e89abebaa25652e10c6373127e489d0d2123e278d05c842ac99ec321b6ed6af94eafc6216a54f62f00e0dfdd44b40eaf85cbed5819c0e553537182b1d9f9548c0e08845ffe8aa53631f76814d759a55fc9d020d2148415b61634864e6e590f5fec73cbca732c1fd19329d90e7821dd106515442d4698b957f697b2c9fb652826283287a064ae861c9c96c58261c20c51d642c5e0e09e84288dc2fd16550787a8d6b1929adfeb1b2392854977ade19af270825f9a20c6c2c5685b08b4f7c27123494a0365bdf50d8acc29f53afe2ee3a743c0b19d7d6613a39a19a20884d98086a5ae633e1a150a2fe2ad5853614b3ce94fbe401be3223d260a5a6994c321366e6daeb06f166989acf825aede985d4ab7b1948d81f7eb27e946948f5dec13765bd203
+InNoiseE = dc9f14a1206da08c2b96b75e5d74d3c5c6b5f5583beb6d67d5db42b7529d062a43192d945a769500e257641e1eb74db99eff89ce0812c958738c45d753c8389d535e1595467b57cd6e75ddf9ae2eeabec6d119545bee4a6196916c14ef934756eaa4d015a783ae9940728d687223447c041c8f60fcf4440cd1c9f138724147a17c2406e57b5a054230653890a014e2200fda3ed3ad0c53ed18aa00a861b66c0c1be983737326320dcc84f914fde4157c48aee7686552c2261e580d988677c1ea18d7e04b711932d0789075b3d67ef34b1e1745c7fc597dc422258faab8edd85d2917b762136a62d5a61df989629f3996cf24d7d240d4d2e5270b5927b727a242f16584c15a142a5fb87b955c5da059b82bdd509374d53e90c5899504c506979f4a000287b8b7f3ce8d64bd066bae117ef3b4cc0caa97dd8614f02cdb57559a11bc222e5cf882026c3597471cba5cb653c665db66abe67073cac8d2c8325d5cc5d259a5a88a1a03e6f8d7c9a7991b83f2fff57054acd8e0434d1729989d0b7b4d27802550654719b79a55abe58736a4646e36d2a5e19307517ddb4b2c69f9203a18b07cadc39603c759f100b28f9c744345085e86f578829a3c0c0136c75dd209615cc399276171e448b626181aa575a7ada14b7865ce62b06363995a0a0d78e07414204b9e1af8d78c3a27d9c9ba54401744ccfd969efd00cf4f5e96c2e84510006a52908881b0a04ac9bb31b2234f769791e92dee6dfa77d71aa97c56caa98b3e4b5029324b570da91d0a4a64f4f518e4e7d660a368514a8750306af83e034d4e975f58765381a7e5dec50c91a68548352e8fdb40d000a50da373a1ddf1eb2227f6004410fd351756e2c760db9e038e9a0d69820c69ea177345b70e72d0edae137446b6b1a7d584fdaa4a50e5af7ba61c5c1386fcfb2325b87546ce1a7901148edd875b5e1693196d7f29c67caa9ee9e604ee0051792302fa7ab812a86b811590deade5a89be2e1c61e6942c8e0bcb2a5435dac7333688b98155b52936c79b3e67753ddd612e5486fa59d92763fceda460d1d59381203fb4bb13b8567f8c5e67e4addc587d9dc78923f0ba902cf015b43a7976751042dd05d3fe87fe0abdf41a4272de09d090831035d094c05528101dffc53501698938bb9a0889fbe266c1a134cd13173883104a5c830f49671923bea9f66507653f2e59f20ffc9bffe43149354198f24d52118bfa0a07f551eba245d46328f5bb79920816d025b28f90d68dca36bca1b393db89d028ab2264c00e3a03a7a74361c25ea962bc147aa255bc3bf2c77d6666e90d304b1298044ebb50076c69f08669269b2b2a7a846ae7687facc9d99d61a24c7d891b6e3e6a78be9343b1f269d6ea8f6a4d588115051bb453c2d34346b7a79a58556af009789ea260e668d721a2dd14f429fd991d2dab08ca44234ef7896eb097f2841493f565f5eb649a0b39425af5a19d089e3c4f8381c2e38dde698602229a5a613884a92517393de89e3f234930fc3c7da7b7299566678371b62a790c3cd64565e13279015e537fc63f64ac4b96ee285de818ea8dcd6942862c83b377cb0d609db996ad60c2d5023ab5c6aa004acb86271a03f8e5c8e514d602662e42a106a7602ede316d3a7e919b7984004d2aa8494644a5390418174668b4b48104f86d795c02aa93768c0bcc97721af092017faa5720a93ac8218b3c855460c529b5184a70fe4ed355b6e1fe00dac5942995d9c6f3eb5501975e22cee248321b59b563c913b7027bb10f3716fb294d6dea9a52bdc8258689461c92016d8de9bbb8390344b9506e07f2d2c95245a8762827f034ab6e53f38a8aba872aaefd589ab6c86526f6146e94af09417a48a04eae574ffe533a3c53fe9027a0401aec5453b0213d49917f1ff3294cb9d911540a88b630cb7a4bf0057ff29b983bac2102ea58acad6ee9cdb1536cb7e7203b09c41bb856471b9d0ab34d965405f6ca24854f4188b2854e20fad6ae8c404438b82214f62cb51ed5d5215c430dace71863c580653ad309f6f57bc0904fe9eab19ba11ec50560ac22860d8086a8388c4c2682480fd279c065c49ae208d96f813669141199af5786eb58e94d946db10b4dc5dea981fd16eee5dabdb6a464ad963c55204f5ae74085cb02e280e10a6a588fce4b437c804550058a89206401ad81d8b75067648d3ec385e469977e55e9fe2a37200dfdeb3b02ab55178ad12ad6ee99572423088aff8253681a19d4a1d699d554b1ba265a196717aa00d4783b8a47c03a42fa06c64a864157884e740378be46f772c092f6fd06f39d44850639e8dd19af8a2a1e8344a2b786bf7d7ca2450c04965e049919acc92d2d2ca212b5c3be0d035010bc478e028f390147800bb62560974c9222cd0e455d7ca5b6f6e5b87b386a6ac44b054f0f416550260a7fcc22465e7cb3200e297144db7e1f5609ddc00bb25bc753329a4c764f29c2f6bdcafd2fba66e6809c32124c5417741744090ce1b6828d00370e6b760a09da6f73089
+OutPK = 7b4db63984b59c5f4c76202fbdb360ed6a27ee1d9395e7721787e4b0d7ed20c9937214a4690ae10bce3a621f08d37706945b1912e0dfa911bde2a1099ac611131dcff41abe5a16d33978094874b852743799d6316c873bf2f8e17827ddac9b33da6a4a5229e01e6d85f1973f4aa7cdbb45934dcb680a625fc4a715dfc0804e8a2f644694390c14e053a8ea5e65a4168a52629fece156b3ab995ac385c7a8ab0c60969ae05563956fd0a3f1d5b009a05a5c1ac384f85c8bafcb9bc3d856de6f39e8c7f908d7acd743ee058e38cad1b0640c0ccd2e5a13e640bdac1dbac4a08cba19038f49175817e00d69092b26395a96be87af3c8bc08cddf4faf21c19147e08eb1d796ec96c624b657687552b702164705782cda3142213254414a6bf0d17edaa692690ba78c4e46ab936d03a7dd785f27576754a0dfa5079517c0b264a20f65c1ea211870a0af071e2234e967a70945e01fb9460cc9b49d66e1b253a2fb709d674c45e588f2420013abe918e4c09f9e1e9aaf0d91daafb158193c14e8622b583dea1a3a8f6997ac5cbf640d0504e3629b1387e70286a244300b4141cbf9e45d87ec26992ecd7b44de2a2b02fd2aacc9565c990c0e300407255e04901102446e3d128aa684d878a1a5d087b51af20907ddaa44190d7113d7af655b7e2244a96b1117df9ce63e5d4612ed0d953358e81178b65f0c46d5e8abf414518169e5726247cc0298d140f2ced8059baadddc21a1521468a0887b09860f8011defcf06879573aac97a8084aea2b915cab6c4f900de1fb7e164b97976219178e4a17abc1a8c3938e1744a240f7446627549176f66c2e946becbaa200c90ba07a892607910363558ca43a9da560b8742667dc981b842dd07b76d2bd1abdc005bc1b1b587b3a3ae4d39bb4d7c218ad27acd522d71dbe953964468e15cb5464042b45118eaaa5fab1d3bbc917d9b57b33be2e56dc062804bb5064fd48b6d68dad551e12ff329fdc5971813121aa4c48fb75f30236d4946d593c8a295900f6a49f143d62a5a682ce686eee16457ef90380cb61d09a1ca514c4646ae5f0a1448c5bec2996f1328da72809e3f0a13344d5e6699786b386211e170b44cfd985ed473ba2a962e4c6b6170a53c638584dcf0438516cbac9ac1c028159087d17b8b403a949a50a0d170aa7d66cd5a97c83231012fa4c49a724b01caf7839a45655df3f7f9caaa192d94e9b40d05352137a9d2906712c25bda8c5522a59f8b190c400b2febbdcb1cd0154e1fe59935842a3cca3aca97fa46fc081a08a37aa6b310e6d07f3694a60ee142b9f86df643256888ad5540817fd3abb4a4ed88b4e8d5b983d8db27e517d1964cdbb377e6681354c23a016dbd15ed9fd287b084b4682dc6bba72e2de24eecf9f5cd0a378bdeeb477da863408e707af9b97424832a69d0280767bd10aae8be374897d6f70a107acc5aa5e4655c32ccfb288dfe6dd0c44434bd15b9c7a02a2565f96d7ce38126f3a425ebd133d55d561bea5a2db19619167e2614a93ca8b0bc4576cb1d225ca8c990a36a2ea86d4797eb71d242f3e04b6177d932dd4ca7a01974636342dc239a5d393f141f610fbc35b243c057a1fa80a3d83c10620c6c880cf9a354c25b368d98d636f1521524c7a3a3be0757dec839ec3c15cb66efa82c8931c384581a6d324e13e471545515a2a008d9c24b857e32659980a40e3a39197029b8e452aac99aeaf5b58651c82bb0ddf68950654c4be82837d000daf1e4c89d1691c757a4cd57db8e0389818c6a80492db4544e6ab764a0181ccead3306e1c0f2665d4e28d09ba7ba513047c501763678ca9bb0a8a4967e4f6e6760d7ac58e5e2ccdbf5784ec84a148052593d6c89b4b3c70411e51bf664fed6af66d220838cb2769565667b2b0a3b31c598f8582078a25092164275aab4178a6a1d083f0f50237a5fa63d3080ab2510b04cd1c42af9ec321d566d4e6851d0a919da49323d196a314d83d1aedc23b6d5140825e54cfa8b1032a0a88ec1a2b116eaf51d0c050c9011862c45c69c9106d425bdd561a415100d401e76a728de8c3198d34607685d290f30c5c3fc07ca07d8f779ae929a0bd3c17eed78e8c472892f3d05a6c8051646c4912f11efba3cf0a561ad7b3697468b2f5be4b20a68884a82ed4a2978b49be5983bc16462b3ea04453521b824c33aba2e5d0e4a4b9c753da12c532ba88993f4507561f2fb2c7d9339043f727ba4749d97e350de064eeb539db2c10d2282adb54908adab2328dff4082d7d85eb194820ed3bbaa9aad149e6055d1ed5335ca8adebd9703949ba1a3981bcab3816a0bee550455fa4343a9c9de43ba673cb1d1f301f9a48978cce66895db5be1ae4e9eeb142f405863228b0bf932afb804ac87f5d8b3eb4c1ad4f4919410b998820f86e35d7d54d60292897130646bc9a888d65e3491bab5d5ba4cd0c74888b94e0d66445e9ef58566b568bd6847bd87e141aec81e3009ef60d4adc1412ae3d81338be513737c6244aa3478125159186387db3d8875
+
+InPK = 7b4db63984b59c5f4c76202fbdb360ed6a27ee1d9395e7721787e4b0d7ed20c9937214a4690ae10bce3a621f08d37706945b1912e0dfa911bde2a1099ac611131dcff41abe5a16d33978094874b852743799d6316c873bf2f8e17827ddac9b33da6a4a5229e01e6d85f1973f4aa7cdbb45934dcb680a625fc4a715dfc0804e8a2f644694390c14e053a8ea5e65a4168a52629fece156b3ab995ac385c7a8ab0c60969ae05563956fd0a3f1d5b009a05a5c1ac384f85c8bafcb9bc3d856de6f39e8c7f908d7acd743ee058e38cad1b0640c0ccd2e5a13e640bdac1dbac4a08cba19038f49175817e00d69092b26395a96be87af3c8bc08cddf4faf21c19147e08eb1d796ec96c624b657687552b702164705782cda3142213254414a6bf0d17edaa692690ba78c4e46ab936d03a7dd785f27576754a0dfa5079517c0b264a20f65c1ea211870a0af071e2234e967a70945e01fb9460cc9b49d66e1b253a2fb709d674c45e588f2420013abe918e4c09f9e1e9aaf0d91daafb158193c14e8622b583dea1a3a8f6997ac5cbf640d0504e3629b1387e70286a244300b4141cbf9e45d87ec26992ecd7b44de2a2b02fd2aacc9565c990c0e300407255e04901102446e3d128aa684d878a1a5d087b51af20907ddaa44190d7113d7af655b7e2244a96b1117df9ce63e5d4612ed0d953358e81178b65f0c46d5e8abf414518169e5726247cc0298d140f2ced8059baadddc21a1521468a0887b09860f8011defcf06879573aac97a8084aea2b915cab6c4f900de1fb7e164b97976219178e4a17abc1a8c3938e1744a240f7446627549176f66c2e946becbaa200c90ba07a892607910363558ca43a9da560b8742667dc981b842dd07b76d2bd1abdc005bc1b1b587b3a3ae4d39bb4d7c218ad27acd522d71dbe953964468e15cb5464042b45118eaaa5fab1d3bbc917d9b57b33be2e56dc062804bb5064fd48b6d68dad551e12ff329fdc5971813121aa4c48fb75f30236d4946d593c8a295900f6a49f143d62a5a682ce686eee16457ef90380cb61d09a1ca514c4646ae5f0a1448c5bec2996f1328da72809e3f0a13344d5e6699786b386211e170b44cfd985ed473ba2a962e4c6b6170a53c638584dcf0438516cbac9ac1c028159087d17b8b403a949a50a0d170aa7d66cd5a97c83231012fa4c49a724b01caf7839a45655df3f7f9caaa192d94e9b40d05352137a9d2906712c25bda8c5522a59f8b190c400b2febbdcb1cd0154e1fe59935842a3cca3aca97fa46fc081a08a37aa6b310e6d07f3694a60ee142b9f86df643256888ad5540817fd3abb4a4ed88b4e8d5b983d8db27e517d1964cdbb377e6681354c23a016dbd15ed9fd287b084b4682dc6bba72e2de24eecf9f5cd0a378bdeeb477da863408e707af9b97424832a69d0280767bd10aae8be374897d6f70a107acc5aa5e4655c32ccfb288dfe6dd0c44434bd15b9c7a02a2565f96d7ce38126f3a425ebd133d55d561bea5a2db19619167e2614a93ca8b0bc4576cb1d225ca8c990a36a2ea86d4797eb71d242f3e04b6177d932dd4ca7a01974636342dc239a5d393f141f610fbc35b243c057a1fa80a3d83c10620c6c880cf9a354c25b368d98d636f1521524c7a3a3be0757dec839ec3c15cb66efa82c8931c384581a6d324e13e471545515a2a008d9c24b857e32659980a40e3a39197029b8e452aac99aeaf5b58651c82bb0ddf68950654c4be82837d000daf1e4c89d1691c757a4cd57db8e0389818c6a80492db4544e6ab764a0181ccead3306e1c0f2665d4e28d09ba7ba513047c501763678ca9bb0a8a4967e4f6e6760d7ac58e5e2ccdbf5784ec84a148052593d6c89b4b3c70411e51bf664fed6af66d220838cb2769565667b2b0a3b31c598f8582078a25092164275aab4178a6a1d083f0f50237a5fa63d3080ab2510b04cd1c42af9ec321d566d4e6851d0a919da49323d196a314d83d1aedc23b6d5140825e54cfa8b1032a0a88ec1a2b116eaf51d0c050c9011862c45c69c9106d425bdd561a415100d401e76a728de8c3198d34607685d290f30c5c3fc07ca07d8f779ae929a0bd3c17eed78e8c472892f3d05a6c8051646c4912f11efba3cf0a561ad7b3697468b2f5be4b20a68884a82ed4a2978b49be5983bc16462b3ea04453521b824c33aba2e5d0e4a4b9c753da12c532ba88993f4507561f2fb2c7d9339043f727ba4749d97e350de064eeb539db2c10d2282adb54908adab2328dff4082d7d85eb194820ed3bbaa9aad149e6055d1ed5335ca8adebd9703949ba1a3981bcab3816a0bee550455fa4343a9c9de43ba673cb1d1f301f9a48978cce66895db5be1ae4e9eeb142f405863228b0bf932afb804ac87f5d8b3eb4c1ad4f4919410b998820f86e35d7d54d60292897130646bc9a888d65e3491bab5d5ba4cd0c74888b94e0d66445e9ef58566b568bd6847bd87e141aec81e3009ef60d4adc1412ae3d81338be513737c6244aa3478125159186387db3d8875
+InA = 16598e075b0e7c09cd899080a945dbe249066492b8c9829f42e7d131c5017540839464989c68ba38dd2365e97c6b03c83f2fa68c84cb8c70a05e961772ccaf358dbbea4f043fa5d8db73c062932cce55f07ec98cfd84b1b2d13c33e94d94a616318b1e400f42b7424e256655d1d810114842d92882dd4d286a2f9ae8e065bac291bb133d462c531c4b902a664d5d31817828ae784b9dd1cdf193824f5578345a33b34a07e7add5246d933330f9a25b72c79f57920da7be25408b26b42a142248c4bec048ada2ff02fbd9414ac16c490ca636082e27c7e502a3a027c822b0bc558d0a48680d89ace313195b8bbd5e7d144d394890594a07e8a6f266562c628744a1e85492e97bd9444d7a69dc74c3005053d81ce2f358d54c84159f48c0f26c3e58aa2a3fc012fa5ada92e0ee63a39c189b61b129fea5ea2243e077e598f9e2dc95a8e31c632ab1b975740685e5d389b785cb95e572e6951f11e401d598b359464a0645882375c667e416c4b2b684269235a29890d85cf6c16c554501f709d09654a6001ac7a2ae52e3c3f275e01eb0366ff80bc34d96a6a877a925690ead51da259710bbcc1c4675b9a97ce6e8b93b4a4c93e7d95ba2ca42adc3a0a5431b05b0e818a04a655db5986514d3b9b905e50c0e9919818efa1d867ab90e190b0fd55704f18791143822a771711289a7009d2c0eff5e09f99c520ce791ba00c8046a0f5e2f30af489c565229f99bc66a42608345769a353f4079906d6d27334a5b11eee821a398b56ab310791d86d5b2925c62ed2d17e28fb89720d180654c394de526dc1558545a796807d33f86ae96953d06dd2a5913a0b9a99846960ac6f6453a125eaa0f4e475a82149485569bd5261084e76dca5291548ccd22f4a2f218d5084342387c1a78a04403c1b8215a9899859e5c1c75e359cace8069e4c85aa8b6a846218a4338ac58447758cd2807c8b1cedbf0319fba190d49dcc554788558c943c65ab65edb113e3656ca1ba6c6344910d26a441f41426afd7bfa103353037057396ad70237d854ee80661a406d0b85c29bca460cb44b5e90e500d10c9dd106d1a10d49b4046178ce003b18eac14517c5aeb2854ef8fcd6362a0e3513cfd24c1f151045f0f1a7fb1554283a5682ed6e75f1a0edbad88f822632b90be8d458c6dcbe1f865f4b265ab27e2fc4bec75eee311261e3f52264014656094205b193315be6a3e5114663429e8823697d504b71fa9ad615acdd36625720ab40956501d998a3fe8037c7bb75032a4d53767b701ab3c150179bd50aa5553a4a272e48c71539d7da256e041ddd9a85b0a8d9dcdbcbdff94d80a4d8e5cefd292fe938f04cad77ba2ac86b57dc5660ee05f7220812ba6a70a2ca1cbc5f1736a5cf293f1acf96268df65e3e92362843d81337c88053aeed7ab2831b98f8494190eff3272d687c171af50468c49578a05a7be6c237460f93f9ab7553981761d483064233e7d4fad5104f5b001ac03ede1776ec0096ba323b765ea74a8c2d9a0d91e130ac9a4807dc6a8376fc362f4645d614d80f3f55e2cb49866a62ada62ae74d9288160bd5cc1d49b88a3326c5f447f9d47405a1b8b9eb23bd03c03e207c09cb59cd4dab8755d8d016bd198e45d1d5ec6017a61fed12b719970fda2a89874662a7e16ea11b185377c37977a1ed0af78fa3042dc17e192e4b3b2f7212964e36d357555d445348c2759d8e3bc1ba94d9e047ad8a40a05bae9f918187039bed17086ea457d1954d4c5575e9ca58040c129bc6fef20fe628d6d8eddead751729fa7d710802db77c1cdc47176512b098fc524024448230e4e95880fb5e375fa7f8300ff67b05861b605636aa04c167b4700b50656054c4ca323534921679aebb3be185412cd9ec0218046e224cd1b886d6a74d0e4479fe502d7038ea08a9a67da97eaf09e59046f6efa65348085d80d1832ed720eefc294365dad860b4afb412a0d7109e90f224cf87fc84338e15ad99e4d523651e0202aca201e98c9e440a4a07274c8dc95146a2e37a8841b6b6d48431f88373ecb7ff13b2c1c366aacf477e58a33af37c3ad1e8e708a10e5685878ce5db4074838b68907176239b6bfba643d88aac92bde285cf142952a135fce2308d9bcfcdb21955eb0342b6f9f18caf8b6f408c6c15cb976108097ba52ca2af509b489d379b27deb0470e6c40cd62021a74cedaae3dda546f6b86c1e5271d011d9145c55d407b359141d5cfeab5c820f221d199764fa369242efdae1210dd7e4cc66c3deb0ba8442bbd27c0e688415f2ddb961e72044b8846c911816b87384260dc81b717a5eed06724e8d5334008fcce70985b3c29166cd5f01e2901f44ce0f75ce0038d48353c2e7512bbc5acce012b90984d2558386a2a33a2e69a3c68e3daf841876a4a668f25cb061b1dc289c863b050351a0ddd787e3f9711d92e61037f180b0820adab8afd5a5fd2e7f198e6e1b9c8291012ef543585371128c62917167ba43a96aa42b296958753a91d16f5cba922d58cd8d2d1621922d
+InNoiseSP = 2ed210c039786d1ec41d71737a4b8292d1686c60529403f5780d3292398c5da63f30ba6a67115432a95b5b59e1c981bc40b755ee043840591cde37a3b3ba8e0c82c297fbf569af43d5f2ac2c50aa0fce00d6f23a155a57c1ea9d6ad9649a23e482741ca773d07f52bde1dd9206fd41783e6849666cba022e6c3b84bed2060e0a57a38a255e7998c9d4c32d0d22980652ba2ca899eaaa69e28eb92cc0b6f9ea48725d1d41a86fea16bc12cd9b7efd5be446221b1b023570da87c3f2d2b49804c9f4abb5bae0823bb8cd066c492f1b64f1c95bc2202b3149d520478ef8f2dfcd4600d4c95481d99daba1fc389f8898a16d2e03fb7842e599c414162602e868c968ff3d06170f3eb845583f05e18d02be726e02051d25a9ac48856f7f33c1596c8f86a5ca98352f4c95ea0a13769398853878f62052eb8ebe57637610886331d5bfc4707d58f3f8b50dbc63c0f6d6213da93189b7c65c755a8a516ac9ec7d918aa53bc191ec6879c75273e31972f3d5d3652ec824be0490c2814abe918caa37e65e4c5dc42316e67d8638e6f2aae10a75c3adc9f2a92a11f4efc6262e1d609ae3a2e3358242f36d08d047911699ee00c319e22b7de9c9d1a0a40e78cf0bbbde864c6986cbf2fad8a50e429c794ff6a06b1f65b275523af0a14b4917f97ec51ac8d1a8da6cba92bef44a28b234dfd1160684461090c72790459247ef0d782331735a01c7194d6923d65be972a0d811900b3ef3000879c1eadbc3f06463772b822104bd32520ee9131efe630c2e40e06cae62b2c95204a4f0b3326bc6036cb53103402925da36a1ed822fd63dacb220e5f5f862ec123946a0a000612de19afe6361e52eeaecb4c40ec617344e3f4af8b16f3086347363b21ccb44b0cbdeae894f0a85b1cb6e68b6596ed29f418cb745a63ace6033a5a19d5479f4a3bacd9a7b39413dd4a21ac132b04d69e62ea8841963715c5e81705e35f496a712ca0a025dae4ad3d3a43b03acc6c0dee55b27936340211c9d55a43ab2acd6b47fad52fac08e3f7e5af0b1196062364cb730a79d097308551b8d4424fe1aa15b07f95afd076dca7430a95a0e2e8b2b78a1d254c184ef4d9a7fc2ab840476541aaf6d71d24e98d40d578675e004a18a9c2b40e1a85adc1da3f892911b887a8270f6beba60fc599f640cc7d3caf5589c8a0d911f6a35ac1492045c54fec2472f076f08c8ae15f9a684e0dfa98eae1d0112854601c92ef8805d112370c143a8a570a80b93a4d01c32ba416740a930042224d47ca0c058822c088d01c13287ab5bee6310fa17ee0a45053f99a7a3672d24a4594ce9a6db96bb0a9858d037d9b03db92417f728c1e58bc24829f1c73465fed9a49aaba0ba2e9606b6e2c16b23054a571c5565729d80793fd875f70074fa8dac536d67b491152d15790233d9fa4234d4cefffb52106ff65b965a857e0e3294962a35e4a782d5b67b6cce0876600b435176703f8f2b46417eaf41832dc6a3e4a481daa54224ea4e0c2894633d5493fa9f09d9a4ea40108644e0a6d434a6edbc07316e9ca2cf99a7dff61e39d93fd408940047626fc0b70082ac612d04db5c40805b5b176ab16f4f483f11aac0473ce84b79ee0db1049db25bbc047bd56fad872a0aaeb6ce3f894d02431b24f49b6255a99c865a3666287e74ddfb6a5e40111824f44b77ceacc1caab124390928da4abeab49198cacf408a6fb118609735a419f94589ca8ad1928907734eaf76e5e69a2ca75564530d7ac991a3a211f433ff9006daee25b0245943c394951786c37af063d0306a8d56e6ab862d0d0069f459904edbca539643a69ad0da4f9ab1906cabd2a22263bd41aba937f9fea83355ae32e3f49c7507c79775c4326a2715356b1b880c79dd0d58177839a21aa6a2fd726a318ab2c849c2004041e591a0c637abedea31f9e97958aaae0393c48934a94fd9d9c0ae6d871ee8c7e8b8a92c13862ee2a025dd668393fea8b6d09106d320bbf0889d73422c441cdfe66aa0127cce695b3a59da27dee407b837c47b52673142a4799ec8eae5607bf8bfdec37748793052abe594c51e0d67f424d013a640222604f8f1a2f97fe90a6a9897005d75452be1b940786013d61085b50de4819f36a3e80a93a162705f961e9e0e22b61b14164f06b9f3a9e23ae10e9648e1c92c70a92582b44d012e9d79ea7d067461a72103a0744766c2f1625ade67726d8e2927e8a8bfc56f20d9b83ae9d7aa121ac2439a424e2acd2233230936a3d7908d699582e3da922a0eafc0a3b8912d17ec1b043f4801bd0aa73789b263c3d9b5c3e08575c25642b38128927b8004746365ba536256f42b01bf58d661d0b8b0b3542b61f50b92782a8ddad8e9a4865dcefd08d7b43b0960ad5af436253fe7db64396d83481002c8dae47cf8a9a4196bb4a51f00e5c462059a7647229b548e5d04c06966956a0548189a6a0d59b1c05c80c6751976408bf4d649de7e60e909d11c1a8309e1c955a34d8beda46a47597c7ef9e3c965915c09c983d8d5c3e22f
+InNoiseEP = d6d8b161e8b409512642cb760a3fd3d00d19e4067a48850e88533eb4c6489ac45bc0846650116500303bb19c96b2f8ea0f1f939fb26411bdb40a50654ebc5d4eac55d8b3dc5327eb5a642eed5761ac7695d02a1d266491d63e515518c1cbc400d2231e1d9163208a5c6ba32a471815aaee089ce4fe0c921125232908eea86059ea99e116b9261841e264a43aa2136dca03ad235d2ccf4095bc9ab1eaeea623e6af79db4ad67af97d73c34698ea1c0f13cd52d05c6a61eb284469f8b00af6c24ac6c5a4281ec9290895564a96d6f8bae1389cfccea802499c2e9e8be0cb50743c835b4e670fb82930c7fdf6e3da7d0e50ec0444d68dafd62571f1e4a2ddee6e8687b4b18228d3c21cf152f5e3b442cdd8afdbe31a7002f876c8e662f4682dafc5477f843fb44db1dae122e37945dd465b97ec41824364f79474b2bff2567a05a66eacc3ae13e333ea6889565189feca2050cb1f0abde21115dae186cd728b73e00452981a39a1e8aa04b0da22f26eb3cbb35c7959959558d6821d4b0a1ba426be7b6623646352947d5562fa4189caa8b812b5a89106274c0aaf02eae228969f946a2d1da600216058956d460366a9b6df6e223d59e0a30d22bbbc21d5427eb2b48dd367649b267330273e73b342551daed107bff228402033cac3fa0fa31e58ba56bd5725167e28852da5c58271dbee696785ed77a35f804e684ef452462d6444574362c99135fa59565b9dec543a25661121e49da42487aaa509b95d26eec71ffe4e4f0f578907fe6c40ecc862fc7e78ea5eb9366a5d1c0aa729da74e07b51dfe4ca54e03b04543f53a612012dda1ce517610b755d9f38d35ebce0cd89b7f2fc2386e5659be02a03e0195a05e1d222f2949fc95921bf211633d4de7c3f2ec7aa50df7592660a81b827b2030aead161ff29a34ea6df36ffaa5560d6a2e033226c30cbd2d776c9651dc42006ef140aa62fd37accc05cd307d2f64b3e0580a0df4b47751b3da41f7aec11219a9ea77baa3050d1aba37549704fbf6982bb294618c01f0953663157bea914ea6b0027642625a70ee6be3a899192378a1d9bd8e578b802237e558811f1a0610b5b0f6bbe3139f2defd8614a419b99597fbb38e0a088124d8f29c14661785888c5579ccd995461b1637cdd49ec49b700fc49671f37e985f72231255b62e78cd045b9b4d3c3d4ee294bad23194714b5f73dcf4a4d5612060301ea6b9931f81d8f5b4a32521fb0de6b9902b76f136796fd382d23163fc08e6e955e754a9b7816ac5172e5a41805d33732dbe910b862b6661bc72200c9a7b11821c65a90255077492a6d864aab89447016989a6ae4072084d4f438040237ea9d5b6f25152824f927afee5483a20750b994a3936a2466a05be166bc7a809cf88162e8eb1f22168a8262e36198a4519ba621b8787061564d013a07be92a74064b5bbf20a500a4eb4be5812b8d432d33a3d835630ae9d0d5f6a67c607b0aaf2d30ac6546e14f7e719ba2df78e7ca5ba25c4b6861be97349e7bc964860db41dba835a4403245b7b07c64d987698e8f02b999add2f0bfb42a244ea0f43e4c64cb5359478244f78a129c5c476abd5b36b6a82424bc07efa50e615f1cc65240c5c9216253f65c22042e1d1a7d4e657ca821c5f3da26a04ef0c96de9f60b9fafa56e19dfff8c43c173b12b8ab429e8dbdd3c4a978c89912d0ad98b6163604c52a6320d868391ec323e5c89d015e89e7a2a267f9168293d315a97a102a13c0a91e6f9d3f51925471ffdb0225c1f5b70094d211d9d27ef4d23e421bbaa1408aa478d4611a2d19f7e8b71e17d9aba5e39a2a620f6d7468ebca1b65488177590c3de42d8cb0dc3ca6d55eadd560158dbe53f380b805b34bd55d9255dc98ac204f470e06171e8a0a25c29c9eaba9719510dc8e2bc9026675060d4be392566b6c43ab83edf2dfc44cdf065963fa7cb11f152dabe87502e194ca241a4e823e110f53b1448f1fc09e204316bc8d4eb7559ea47806287ac463949d8a4dea242ed6495ac5b3aa85f2885d0d1935614a8d8c0d6cc8b93a7a3264741a0c8c3dcea7bba25c62678c80e46b52f97e2911b7056235138e20640217a6241097c598537e612b0fb6d8b7c665678e8c1b92f142d30b7e0b65cabbcee0d180dc02855f8ba9831612351bd84b76d9b89ebf4abdcaa5b9b7fe295fd6e5c8740e4ff713cfbd89d2a1adc8b9391ce76cd2a384aa35aaac6441fc522a47ae7cd9b11ea22ccc1efbd6853637448a04fed08be92fc748bcd98b1f8304a52756a7dfcd42f9a8426246def0bab7ee43dc238656904662695703265cc506b6d02568208c9ff5d006db90b48c9e22a53766717772ac05666d4927be969803418a8ffaaf76e799e069145f793ae4406d1bd7c8a7a9b11005ec0ab5fbc6ad4363b60aeeca0cac2ecf987dbc4222dd7f7398c573c166007b9f15bd90eeb195c40e72ecc62d274b389d2c188696bbcc9f26223fb68c448912ca34b1c43640f90f6a52173a9eba97e6a65a2d8f438815a5262e4f
+InNoiseEPP = 00f0ff2b0000c0058000200000c0010000600000c00180000000fcbffc6f01f0fff6bf00b0ff0b000000ff2f000c000c00feafffebff02000070fffbfffebf000000200000000200011000fcbf0030000c0003c0003000b0ff12000100ff6b00ecbf00c00110000400007000b0fff6bffeaf000000070000300040001000014000e0fffabf004000e0fffebfff2f002c00fcbf00f0ff2b00fcbf02c0ff1b0000c002400110000c00fe2f00d0ff06000400000c00140006c0ff0b000300fe6f01400008000030003c000800ffefff1b00f8bf00b000c0ff0e00ffefff0b00f8bf010001100000000100001c000400ffafff2b0000c000300000000800ffef0000000b000400001c00fcbf0000010000fbbfff2f00acff02c00000fe0b001700fd2f01000003000000ffabff06000100004c0000c00140010000fcbf0040ff0b0003000100003c00040000000000000f0002c0ff1b00000003c0ff2b000000fcaf00c0ff120000f00050001800014001e0fffabf020001000003000100001c000800018000e0fffabffe2fffdbff0600fe6f0000000c000140010000f3bf030000f0ff1a000180ff0b000400007000e0ff1200028000f0ff02c00080ff3b00f8bf0070fffbff0a00fe2f003c00fcbf00f0ff1b00080001c000d0fff6bf02c0fe1b0000c0feef0000001300feaf00f0fff6bffe2fff2b000000ffefff2b0000c00100004000040000c0ff0b00ffbf0200004000040000c000e0ff0200fd2f00fcff0e00068000300000c00200001c000c00ffefff1b0018000600003000f8bffcaf000000f7bffc2f00fcfffebf02800000000c0001c0ff4b00ecbf04c0fffbff0200fe2f00c0fffebf00f000200000000400001c00fcbf0070ff4b00140000c0ff1b00140000b0ffbbff0600010000f0ff120000800000000b00034000700004000180003000f8bf0000ff5b00000000f0fefbff160000b0003000080000f0fd1b000c00ffafff0b00070001800100000400024000d0ff0e000200002c00f8bf01800000000c00028000e0ff120000f0fe2b0000c00740ffebffeebffcaf000000f8bf007000500000000040003000f8bfff6fff4b00fcbfff6ffffbff0a00feef00300004000180fffbff06000080002000f4bf03800000000800ff6f000000fcbffd6f0020001000018000f0ff06000100002c000c000000003c000800ff2f01200000c0007001e0ff02c003400090ff02c0fd2f003c00fcbf0500020000fbbfffaf00200008000300013000f0bf040000bcff1e00ff6fff0b00030004c0ff2b00040000700010000c00fe2f002000f0bf050001f0ff020000c0ff0b0003c00100010000f8bffd2f000000000005000170000400020000fcff0a00028001200000c006c0ffebff0600008000100000c0fe2f006c0000c0faaf0000002300fe2f00100008000180ff4b000800050001200008000080ff0b00f8bf00f0fe0b00f8bffcefffdbff02c0fd6fff1b00f4bf00c0000000f8bfffafff1b00fcbf040000e0ff1e00024000c0ffeebf01000040000c00030000000003c0fdef00100000c00880003000f8bffc2f0130000800ffaffffbff02c00400001c001000003000ecfffabf0240ff1b001400ff2f002000040002400020000c0000b0012000fcbf010000fcfffebf03800040000000feeffffbff0a00010001000000c00380ff0b000b0000b00120000400fcafffdbfffebfffaf0010000000ff2f001c000400030001e0fffabf0080010000ffbffeaf0010000400fe2f00dcff02000200003c00040003c0ff2b0000c0feefff0b0000c00180ff0b00070000c0fe0b00fcbffe2f02300000c000c0fffbff02c00200001c00040000c0000000f4bf038000400000c0fc2f00e0fff6bffe6f00d0fff6bf02c0fe0b00070002000050000800fc6f00d0ff0e000080fe2b00f4bf00000000000c00050000300000c00040010000f4bf014001100000c000c00010000000ff2f000000ffbf000001d0fffebf00000040001400020000f0ff0e000000ff0b00ffbf010000000007000280ff0b000b00fe6fff0b000700ff6f01f0fff6bf040001300000000200000c0003c000c0ff0b0007000780014000fcbf00c00010000400fe2f01f0ff0600ff6f0030000c00007000e0fffebf0040000000ffbf00400000000700ffefff1b00fcbf05c000f0ff0e000200000c00f7bf01c00010000000fc6f003000f4bffc2f001000f0bf0030010000030002800010000c00ff6f00000004000040001000e8bf01400000000000ffafff3b00000000b0004000f8bf00b001f0ff1200fc6f002000ecbf0000000c000000040000bcfff2bffa6f0040000800ff2f00300000000000003c001400008000f0ff120004400000000c00fdafff1b00e4bf030001200000c0ff2f010000fcbffeaf0130000800feef00000003c0028000b0ff02c0feef000000fcbf00b000f0ff0200034000000003c0010001400000c00700000c00fcbfff6f0030000c00
+InRand = 7329c31474ae53402ff402d394b9567d25ab9fadeaca5a4f39805974ee711114
+OutPK = 4a1de2132f661340403d82cb585b995cd9b1e55500474cafe43c0c0c30594a673d283cdcd7b427c52c99bb6a319256203072c8c9eb9582bcff2029566fbdbb390438f9570e9e0d41a8508a846ff9e4729530d58431dc3f183b04bdec9420898961a54dc20277b764bc3263e992e1649075e49fc62b793c74014aeb25cc26fa22d3c9e6c0902c1ec424425e9921113a0b11dc16e70c0c37c699a1fac49d846f8479f56ed2842a9c9feb290a238c99278a29becabb4d5241c3b496f00d7394ebb5c62caa4b6b68a4477426af6b59a0b55b2041a3a12a60f8c191354dc0abf24e4b1eabf82aa1941adfa450fb9e92af32681a679db4b5f281b76673725d9e596ab4cf8a448ec53148b5225a77d78d93b4ac748842db60cf80690fcb02da11559e17c34a79c3d94cf112f8e190782b4f9362172cee959e8c16c3e4c9492d5d304418c1bddd929bc557c89e5865e4550e0272912a5cd88a18108a2dead400c548761467371709a6ecc797b6cb383b8c530902d1618bccdde989ea75940b8ec3e5de652fa5274827d28048e5aa4b6ab1aa50d9e986331e927be94971cbed86868c5bcfd59b520f1347629224689bc583e7fb10642aa597c021022a4d954fdc10b312ab6267ae621de96ae42337e2e64c2d63141b58deac9f6f6f20e03c500ab647ce02f04c0779914dba1a4ca288d206986ae17715c37113ad727ed8ec887af2c58fb1c6079243106e3c957366b5595195e80e120e4d9debe9b2d9c52eafd66b1c422fa2932ce69f4890e004bec53968af64596d89b575035047e11f41515fbda8fd832b338b517b926b1187fedca03b8a9a724cd04288ef9661eb3a6c492dc5d16d94364260d28176214d494228e8929d069a10de59933c6bcba2de70beee7904a19da3c120675206d8347c912e79419754603159dd1cc34774157f7d0dfdb48114022b5903b993412759530ebafa0aaf1a0d2545f426abe3c1f5e949c54a722c05c200e0876f5d04da5b4d093da15d93587c88bb65a250c7da11aee77f5818a51381ea9a81b1fa4bb513f2c022e696b18ffb60c4ad3d9ca40ee745da79d6a880a932344a5e5372eb25059a7910d036104c1ff4956ba2358d5b17cee3076b11219fdb37f3fcdebc6353de299315516799b5b24f901de88d0fe113a6b21389f6c8eaea6a9f596c7b688961b418b5fa3782366c631d8b006905f618fc458ad87e6ac4a5b2f5ac28894828381f0aa26c0c21f148350cec11e5e39bde902584a2788f7e31941b7d52ce7e14e366c9772108adfa5f2823250e7fc965aab81162212d1ce245dfba74fbc67b7bcd821ec5984a75f5c9359348a333cb8586ca1c2a7a665c0aa6d29999b4b540a619251696a1bce815a287e2f801b36c8ce9bfb115bcd91efa22bd84a24752768e0937d1475361d8dd6aab55ceb4fbc5bff3d42ca85f955a5c9618faef90aac71db8c0d184b4422c96189124ba7fdad9c440bd2a966684fb84dc76c12db5570afda885ed7d09a35414c000e2323f0d588a8c4a40b46c679a24e8c32b5022bd2aacd4732e9f69a4e970c0e188d6141ff3892c698c6f33647dcc915088b9f43c4540a668e293a06e65b811e86b6ff466175295516bc2ac3dd0ab4350645d03aedac83e609125a1295ae7667c384a45ab77fa8700e739e5655253ad681258cc06b062117140afce9b4244860510755b9555326ba4be03568e509aff5001bf00370a06d6033e945669213443a34894d3f355a74a0cd551a918b837dab47608229b8f4f3ceb2ac478eda449a03744bb79077aaa875216888bb7c551ae06264c8d205aa5a1a76c7603b31a81e2e2cfa37c527ab3c534bbbae210812f6c1601b49174ed8a19159d72050c56900dfda35ae2baf78f8e0627c0fff839ec64ace027f2086d356084b8f3de9a59d26592425b096d38dd9044ae9ea2de966af0077e5add4289670c5aa16e9d9c61abc1abccd060440b363ea1cbc2f636ac4cffee0dd94d050a555bdb23f71199de9e44b90c351315495494d9266861427f80d87a966fc118151d659df787e9c5dcb6259fcd7381b7c906d5083b9149705644abe895b8005b2aa3ebc772562d8804050725cd60e54d5c56a79032edeb3d28c2c0bf1a5d765738299df565452527d5b8fb1804eb7ecd167ed57427fceeb426d6cb917acc4757da781098691304495f910bd52d356f61c9c9dc43c66e2429e6f57e1c632f4005448cbf95b74897e947abe126e0eaa6a40c559722d9a5b9b04f7be2a3a102a94e4961c69589a94684a1d155a02b8fdeb362882e75a71b9bf8fc2748c4e73852de28cd8726ca96b82c57d1e36225bd8ba44358536fba4b710bd8d4a9a9b2e1c99f26e62164794af4464df9584666aff8ee34b65d69a21028ac649657ee73c9550da69bbd4566399264465fa1b8358b8bcb92fb8978aa4a04df60b0bc5705c1e6e1851905cf1d70460a1d7e88d487a18ae1228f4278430b52127aea496afa4496e7628800dba95a1dc9f17b305ab82e19b593d9d6992264fe29d15157
+OutRec = 01c00000000800038000100000000180001000080002c00010000400020000300000000340000000080003000010000c0002c0000000040000c00030000c0003000020000c0002800030000c00018000100000000100003000080001800000000c0002000030000400010000000008000300001000000000800020000c0002800030000c0001800020000c0003c00030000c000180001000000003400020000c00000000100004000000002000080002c00000000c00000000100000000100002000000000800010000c0003c00030000c0003400010000400038000200000000240003000000002c000200008000100002000040002c000200000000100000000080002c00020000c0002000010000c000240003000000003400010000000010000100008000380000000040001c0002000080003000000000c0000400010000c00038000100004000040001000000003c000100004000300000000040000400000000c0003c00020000c0002800010000800034000200004000300002000080001000010000c0001800020000c00014000000004000380000000080001c00010000800028000300000000180000000000002c00000000c0001400020000c00020000300008000080001000040001400020000000028000000000000000001000040003c00030000c0000800000000c00004000100000000280001000040002c00020000c0000c00000000c0000c0002000000003c000300008000000001000000000c0000000040002c00020000c0000400010000400010000100004000000001000040001400030000000024000300000000340001000000002400020000c00034000000004000340001000080001000010000800000000100004000280001000040002c000300004000180001000080000000030000c0002c000300008000280003000040002c0000000000002400000000c0000800020000c00008000300008000140000000040001000020000c00000000000000000140002000080001c000300004000340003000000001c0003000000002800000000c0002000010000c0003000020000c0003c000000000000180003000000002400000000c000040001000080003c00000000800004000000004000080003000080001c000100004000040001000000003c0000000080001c000000000000200003000040000c0003000040001000000000800008000300004000280001000040002c00010000c000380002000000001c0001000080003c00010000000000000200000000380003000080001000000000000014000000008000140003000080003000010000800008000300000000080001000080003c0002000040001c00000000c0000000000000c0002c000300004000180001000040003c00020000400034000100008000040000000000002000010000c0001400010000c0000400030000c00024000200004000100003000000001800000000c000240001000000000c0002000080001c0001000040002c000000008000000002000040003000020000400014000200000000180003000040000800000000c000380002000080000000000000c0002800010000c000280002000080003000030000c0001400010000000004000000004000340003000040000c00030000c000080003000000003800010000c00018000100008000300001000080000c000100000000040002000040003800010000c00008000200008000280000000000000c000200004000080001000000001400030000400000000000008000340002000040003800000000400010000200000000340002000040000c00000000c0001c00010000c0003c0003000080001000030000c000380002000000002800010000c000340003000080002800030000000010000200004000240001000040001000030000c00024000200000000140002000080003400030000c0001c00030000c0003c00000000000020000300004000380002000040000c000100008000280001000000001c0000000080001400000000c0001000010000c00014000300000000240000000000000c00000000800004000100008000100000000040000400020000c00018000300000000240002000040003800030000000034000000004000000002000040000400030000c0000c0003000080002c0001000040003c00030000c0000c000300008000040003000040001400010000c000180000000040000400030000c00004000300004000000003000080001c00010000c00018000000000000100002000080003c0003000000002c0000000040000400020000c00028000200000000380002000080000400000000c0003800030000c00034000000004000140000000080002000010000c000080002000000003c0001000040001800000000c00028000200004000140000000000000800020000400004000000004000240001000000001000000000c0002800000000c00
+Key = 20eae83d111358edd1ef4c2dd731ec8ab172c5baabb832d8198b7f8f615a6939
+
+InNoiseS = 819fc864be3149721adb2aafc882e380dcf06d756412c8a01283e20e6ac1a396c0e14228016352fab19a6b41009a054ebc5ad9a4dbb34014e1df2a7388be6d9593d71860109479801ea9c464ba476edb713664a3245822999c2d8490db2aa7874aaaaf4cc0a1a3fc4617ed5c86f25985078fe7d6f791984d55944621aa86fa6d07763f2e57122e50d89235b3a5ad9bc47684b5f1a0d9005b059b70038f319e31137bc116d7229cab130a331403eaa76aa2a5225b7c9e7f57470b029ebd8a402f55a83e10d6290c391cb90c549c1de65bf83ac64253674c2804701c5bb1e616bc806b72224d8d1c43e049ca146cae42c75569c6797073dcde9028345ce38021a535daa7288018e56b16406a4e8869bbc656070e2699625d14ba996e81431a2d0a14e2405a082e40e13fa2b37a1ecf9a3923a68e1d990b812a1ffe9a674df40029747d846ffc894238b9279901c21489b975aa670448a4766a484918ed7551f9ee7a66bc26b88b002c7bd8f51f9b8c42a8e3ba214815bd687648459f10f2a391856ec3c5bc1a358980b1aea10ab26e430663ecc38018323f2c36daafaa1ce252774913ac30b6d27564c5c20e11e74606b1c1075ba60e451756591d443ec60ce49398d7b4ba3dd000630aab95b8111652e0c110fc04059a68a5c17c5e0a8382f3a32de475f01082a2fe62264b6841a44da669475348dbfda93a9304c502abf4b1710a5b27cc39a8f0e705a4633c5fc65951e4c7f86525c0d760079a75aa587a32ff0e9b82ccfb324a7e8abe9eadb940e10da2ce00f82362b26e8447a1eba21643c0b0e02a2d1190ef51db4a5969aa5c50d2bbe64d8fce2186f2647dff4aea76b78d33fbdf7d74bfca0cb20125eb5a74b1b26d68e3531db09f634bd134603438492df7c4d1a7402f7559e0a4ac8b8e0c417569478eae95226a747d7ead94390c5633041b27559d1e27bfe9104209897e3700edeba72d6f496cd87b7d446a1569b490dd8abadea4096b67396ec8c269bbb7f264bc9d9af9423829a149c3433b215528a90bb1a44878a2c84a35e23220eace1072dbb03c7c1f6059da627e9ca408c572b03ba1ee726739d8b32229f4ebc87c9b7fddff1652a24d02868c50f7cca61da9fdcabf6e733a1d90fa49d66fe8e73d80b0b6a567ace5b62b4e12cf1c5e738199881795ceabe2a517ab2009a90999ac002a40147ec93511e5b484b38213b09200549e1e386b9aad924605721498c0c2105a5129c0877aefdc25319380735eaa680a97c0b51abca6605a9af4d9167e87cb14a6c7424b4d427fe4db4e5fe9867004833a159069a3f6592c232a4e2db38512bee2a9b991d415352b26d83115e92d6567e0d943c67f8ae7b694c1e6beb1e857267311310426713a842e46aec68c0b4e9825a3133273c76475804aed47f31c36f8eba860a600967953152372cc1cdf893e325ec92d14ca45a9135a9c5b5cab4413fdac9f90cbd74be6beeacb6b248d328f081efbe6f268672cc244c04fd6509f2df12628b4a1c9e614eb1c6157d8981e9a6a019e2cd745733765582e92a518b2785056c7e932fc860f162c4c62e738baef86e588e3155515e0fedb0bcd997094d93b122d7d54c01296704e38b4ee47d0b67d5cc784f95a3b845969c1cf9ae3364a314f8aab0a19279c1784f6dfdc77c4e65fe5f43a77a8cabed319cd69ce96ebe04b254465da81e561103b242a2ca971927371d985327b850c998965327d18273f66c4f98281070e940ddbe46e8a4dac8130c4690b561f7193b3518cc464f096e720097dab1a17b4d4bb2ad6abf84b39246f470fe4589410a52888c6c00163d16df7c2225ea8071b9154a0fa340a29cc4bae8a37640c86f9ee7ebb1fda52040b09979a85a1b09f5432c884296191167e1802949857d1490c862ebaf40104a9cd22425338a27de46c08e34299090679fb115d473947831052dd883805d70625944e1723de9217857ab05aa2f70461982527d7d07db403b960800991fa06d7299a77447043eacdb52036082403867f0a182031179cedf1de9d0a5da71782718d6c874dd359be309f7090a94835e10f732c9dc9dff59abe1ed8441680117811f2d909d53a29a26bf47756444424f548e89abebaa25652e10c6373127e489d0d2123e278d05c842ac99ec321b6ed6af94eafc6216a54f62f00e0dfdd44b40eaf85cbed5819c0e553537182b1d9f9548c0e08845ffe8aa53631f76814d759a55fc9d020d2148415b61634864e6e590f5fec73cbca732c1fd19329d90e7821dd106515442d4698b957f697b2c9fb652826283287a064ae861c9c96c58261c20c51d642c5e0e09e84288dc2fd16550787a8d6b1929adfeb1b2392854977ade19af270825f9a20c6c2c5685b08b4f7c27123494a0365bdf50d8acc29f53afe2ee3a743c0b19d7d6613a39a19a20884d98086a5ae633e1a150a2fe2ad5853614b3ce94fbe401be3223d260a5a6994c321366e6daeb06f166989acf825aede985d4ab7b1948d81f7eb27e946948f5dec13765bd203
+InPK = 4a1de2132f661340403d82cb585b995cd9b1e55500474cafe43c0c0c30594a673d283cdcd7b427c52c99bb6a319256203072c8c9eb9582bcff2029566fbdbb390438f9570e9e0d41a8508a846ff9e4729530d58431dc3f183b04bdec9420898961a54dc20277b764bc3263e992e1649075e49fc62b793c74014aeb25cc26fa22d3c9e6c0902c1ec424425e9921113a0b11dc16e70c0c37c699a1fac49d846f8479f56ed2842a9c9feb290a238c99278a29becabb4d5241c3b496f00d7394ebb5c62caa4b6b68a4477426af6b59a0b55b2041a3a12a60f8c191354dc0abf24e4b1eabf82aa1941adfa450fb9e92af32681a679db4b5f281b76673725d9e596ab4cf8a448ec53148b5225a77d78d93b4ac748842db60cf80690fcb02da11559e17c34a79c3d94cf112f8e190782b4f9362172cee959e8c16c3e4c9492d5d304418c1bddd929bc557c89e5865e4550e0272912a5cd88a18108a2dead400c548761467371709a6ecc797b6cb383b8c530902d1618bccdde989ea75940b8ec3e5de652fa5274827d28048e5aa4b6ab1aa50d9e986331e927be94971cbed86868c5bcfd59b520f1347629224689bc583e7fb10642aa597c021022a4d954fdc10b312ab6267ae621de96ae42337e2e64c2d63141b58deac9f6f6f20e03c500ab647ce02f04c0779914dba1a4ca288d206986ae17715c37113ad727ed8ec887af2c58fb1c6079243106e3c957366b5595195e80e120e4d9debe9b2d9c52eafd66b1c422fa2932ce69f4890e004bec53968af64596d89b575035047e11f41515fbda8fd832b338b517b926b1187fedca03b8a9a724cd04288ef9661eb3a6c492dc5d16d94364260d28176214d494228e8929d069a10de59933c6bcba2de70beee7904a19da3c120675206d8347c912e79419754603159dd1cc34774157f7d0dfdb48114022b5903b993412759530ebafa0aaf1a0d2545f426abe3c1f5e949c54a722c05c200e0876f5d04da5b4d093da15d93587c88bb65a250c7da11aee77f5818a51381ea9a81b1fa4bb513f2c022e696b18ffb60c4ad3d9ca40ee745da79d6a880a932344a5e5372eb25059a7910d036104c1ff4956ba2358d5b17cee3076b11219fdb37f3fcdebc6353de299315516799b5b24f901de88d0fe113a6b21389f6c8eaea6a9f596c7b688961b418b5fa3782366c631d8b006905f618fc458ad87e6ac4a5b2f5ac28894828381f0aa26c0c21f148350cec11e5e39bde902584a2788f7e31941b7d52ce7e14e366c9772108adfa5f2823250e7fc965aab81162212d1ce245dfba74fbc67b7bcd821ec5984a75f5c9359348a333cb8586ca1c2a7a665c0aa6d29999b4b540a619251696a1bce815a287e2f801b36c8ce9bfb115bcd91efa22bd84a24752768e0937d1475361d8dd6aab55ceb4fbc5bff3d42ca85f955a5c9618faef90aac71db8c0d184b4422c96189124ba7fdad9c440bd2a966684fb84dc76c12db5570afda885ed7d09a35414c000e2323f0d588a8c4a40b46c679a24e8c32b5022bd2aacd4732e9f69a4e970c0e188d6141ff3892c698c6f33647dcc915088b9f43c4540a668e293a06e65b811e86b6ff466175295516bc2ac3dd0ab4350645d03aedac83e609125a1295ae7667c384a45ab77fa8700e739e5655253ad681258cc06b062117140afce9b4244860510755b9555326ba4be03568e509aff5001bf00370a06d6033e945669213443a34894d3f355a74a0cd551a918b837dab47608229b8f4f3ceb2ac478eda449a03744bb79077aaa875216888bb7c551ae06264c8d205aa5a1a76c7603b31a81e2e2cfa37c527ab3c534bbbae210812f6c1601b49174ed8a19159d72050c56900dfda35ae2baf78f8e0627c0fff839ec64ace027f2086d356084b8f3de9a59d26592425b096d38dd9044ae9ea2de966af0077e5add4289670c5aa16e9d9c61abc1abccd060440b363ea1cbc2f636ac4cffee0dd94d050a555bdb23f71199de9e44b90c351315495494d9266861427f80d87a966fc118151d659df787e9c5dcb6259fcd7381b7c906d5083b9149705644abe895b8005b2aa3ebc772562d8804050725cd60e54d5c56a79032edeb3d28c2c0bf1a5d765738299df565452527d5b8fb1804eb7ecd167ed57427fceeb426d6cb917acc4757da781098691304495f910bd52d356f61c9c9dc43c66e2429e6f57e1c632f4005448cbf95b74897e947abe126e0eaa6a40c559722d9a5b9b04f7be2a3a102a94e4961c69589a94684a1d155a02b8fdeb362882e75a71b9bf8fc2748c4e73852de28cd8726ca96b82c57d1e36225bd8ba44358536fba4b710bd8d4a9a9b2e1c99f26e62164794af4464df9584666aff8ee34b65d69a21028ac649657ee73c9550da69bbd4566399264465fa1b8358b8bcb92fb8978aa4a04df60b0bc5705c1e6e1851905cf1d70460a1d7e88d487a18ae1228f4278430b52127aea496afa4496e7628800dba95a1dc9f17b305ab82e19b593d9d6992264fe29d15157
+InRec = 01c00000000800038000100000000180001000080002c00010000400020000300000000340000000080003000010000c0002c0000000040000c00030000c0003000020000c0002800030000c00018000100000000100003000080001800000000c0002000030000400010000000008000300001000000000800020000c0002800030000c0001800020000c0003c00030000c000180001000000003400020000c00000000100004000000002000080002c00000000c00000000100000000100002000000000800010000c0003c00030000c0003400010000400038000200000000240003000000002c000200008000100002000040002c000200000000100000000080002c00020000c0002000010000c000240003000000003400010000000010000100008000380000000040001c0002000080003000000000c0000400010000c00038000100004000040001000000003c000100004000300000000040000400000000c0003c00020000c0002800010000800034000200004000300002000080001000010000c0001800020000c00014000000004000380000000080001c00010000800028000300000000180000000000002c00000000c0001400020000c00020000300008000080001000040001400020000000028000000000000000001000040003c00030000c0000800000000c00004000100000000280001000040002c00020000c0000c00000000c0000c0002000000003c000300008000000001000000000c0000000040002c00020000c0000400010000400010000100004000000001000040001400030000000024000300000000340001000000002400020000c00034000000004000340001000080001000010000800000000100004000280001000040002c000300004000180001000080000000030000c0002c000300008000280003000040002c0000000000002400000000c0000800020000c00008000300008000140000000040001000020000c00000000000000000140002000080001c000300004000340003000000001c0003000000002800000000c0002000010000c0003000020000c0003c000000000000180003000000002400000000c000040001000080003c00000000800004000000004000080003000080001c000100004000040001000000003c0000000080001c000000000000200003000040000c0003000040001000000000800008000300004000280001000040002c00010000c000380002000000001c0001000080003c00010000000000000200000000380003000080001000000000000014000000008000140003000080003000010000800008000300000000080001000080003c0002000040001c00000000c0000000000000c0002c000300004000180001000040003c00020000400034000100008000040000000000002000010000c0001400010000c0000400030000c00024000200004000100003000000001800000000c000240001000000000c0002000080001c0001000040002c000000008000000002000040003000020000400014000200000000180003000040000800000000c000380002000080000000000000c0002800010000c000280002000080003000030000c0001400010000000004000000004000340003000040000c00030000c000080003000000003800010000c00018000100008000300001000080000c000100000000040002000040003800010000c00008000200008000280000000000000c000200004000080001000000001400030000400000000000008000340002000040003800000000400010000200000000340002000040000c00000000c0001c00010000c0003c0003000080001000030000c000380002000000002800010000c000340003000080002800030000000010000200004000240001000040001000030000c00024000200000000140002000080003400030000c0001c00030000c0003c00000000000020000300004000380002000040000c000100008000280001000000001c0000000080001400000000c0001000010000c00014000300000000240000000000000c00000000800004000100008000100000000040000400020000c00018000300000000240002000040003800030000000034000000004000000002000040000400030000c0000c0003000080002c0001000040003c00030000c0000c000300008000040003000040001400010000c000180000000040000400030000c00004000300004000000003000080001c00010000c00018000000000000100002000080003c0003000000002c0000000040000400020000c00028000200000000380002000080000400000000c0003800030000c00034000000004000140000000080002000010000c000080002000000003c0001000040001800000000c00028000200004000140000000000000800020000400004000000004000240001000000001000000000c0002800000000c00
+Key = 20eae83d111358edd1ef4c2dd731ec8ab172c5baabb832d8198b7f8f615a6939
+
+InRandA = 312dee62b48992a86afc71cfed062c85e5f76ce279f42a4e0561540685c1cf72fcde7f4720ef87581496c59d3cf0d14a745aa1f23292c56ca380c12045b184669164c73c3a2492af440a78453a1012fca13d290be6122cb832ba9de59019b8d0a40b6e2a8a99483931b5ee2b4971256cc31107c2cb14503e079d27570e37ac03c2aabce21990c0e4693c2a4c0eeded78361503d9023fd60edc742463daa39d32826ba8eb136dc02e6fcad62aaec67d9392a958ee094ba90b53b78c7496941644a04e7654ef51d18b66c80d4b55d9c3d5153760e8cb8495182e0a8ce50327142e286c27303ce56edaa6f74683cd8d10ef12d9970c30352574c06bde230f00d089214c6ad913333430a903f5253f13fcc4249b50efd5f0ad0c7b450713f84190e722c8b368b044744ee5c04172719d48a2919d3815c0c47a04848011c5843ea755007b9458a7c82340a243045d017946651ed32172980e353495df914ad64c2ad4ba925e4abd2b2fddb544386e4dd65feae8e2b0ccd0a2d2742c8666266762b4b6713b17240b5776278a6e1ad4c2d42ed64d32b14cbc66e7cc8844510a30faa9bfc179566034865ff0f7fc5510ca31e3093d39ca23c5c5d2e4b5b61b1c41be690b3822f6624cc99c2754710893f01105682c8685c11e36536114f07261e1e6a659f7e25c59824af93030a773450567a6c5a7f0150c7331cd4f60566c13a2320f2bcf6536e6b16ede24c3cb69f451de672451367969a6dd6d0afa58afc7daa9b6fc450d802ba879fc22207289783a79e614d3cd4f6ab0652a6a17bbb7f9659d4f14241a08382a549f4ac102ad0f8d8dd9706f0db4efa9c2dbbb9885b4e961289961ba8b8887d0b9dd20f5101e0890012d39a9e115c87a255001287b08b29ed9989b670b802e485813155bf1398c0b0409be7c1cba4b0a388014bf5bd5218199e63afc8d5a1548342fa14fa0e135ac7e05a5b9e1c475b6e7e30c1a75d630c05b43125b75410d055744f35805232183d57915a0e6a28eba865c61201baeb03cac68fb23fe6090f67f80cdb5039bc45638afa0a36520ac20c9ebd3a0d55d3c46d0ca48e52de52bbe70c3c911fceaf6b96a2e748a69b9d94bde44d5d5fda738226d3768a5d96a0e20b112af01ff59bbdf9c9bbbcea6af9ac22b74c2721222c07842296c5a1de44053eea0870b94ec94a1b0b1710e3dabfa3aab9c49ac1b3e019b712c8da748b1859b2aa5590ec4a7e78f1f1461f4b23015a5a9f5dd2e2624be2098580cf8de4b470a799a7e6c8753bb02b10c1dc1e70bc26e9c6d89039d282a8edd20274b5dbee6184327249664742e733a6d7d7e01100b638408b3d0479e80980d58c026a347fad6733de51b013f983455e257215adc3761624288cbfe8cda20459104bd18958415f2c120704cae55d2ff9637fb599835745869c127a4522e1e26fa0eb8f04c8a6cce41b09be1b1965c05a6551f74530986b6d7adfc53ff80bbb018b56e66665df1b0455b25d34c18b4b5b616051af4ca559010da68b8fdc6bf998b39f0def85c9fd9db86960d9ac5d99ae685bd2686546b6391c08426dfdeb133de4939689c67c569a2f7958ae70d31b5620db92963e0af8e2c25377258aee1051c9adc749a0d1e87d1b1bc0c9a5c13468b408172832cd893e025076b77d5a496b1776053fbac2a8251c5773632b91c7505bcabb57605ae2280e30b94131b63fca8caa8b6ed8477e60cb5005c48d91952b25caf5c2c8743be2e6754b712c0710d4f9f94317fa24a411271f8b4e8669241d6ba9cf65b7493fba1adcd0b4faaaca6bb2d8d79cb4e233d704a6725e5a4f19e1f498a96e783817b470140c0a25551650cd88ae4fd330b4212f6d848ae902ff662573a0ca7a6cc63898a6eaccfb97613456309e32e800fa039735a486962c9a58493afb7b9dc0c4bd9b12bff7e767b8f6f42f7bd53d0837a7574ddafd04cde42234a4919981cfb6d8841a3c063e03a52bf8598b0f12d6a28f82a4177a5ee7c3c2af1f0675685f8ab3c41cdec3046081b268f7999d9a17555826aa6052b8357d0b68b606a1d503d6627bbe608a4ccf94851502946390448779e9ffbc99a8d66874e988774b508ee66a03c5c94ca6224a618caa1ad9e69091ca4aaf840b856e2c1742a0ef0b067eca80849e7145ea574c093a12736bd207a51f51379bcb2ac2f08532e5097b6e0455516b0aa27c2af52f406b3f29cdaa7cc9609becf1821dd9c9839221b86f01c6c1c93169bc0fc6f0864adf9cfd1966e00cd52fad9a9f522ca821a2a2dab40fab8e199aaac12e2f1154032a49c5ea7a4ec2341051714136ab7e5193de862f12005881933b4601603daf7056e2c8582ce56b2a9aca49b5f3411cb182fd85f5e586bbc8124cac764eefe16242de424d5f89d1f5ace352829554c6cf10b488c5e7513dcf4a2685c904dc0727b040d14e7d92115ec256b590ff1a9b2295d4e7be92638b21fd55d8ad23165318d844b252523fca19961b9d60cd76597541ca04dd310080127a2ab8145fe9a8ba5a4
+InNoiseS = c1e9a276ceae5b944e79f8c57ab825a58ba9d01a23cedd5b2b2172a3f8ac35e80b5a3f84c034e226219e78e800453f3ab95329bfe0f4c17246ab6193db9dbe324b5f07f0998d6d83d24208d1b51298b5166c66258d26d86278843e3ddd13da7ebe0ed24902765149465113fee9461a84af1a68c8bf76769603e82a21a693fb0442bb70f599d8982076b9fc36a42c46b75db8b1699544e557fe21330ee6b53bd2310e6dee459b7a6fb55cd640ab1881334542aa920a8ac4e77c87c60ab1c98ae888f42134db67a7b809c69fc81194c487f24b61a011b086d058cb4556b582c54e4f047f50531416539ea7c1f04e7db95bacd3afb616812285354344167ee4745512601dfdae2a9afaf531b40e16d86569420b2805722ad890ed17308035c8943a0daad4e8c8325e8cd7d0263803879ebf420df2b761a86939b4e19ab161ae22bc045acd0af1985dca8230a752150191b20890d0788b9e8e299d08fbd7664e9645c43940c1b06d1c8251cf859d158fb5b515e40c0aaccd90b370020383b71298cdb335803d4b58fd3c8217435218b6b970d180a284d17b7f61ebeb9a46b8bc476bf321010f06128c02e171763dcd10b655aa2542213b6467800f134284da21622f6c20c522d1d05adf9bed5b7a6d63a3ab7236074e1f9b999138ac258900eeaf68a8328ed5084a23cf7cbd851ba7c222d1975363a0770cc446e7c4ef51e49457eaab2ef1fce02a1629c68b12d1aaa3a9bf041a765030d0e2a719ca712fec479ae3f5a4c2caba024ddc2c4c2c354bfb5c55b62daccb7a068adb03253437f87438643ee9d86929d5681b52b87664ace83a2672daae7c1f6c6aa2c486f9e3bb31c4f27b32d047a6af990e08d36e3a8fadb376cecf67989c4977d33d56db106107de6e89849646132a23858514a8931ebd4383d2635f90b2f17b7d92eae259e6ab4da034992a1b6ff215254e78a930fa6cf12283b7d23c73e08788a645b55268ca37e6c49227bb5f2f536caeab9344b7904519509990616250f127201bf5631ec28f5b9b7897870282b69bb46a8854bb5a66f626f9b5a394e062e4208c194cd1b963747216d8975f28a2480dc04a0f31462287d463ab14969827aa2f4fc4c30e977153e9e992688c8ad0b5c3efd17a4b95ec910881311649e223dd8d9348e11f0183560b345a4064c1205d4d41fa5b2b5c60e00dfdb2f31199d8897ea960fd78e6000b7bbb94720d275d9bbc819ca124dcf706a27615209cea60b952fb90455a2bbe3d311b9da08798491684a6291e915aa80b1983d6190610a094173575a7772587408338571e8e248a0b255c18a2cf4684040d215f88da53e9a6114903c3683d3eed814de857742e76a95282d87877289abbe54efdbc9d1961b1176cb5066d3f0bf7556be86106d1d6e9a8bfa8d5fbecf460095821989abd55b60261c8287a137feaedb0515e45694721081851957e88d105db0d974d5d5cd5a9386a8a037f315abe3b809b7f1b6656ac2d269452a39868e66b8e49543584f0667614a9f0aef09a7d956370a6a58353b70196498924bfa073ad687b1ee1a768ecabb7ab15f22fbc71579f7463429d69670d2ec605119f319574e572ee229f6241fab912addb1b83d71bd143149408abb1c15bde84ef93e6d2693c9423d99128832629e6d75b682e0e0181a0dcf442b4c27c32846431a3a6d8690f1c188a9a4274bf284bf12bf0a0dc9672d358b1b6243a631fdefa6464f9463c89f7e423ce03fcd5dd22fd606372296b024baa86c8c922071842a5084a799392ad39880a8b50d9386c7d60f3920db18c1feceda8d72e36e3db48858c00b0e921e35a09e1b16bc54428e0f119b7cd07466af576ec1908f489206e8fcb16580a8271d612ef272f8a5e18c947e10ff2263b08e46527b42d1c993774ed4139ccc0b39566adbacdd1aacb0eb2aceb6dacaa2cb1818b53e8e4b2995ddbc4f399f86d80e6644a2550d129f0a21e84f8950aed8cdd59fd1d09470ea43a19ca7f6a8de69422f0b3078a87a3129a8d819478a470d0624593620182087f57c62450c5f1121486c377648c3e5118e59659c56fd408dee705beae9b412467884904c1488cea3fc51696471ef154f9547ee6ee4636ae578f0611b4311c83e744f186ce2013e8eb00633a3a9223e39ea9107a13639a4dc0457116d20899da92e623b64240d090460a43d88476564c630f99a049f5ce5e34d645c8890e71099f16ebc72121aa044685fdf187e166155736bc1429c85cab2c808c0a1eda3bfbcc737395b4845031807b872407381212efa6856b69b145db0c4fa936ad6f05a824c10f500ad9e91cca8b7c0d57e38c3b82a8bc6d8132b6ae16381604ebfbfd8e8416177ca560e2983963fb1b25ae28d85071d251493e4c27a34319f04eb387a592e62c95b7e8b426dffe2b6d2ca89a71e091bb15c542ad9cb4211cd789b95c13972b9aea65e12051af44020f52971e61324245e9154d528879e559644ec8f7470e06a6d897cb84a13a656ecd55a69dad7234c79da3450a4d
+InNoiseE = b123f788afbd9623d25ab427c24266da1a3104cead00810400d2c49d3a0ccdd384345791ac7f18527ea9968bcf80a5ecbc5b9830a46989995409b4c674442c820498c56acd262fcd76487e79186163bea2d9fd39a90f8d067da930e8ae17ab53cab136acf4c052613794e58c9b2d2d2cd087bca67714a6958189da4be411241d22b59fe2a571982203dda53ae4a19684ff5a6f461b5df8065d8fc10ccfc58c5a82b194e67663ed26dcebe96960287e2345a102d9712a1688f915e59e84608471cabc182963d809636669bf58ce70867c8d093ee4681416ca1daeacee7996aa15c8e5e4980621241354e8d6424a6cc42720683b509fb5a26566b1d17cd6c02367cfd67348128973544429c48a77f842f93eb9c2ea51ab5e0adde93a3abfdabae3dc6b73fa20a21b9e5984945621a49b0ba465f279b440c0c43f3252656d300429429c859aacd889127c880fe62167ba2afda491f25fac8cd09ae3c540c802b366be5787a264dbdc5608ca5863d5a964a39f58b5f84d122af9d11a8e63a2a5da74b205e7827baa9c23c9d6428117be6ebc6a204bd1243c406de5962e3c40a2561cfb612e45584d8d3b51a84e13d57ba4cba4077912f35654b62f5acd9c40368e12a45d14f661bab0aa1b03d547a430cf92b69424a4202e092f943e1d88b60d4f04c3345c6bec4cb1f3959d3d4041354bf492d318ebd3cbe4b6d02efd49d16e2c47a988233f39731fd68e8964758223a0e86829b1307b2b0828090849a5037b73cc49558ecebc25881d4dae4dca4967d81c7c623871315d0347ec9d9a74e2864a0542e4930036f487c8d980d043611dfe2b5e554678d1dcb75e3e489c6f6192275ca935d04c0af8a48e17cf6dd807d9a0df204889c2cc71e291d0b2db7dbe978729fb9130455bd91144405c8c7b006a69a258a0dc9bdfa20824b1665778896d41816e90348b88e811ee1e001692624f3d27ed5115545bb80928413a4a1dcb0d00e92ea29b55c7a2b4801a54776d63422650039044ef7baeee3bce2cbca65928252415e3f131e17d0625e155315144195c48f0317c22346595a360cc8f8be07f492e1e3a31e066074f3170a4e954f5af0672db877f1726d9b3e304b85ad81a80715b7272f13d9bbe2b1055535578ed19bd32327e9a9659d317b129545c8f2d1600da2cb4a5fc73452c839297695b211d52a021c5b283c97d4443f2523df1252fde96b1007467fec8a6157dc6426ee63fb8a56239cdc202a18c591fec875c39f98081d7ed08466344a48b244f40836eadaf219bb7f81ab67459a7189568047d811938feb0542cde5333b932ba2cdef78ada3d36cd10b2b553c025f4ae3e07ac82042cabdeea9fa69a0ad6048b6c113e2317808278f29d679ecb0b6bbd5a84e8f94b059a0a510a389add6e3f97d49a38646041802a13757bc69f16916d320f258d81ecb0484fb46098d2b64b171e418388fea898349d29d4e3452ff2a273810d24ae118d3de6364b3dea83d4a124340be5be610af4351f38acc2073880fea0705ae68c550a7488dc8de10be321987c47fd36949c8dc20603b73ed20699da946a5449b9220be249c9c1609bceea464fa834d9565bd7f9cd1b95e349978a8aa727a03f74778698164d9e537c04aae48333a0265563b1a7c8e3ec3043d5277fc79fa876d6c464c4d17e7d745cfd20f3786c65e546eb74565984aaff0550427a074bafc6bc583806a2eb5acb151deeca2c35a8fa2efaefda17f5242df2c2f6a4baf16b2d689995ce7896ec93c0f81901a0789ca76814b49c8d56d846546472984603d521924841def323a36c1c0d23f551151124c40c1cd964481888aca737640128cc9b6feb821855cf1392b5ad0071fe6389386ded227eeb8f4af27a2fa6128fc4c0a9578484182830d97594ca8b856c3c860d9896383649aceb8240aa500dbf1b540d0820a232d4e86b676ecd59b94993452b1e20152385784af462b806434398262ee884d4dbaf1c5f9e5404d13f9c5a5e83ffb39eb26a5414cab5f479653bc916d95b49b5d8a621e95a588246052602da45a080d3f928c4c4820d455a31673924dcced89af2a4bc2a815621fc4d9500eaf499d2f42ee7938a28dfd8089acc467bcd104a93a097b211a4767f9846a75cecac405e35228efd3ecb0ed72a85cd3607832f4b5c6e8d7b97319afa1836eca366343a896439de14d3ce3e2f0740e3bb79e9ab275e2b7523f6528d0ae6d22185ad89a61d5541ee33940e3e9ae556891f09090a22f4bdb303dea398bc99790a1333555d9a50aabde3b9e6238200b8254a8eb8c2920711a04978508615a3a6803b5ae4125890fa1ddb2e7ada364a05dfc13d645f8d8c7aed656a62c4a1f0804bc4405c2cbb5ff068d0e4979f232508a6166deea5c10149567b3b8b0ceb967d002ed3deb381c68a8d0fe71ad4301fb815c2a5c9f46f0ddca0d8f20205b38aa1b0fd32b0f6e91ed8f4b0b6ae5f02523772599e50f1f770aca9705cb563600863a81f4f74073ca4374cc89737f2601e0214e143920a
+OutPK = 535792f6599d034f5ed9e9b5c5b3c10110f32ec45aad4ad1315f9268a65f8b97d6f1b2d4200711378574d62e6c9b71b16ad3d5b70bbe4a8f538646973f5c076028a0e7386962f49059e3dc20bc724f4ad20eb9402a5d1df57c09762ecc2804a9fe11c42f085a174c2f0dc98be0bea24e3e20b1f88df0545f59bee80282b166861a43ca8273a6013f760fb2bef65c37789b1aaf02220dc155d153884a40359e511e9c23a6f2434916190a11fa75320d6945af461a921ed2ea3068cacc33822147e9b8cc59f4c958483039a50d145d5b7974136255185478587528697cc20f989a2912c6324ad4273690b34baee43c26dfcf01dcbc4dab41407bf246942dd41d1926b24150aad8892b58116895ef53bf281088439c8947189d00879e931192379b9633a1235452fa283718f692a7f566272575be6076a995ca80149841abbc43d7941d810b07687b0e1e9e6d2d439c1d1c8a47f486a41a2443e7d95962224af6562c23e6e5533c2a82009d241424daff48325aab87867924d0ed1b57166934afdaa52296ab097aa2181328f88995b4095519f7545518add8610e0aa5ad32776986fab0a9b83cd860f054318b1de8e366df454bc26d8672dc89b4aa268066067e2727469d32463253f0aae277bead7f9d1090d215e6b3a116268617766b75263c4ab6ec010918e566696a93dd2267d30321897e8507fb348511276df33497726bb4c1d4d38f0049a5cf4cb5841c61e96dec029218579b100539be5216891914606f1a97cfabc284167e8ccf1acde59d0c61542085a6ec490913500e488a389940a376d1d799b4332e470a44190ea2a435770feca6bb46ded13790206fccedca4192a77948eee594ce6e064f49f5e7bd85baa272a67db9a68a5d9b44ee0495fb434579bb9a2c6be16c79d1545b85226b469bb857e2115317bdc91c0c2333c1e7000f476c522685b52d98dacf7325241900f08ac60aa225f52ee134978617c78d68726d76ad7e27b7776c1827674d267a1f0551f503ee960b3e3a7aa19af0640e3cdc1381f74542a13b6629d337c2980f40ba664461a982c5e736ba4d841c248ec345b05f9b46669a44043903453f03dda48e236d6714bd4e7fa89912d991a1696e40bd82fc0669b7d883840d624a74ed7fd7d6b57a549c231a2a4c1fd5aad98699607be149d65244644656d93f0173c02f53cd1c79b62e80ecd82cf5774a69e05ae0ea7a1c02352d499821894e9286d4077af49e9441acfad4b21465dc0dd359b07fc4617cc316e1a4954b55542bf07d818efec0ea15abbd04e2e90230ac6f6dde24084238cdc56649f1209f0ea0e3611c2abf8d45710184f4a54a22202652ae4a5ee9f720b4a023fe4493c6d22971b693f0fb9a194a8c9a41789b1d7fd020faa3c936a91de323d0290c84ff978695b09643512f6205a1e1150d842521718c0544812a6855ba63cfe15cb2bfb16dd9aaa54b1ce8302f568062c14122d767082afaad9c3d85ad148e969a1b0ed8d19516427f297ab8eb1e719e81a2b6e6da0148a933e830fd16650c66a3b2d57b4c0269504c11121c4ad1a0c839b8650416850deda33fa31d35d7442fdac994daef5127b3eab1a1587034a5ebe7911ec46139ef3b4b8c8a9889ed2412172d3c8a163f413d1dadf51c3e60df100cfd2474730cc63aa221b863b2a2271b8b1109610d417f489ecbeed2362385c127625c0d50a0ebc3fda5a5d1e645e890924dd38044eb645887795a02b6b0ac48fe813f17a47c7b53e58d15176110fc9b16b503f297b4dc6b28fe1148e96ffbd408e41489d201c590b2285c0309832a3e22a7441c70501857f1ca0744a0e20910683bf023b6397485246600f161d927d0d9c34d7bfa59fc7326b450edd9ba45b621a3ce9315914c798d96a98d55544051536cf082674e13ea14d8b028bdbe99451d0774cc85354afa87f3648d36c9b8a657bd595e2ea80061b6a9059baf41a652961265aa42882d926fcd4b91860a229ec22561d596b26950976b08719ced1e8469536d43f9a8a69998ae4ebe435739b811474b1c48721bae7aa36d40655a9ea69a1a5894033953f0d6e488d1d62133a9c309c3d49e8c4cae0acba512519d11a0997e81215cf55ac0ccaa055d6deb039c672ea8ec81b34a175b45c9448d45a1479c84d95031216c0b8f30cc286859daff9a6a8e4d836d5ea33cc030532de579560846311e7b496a501bec2de3ba760d3f0e609659f4109f0fc1f6c70df56eb6122bc08082784748f375fa9859bb2b6207a9550bea67af4bbd141a5e591ea83d392af2675575ba4e19636bf6c1670a813414d08b5fc989e49d8840ecba24a6d192d63a11bb6167a610f786a769039c83d99d9f0fc6fa89ee21a475c7960918fe5e70dea2da3c5985aa63f6889886a4b8631eab5910b9f0578ac94c919a5c42167435be09c487e496465213bb5e9db5d8658abc2a6416c68e873a8a3e224c9c18bea9b8c983c53654e5df65e065205721dc199cc442440b6727b610822cc9f4d044511e7fd673f168cd26
+
+InPK = 535792f6599d034f5ed9e9b5c5b3c10110f32ec45aad4ad1315f9268a65f8b97d6f1b2d4200711378574d62e6c9b71b16ad3d5b70bbe4a8f538646973f5c076028a0e7386962f49059e3dc20bc724f4ad20eb9402a5d1df57c09762ecc2804a9fe11c42f085a174c2f0dc98be0bea24e3e20b1f88df0545f59bee80282b166861a43ca8273a6013f760fb2bef65c37789b1aaf02220dc155d153884a40359e511e9c23a6f2434916190a11fa75320d6945af461a921ed2ea3068cacc33822147e9b8cc59f4c958483039a50d145d5b7974136255185478587528697cc20f989a2912c6324ad4273690b34baee43c26dfcf01dcbc4dab41407bf246942dd41d1926b24150aad8892b58116895ef53bf281088439c8947189d00879e931192379b9633a1235452fa283718f692a7f566272575be6076a995ca80149841abbc43d7941d810b07687b0e1e9e6d2d439c1d1c8a47f486a41a2443e7d95962224af6562c23e6e5533c2a82009d241424daff48325aab87867924d0ed1b57166934afdaa52296ab097aa2181328f88995b4095519f7545518add8610e0aa5ad32776986fab0a9b83cd860f054318b1de8e366df454bc26d8672dc89b4aa268066067e2727469d32463253f0aae277bead7f9d1090d215e6b3a116268617766b75263c4ab6ec010918e566696a93dd2267d30321897e8507fb348511276df33497726bb4c1d4d38f0049a5cf4cb5841c61e96dec029218579b100539be5216891914606f1a97cfabc284167e8ccf1acde59d0c61542085a6ec490913500e488a389940a376d1d799b4332e470a44190ea2a435770feca6bb46ded13790206fccedca4192a77948eee594ce6e064f49f5e7bd85baa272a67db9a68a5d9b44ee0495fb434579bb9a2c6be16c79d1545b85226b469bb857e2115317bdc91c0c2333c1e7000f476c522685b52d98dacf7325241900f08ac60aa225f52ee134978617c78d68726d76ad7e27b7776c1827674d267a1f0551f503ee960b3e3a7aa19af0640e3cdc1381f74542a13b6629d337c2980f40ba664461a982c5e736ba4d841c248ec345b05f9b46669a44043903453f03dda48e236d6714bd4e7fa89912d991a1696e40bd82fc0669b7d883840d624a74ed7fd7d6b57a549c231a2a4c1fd5aad98699607be149d65244644656d93f0173c02f53cd1c79b62e80ecd82cf5774a69e05ae0ea7a1c02352d499821894e9286d4077af49e9441acfad4b21465dc0dd359b07fc4617cc316e1a4954b55542bf07d818efec0ea15abbd04e2e90230ac6f6dde24084238cdc56649f1209f0ea0e3611c2abf8d45710184f4a54a22202652ae4a5ee9f720b4a023fe4493c6d22971b693f0fb9a194a8c9a41789b1d7fd020faa3c936a91de323d0290c84ff978695b09643512f6205a1e1150d842521718c0544812a6855ba63cfe15cb2bfb16dd9aaa54b1ce8302f568062c14122d767082afaad9c3d85ad148e969a1b0ed8d19516427f297ab8eb1e719e81a2b6e6da0148a933e830fd16650c66a3b2d57b4c0269504c11121c4ad1a0c839b8650416850deda33fa31d35d7442fdac994daef5127b3eab1a1587034a5ebe7911ec46139ef3b4b8c8a9889ed2412172d3c8a163f413d1dadf51c3e60df100cfd2474730cc63aa221b863b2a2271b8b1109610d417f489ecbeed2362385c127625c0d50a0ebc3fda5a5d1e645e890924dd38044eb645887795a02b6b0ac48fe813f17a47c7b53e58d15176110fc9b16b503f297b4dc6b28fe1148e96ffbd408e41489d201c590b2285c0309832a3e22a7441c70501857f1ca0744a0e20910683bf023b6397485246600f161d927d0d9c34d7bfa59fc7326b450edd9ba45b621a3ce9315914c798d96a98d55544051536cf082674e13ea14d8b028bdbe99451d0774cc85354afa87f3648d36c9b8a657bd595e2ea80061b6a9059baf41a652961265aa42882d926fcd4b91860a229ec22561d596b26950976b08719ced1e8469536d43f9a8a69998ae4ebe435739b811474b1c48721bae7aa36d40655a9ea69a1a5894033953f0d6e488d1d62133a9c309c3d49e8c4cae0acba512519d11a0997e81215cf55ac0ccaa055d6deb039c672ea8ec81b34a175b45c9448d45a1479c84d95031216c0b8f30cc286859daff9a6a8e4d836d5ea33cc030532de579560846311e7b496a501bec2de3ba760d3f0e609659f4109f0fc1f6c70df56eb6122bc08082784748f375fa9859bb2b6207a9550bea67af4bbd141a5e591ea83d392af2675575ba4e19636bf6c1670a813414d08b5fc989e49d8840ecba24a6d192d63a11bb6167a610f786a769039c83d99d9f0fc6fa89ee21a475c7960918fe5e70dea2da3c5985aa63f6889886a4b8631eab5910b9f0578ac94c919a5c42167435be09c487e496465213bb5e9db5d8658abc2a6416c68e873a8a3e224c9c18bea9b8c983c53654e5df65e065205721dc199cc442440b6727b610822cc9f4d044511e7fd673f168cd26
+InA = 312dee62b48992a86afc71cfed062c85e5f76ce279f42a4e0561540685c1cf72fcde7f4720ef87581496c59d3cf0d14a745aa1f23292c56ca380c12045b184669164c73c3a2492af440a78453a1012fca13d290be6122cb832ba9de59019b8d0a40b6e2a8a99483931b5ee2b4971256cc31107c2cb14503e079d27570e37ac03c2aabce21990c0e4693c2a4c0eeded78361503d9023fd60edc742463daa39d32826ba8eb136dc02e6fcad62aaec67d9392a958ee094ba90b53b78c7496941644a04e7654ef51d18b66c80d4b55d9c3d5153760e8cb8495182e0a8ce50327142e286c27303ce56edaa6f74683cd8d10ef12d9970c30352574c06bde230f00d089214c6ad913333430a903f5253f13fcc4249b50efd5f0ad0c7b450713f84190e722c8b368b044744ee5c04172719d48a2919d3815c0c47a04848011c5843ea755007b9458a7c82340a243045d017946651ed32172980e353495df914ad64c2ad4ba925e4abd2b2fddb544386e4dd65feae8e2b0ccd0a2d2742c8666266762b4b6713b17240b5776278a6e1ad4c2d42ed64d32b14cbc66e7cc8844510a30faa9bfc179566034865ff0f7fc5510ca31e3093d39ca23c5c5d2e4b5b61b1c41be690b3822f6624cc99c2754710893f01105682c8685c11e36536114f07261e1e6a659f7e25c59824af93030a773450567a6c5a7f0150c7331cd4f60566c13a2320f2bcf6536e6b16ede24c3cb69f451de672451367969a6dd6d0afa58afc7daa9b6fc450d802ba879fc22207289783a79e614d3cd4f6ab0652a6a17bbb7f9659d4f14241a08382a549f4ac102ad0f8d8dd9706f0db4efa9c2dbbb9885b4e961289961ba8b8887d0b9dd20f5101e0890012d39a9e115c87a255001287b08b29ed9989b670b802e485813155bf1398c0b0409be7c1cba4b0a388014bf5bd5218199e63afc8d5a1548342fa14fa0e135ac7e05a5b9e1c475b6e7e30c1a75d630c05b43125b75410d055744f35805232183d57915a0e6a28eba865c61201baeb03cac68fb23fe6090f67f80cdb5039bc45638afa0a36520ac20c9ebd3a0d55d3c46d0ca48e52de52bbe70c3c911fceaf6b96a2e748a69b9d94bde44d5d5fda738226d3768a5d96a0e20b112af01ff59bbdf9c9bbbcea6af9ac22b74c2721222c07842296c5a1de44053eea0870b94ec94a1b0b1710e3dabfa3aab9c49ac1b3e019b712c8da748b1859b2aa5590ec4a7e78f1f1461f4b23015a5a9f5dd2e2624be2098580cf8de4b470a799a7e6c8753bb02b10c1dc1e70bc26e9c6d89039d282a8edd20274b5dbee6184327249664742e733a6d7d7e01100b638408b3d0479e80980d58c026a347fad6733de51b013f983455e257215adc3761624288cbfe8cda20459104bd18958415f2c120704cae55d2ff9637fb599835745869c127a4522e1e26fa0eb8f04c8a6cce41b09be1b1965c05a6551f74530986b6d7adfc53ff80bbb018b56e66665df1b0455b25d34c18b4b5b616051af4ca559010da68b8fdc6bf998b39f0def85c9fd9db86960d9ac5d99ae685bd2686546b6391c08426dfdeb133de4939689c67c569a2f7958ae70d31b5620db92963e0af8e2c25377258aee1051c9adc749a0d1e87d1b1bc0c9a5c13468b408172832cd893e025076b77d5a496b1776053fbac2a8251c5773632b91c7505bcabb57605ae2280e30b94131b63fca8caa8b6ed8477e60cb5005c48d91952b25caf5c2c8743be2e6754b712c0710d4f9f94317fa24a411271f8b4e8669241d6ba9cf65b7493fba1adcd0b4faaaca6bb2d8d79cb4e233d704a6725e5a4f19e1f498a96e783817b470140c0a25551650cd88ae4fd330b4212f6d848ae902ff662573a0ca7a6cc63898a6eaccfb97613456309e32e800fa039735a486962c9a58493afb7b9dc0c4bd9b12bff7e767b8f6f42f7bd53d0837a7574ddafd04cde42234a4919981cfb6d8841a3c063e03a52bf8598b0f12d6a28f82a4177a5ee7c3c2af1f0675685f8ab3c41cdec3046081b268f7999d9a17555826aa6052b8357d0b68b606a1d503d6627bbe608a4ccf94851502946390448779e9ffbc99a8d66874e988774b508ee66a03c5c94ca6224a618caa1ad9e69091ca4aaf840b856e2c1742a0ef0b067eca80849e7145ea574c093a12736bd207a51f51379bcb2ac2f08532e5097b6e0455516b0aa27c2af52f406b3f29cdaa7cc9609becf1821dd9c9839221b86f01c6c1c93169bc0fc6f0864adf9cfd1966e00cd52fad9a9f522ca821a2a2dab40fab8e199aaac12e2f1154032a49c5ea7a4ec2341051714136ab7e5193de862f12005881933b4601603daf7056e2c8582ce56b2a9aca49b5f3411cb182fd85f5e586bbc8124cac764eefe16242de424d5f89d1f5ace352829554c6cf10b488c5e7513dcf4a2685c904dc0727b040d14e7d92115ec256b590ff1a9b2295d4e7be92638b21fd55d8ad23165318d844b252523fca19961b9d60cd76597541ca04dd310080127a2ab8145fe9a8ba5a4
+InNoiseSP = c64a30f40c2146684b38004f9863741b2214bf060817d2d629f93e74cbc804336cc16adedf04d06e9d15a08426d15811a0a649cdd63ec59b4cafb7713b793d3c06f35b70a516eb932cb0086ebde5c3d7ab1f9017a10a0c382d3a7add8ea8195fc1436da06591293178f58ec70abb2e967ea9b6da0488995f593608c815a48c9c26b8035a33496efde470043b6cecb9f1c1c4b1eca56d572a382fe34df759cd15aa0465aa29e16e9fa71e673784662d534152db401db62bd0762864e84f392da410da063ca169646429fa5f361798e26fde806c9f268879669791adee4721d071b1ef4f7a6f64508e44e1b47e2c3bf0c12f77b4350cb2cd1f96d76415af453d016bbd638aafa1606d8e58eec8e1a0de86b466d6f7b7cf469d1d6e1847bc5c6874d78bd9b14a630be4c6db7b8529ef8fd18832084491635ad6c97e55b9a60bf0a4ea4899017481dd39a3420269417c71a520d7a2b3458d4f4e4a63777b14bb84ab31f2561c14005466c58a9e9a588d96c252e17d8e82cb3509d406c151f0521d9d774ad166675801a54ca6f0993dd12cf15f44d20da8b9fb052265bcc6524ac95221377834348cca46a23804874b12f9641418f6454b4612ecb7ab1ea664e4047fec42b2790cc6903b1205c8ab668a3596b3838ee958996f09d4be74ae0a18ae68ebf99c2d51df8ac3789cd2ee2521bbce27b4c718a6a4a210c124e54898d9ab04295e11e7ed01bb5b4d12cd9e341e0293b539a8ba619924db875d1f30959499d70186af9b64922099989596ea22f9399a0da0c2b049913bba52836a0b9cb0e6a0b225bcfd2c808e9292082977b7ecdca3b556bb354eaa2ab2a5bec6cd1d029b561789d28c523eea3822ab1f6468beb9b06878bb7ca69ebcc5e0c4ce9831ed2ed4e6ef4c01812e20054966b06a93e5896c2a054e14c90761793b3b8ea562dffd99a71b6854283833b590b5f03d7ca3f25534684491091e17dff72c9174474f4ad26ace5e51a5f78308716878d1ee07bf441f172b3472ec324cdda53bd04ac00faecac6a012a97a6fa22817ca217517e2b6c9dc74245a6a0b76260d4bfcc5d4a2de267815968c580d5dbeb2ad5ca39c0e979c184d39cac65cff1860f589c895bdde0dfbf45450361bfac39d8208df9d87f476c966d8daa8da7d1a5ff25a00d3a771706cce66a2e0e827fc9c55c2f442a831012df93b3035a51a4371049155cf154a96f5546d65c14e0136483bbfddfcc1aa2928b71010830a60191f9808840c3c894cefc2755ada5ce0a3dbb34eee0a0725979259425ac7678d834296039201cc4786ee974fa49497931461c95fbccb07555d0e60184664344992da6d42c9253c176deb548996a41be23e7a03e04badcbebf70dc6231a176aabb310438e25c379f4796d9d038cf7f8ac99aae2abc5639abd3f038e722465b8e45f01a2587534de24fa77d2b1ac5d882346a4422ae3211fb0f751a25c92393524619bbb014eb1564a245be8fbc55eed48356004e56d396f2f55a9daf9e0a35da47f23b7940caa0d2e26d4d68d88c3dc7a180637726da7336ea68fa4e5a8c124342c93e825a47419bc47e43b747e8c45558fba94e8ac0b5a0a5b51bc667b114c94064fb192b7182ab46908916a233fc959903e065b4e14991224c1a31424a18a0445e5c1ebad02ae87a88b72800d694c6bc940df3574f7501893835298b842c4d2b31063d91a1399e08a66a6886b59ba426f022d2317f5b298cd1dc1b1df3d8d4bcca913754a4b1946b39156357add4143948ac49c8644779b5ab1b7036193b7788d9c2ba55d74fe8d46c4840d7b328574320942f5f3e5150feb3079ce2c7abe5923e62c217e6f4e1f36b5796838c617e75f7921cb9a0043cfbd4da225f6f45492ba7f85dd51c62695f94bfee8d674b32b81de685530b7bde2825b000c3e2a8eb1f44c1a52cf23cea72fd517f36f4e587dde8161093f7801693e71e9f1d757f8532499a414a96aa16ac8b1409bad18205ec0646c5546b4047b06382101c521ba414d6c3b5f81c3b2c1898fe22538222cf825ce50a8b3dbad37e04db1f538d1701061ed41ba593acbcd3ee198442b5f1966914930129c8196e5cc422183ed2726b6fcba19c8d285ff0ab0908261d713856e12a5c198f9b2913fecfe95a0a4b4c5125eb87d640514961b5720582fa4d6ef87ee653a805570b4a326a6c2c2a46398fea5ed1e1fca0c857799de7a4b2258846adcae3282417e936bda359cd4893e118b363379125d13de48764a8cc2ae391745b263c0d55978900a7ff39902c5f6f85a8a254858dc529f4c6e2451ccbd140e82e9ab60f045efa83a12390e62060e920bb30eb09c289325597e0a819da13a0a555bdd8491599975a12c9f2aa7ffc660b75a2a0735749467ea7475131da2488427db46725242819dbb7bda96acef61c1367c62254f4868eb0d6de1082d70370849764b3bc02035af46dfa474791a82ca87e433d62174b6dca59532a59d0560d6b0779e7e3be36d9ad9723abd0e9bf8e9d56914e50140d8de2c
+InNoiseEP = 1084eda5639e2a95dd2c094281973c88e05852785c2d8e11822d4e257b8299449f751d69d084fac98c6a216e028ba52dba4015ead204e893ebd62d323cde8580a99f05b56676a441b1d636fe553143cc573e1855f24c667a9d8433efa38af3e0de544743e69769880796e95e6006919ef5ac9c9bb7d416719b2ad80de0812e11e3d3c541976e1f405662f27aa11707b8a858bee897caa5e0d06d9d92ca099c75a747e4dda9340a8b2c8d63ab767279e7669e7b66ca2718851bf0adc494906799c5b25e744c06c74445feb2e8ae88161079b46bec4cd920de6fc59de5d2d3f96f8463b4ba77ec7eb32fb3b0b1903661072bdb6018aeffa56125b09016e89a40817e38607eaa801191a493cf0e96207972a24561bdb40c3da2d78903957ff268f0e9dc3a3f3486fca5075a7cb832b2a08919e9366f1d4b2761a63dbec44fc5b5aed5b0742773e58d1a7cdb044204883d31b3a1d8634ab26f53846f7372587afbe4cf471fec7068e574e89d9c2e6ce65217d0cc6fe6620d1601e5b762d36a54eb6612d7ad663bad406111d2cc3618dd891d42ca66fe3944f38812392bbe8b9086e4f259be81b7953756532d741a51087377a8044013760a72806b108c055173dea0dd813f8a70349b9fad63b44f20a3b0418f4548316fd26cc740b6e9b324930b252822267b656fc1882ea0856301971d1a7e3fd1630a9590b96d16e7c71e1d808d00ab899f780809a612c2fa152fc4497e50622c37d69447c6ccfd0d355a10778cd1b88894c9d47ac12ac7a4b311d359863caef86aea8d7416576f161fd92bab081cb8e06d1d198d6e9b0895583a651a229b250778dc049710542594c79c45f338861e679cc554e6be3c2740a8733655e6c5aa5b8bae797f5b442a58599f321ae316e592bc380b879a87483eeb9d9761a550ae9ad46940056582d11ddd6870108b16a4d53b11896c6ce60ce1415e3f3c082a6a10413b354250b0d97561d4a0b9f36588137555c21824440b2f928aa6e3403a9061fa4b53cc73dda4cfa867449d5c65a090b16a87500df94b4a08882e11910bc51ea7fd06eda4a7a66640c6ca915ca89ee5cf322b57412d8c4d8d3385ad147241ea978f4282acc3dd10f3ba036be51646a3c63f3c578380b6687a816fd0c2dba86d9e8ba79940cc0b7c49e1034681227cddedf2ee6e638549141af0744d7d817730ea98aae4d0bdea72fa9506511714c64574da0e3221b1ee52d4deadd3bd9934752fb0c3a4f148f64f21a2815131b842ddb6680c49c21ae3a7c9dc4e5c405b8964728d67499fe48665ab7993b91a972e543699e7336dca6a889a8a3636a86cc7df9ef9234a1855629a01f592a6b8c6509bff789f2c446f81ae591b8458b5089f10984fdd8bbbf46259b91009174b4a8d2ee32fe1c190360d91d251638661b4c7e8ea623e6a2ac138f1aa8d9a2a2c5c87d83a972d4b36133b69416e8af142a5a612f0d7b80138b9750ddf813b7ac8204ad789bad2e166a5e3560589c14e9389a6932c743fbfc78cc047ca3a06da436baf8c0a651dcb74e356b9e9e7b7e3d92c88ab0920e54dae161491d1907159b7bad30e16db74547e061f3b732a819ec9d565cd769e915c8802a59528f05e2d70a04d991b6af9d4df6c122b6ffa15c62db8f6eedc120f7232a2e03a1b1442a67da1d6463af40d1ca8b2e2ccc5845c530036a6085b7f2969162c58aec6ed2ec71334583f93c47043e94c34d2cb2640f5b0884f1bc3ae9e2658e9d40b18c89540542c877e7252daebbdcb1c8d0c5ee5eb6ab46a3efa8ec02877362f562190614c65893a0240185ab1445727e5b400ed996184f0076a155134242de6923095fc65812a548d57de2882483c194f8a92d765d51119ac195ce56b785865c3837806f516c5566c5a32e5493e6da2f7959c7f8e2ca03a5b46b488629e463436956f2381f938a0311dc4950b3b56164598b2d71b1515492630449465bc888dc14b7bbe7e3cce4fa2f0861d52633f3689f068f19645525c4c09b01af422d95c9b480e1f0a08691ad98d29940a22260296e85436e47f891eb2f27261050464c7c1603c904b59c268c98490b42f4b7992c952d316c14a76928b6c0d3a19a93427ab6f8f503bc087bc4bc8227990378ec9a4c8bda8282f4aac76572519802d89e606a031209bec03b242ae73a6a1c839e513b50415d9684e58eb44e90a7c7957f4accdf87fe46ebf45eb12e8665395a5e357ae64284c841ec664bd9b1f2f9f53594d96bfa367e47fe6338804c6e03409aae54c9a3032702bb50fb3039bce16b0d00f1a6d747dd74d17054f2923f8e43316006c3b82e4b3b003b551ba534f1a8a45bdbf1729813f2005812edf29df358f629047ab933dafe59f998a854421621fcdc10726309122843347a07671c91f048dcd1d0b2369988ddc13616064838be1852765ec9a145a2dd6247afa521a42ef885cbb0e226fd84f8693d0f836daec92c75486a8434d9cc40436b9866c90600e000e3ade202446c145866931a138e66d96cd25a256219b
+InNoiseEPP = 00c0ff2b00fcbffe2f001c00fcbf00c00010000000040000200000c0fc6f0030000800ff2f002c00080000c00040000c000080001000fcbf04800030000800fdaf000000fcbf00b0ff1b00fcbf094000e0ff0a00030001000000c00580ff0b000000ff6fffdbff16000180ff0b00130002c0ff0b00f8bf00c0ffcbff0a00fe6f00b0ff1200fdefffebff02c0faefff1b0000000400fffbfffebffc2f00f0ff060001c0ff2b00fcbf0440013000fcbfffeffffbfff6bffd2fff1b00f8bffe2f002c000400040000acfffabfffafff1b00040000c0ff6b00f8bf0200002c0004000300002000f8bf0080000000efbffdafff1b000000ff6f001000000000f0fffbff06000580ff2b00fcbf0400ff2b00f4bf0400000c00ffbf0180ff0b0023000380005000fcbf030000e0ff02c00040001000f8bf0780ff2b000800fd2f002c00fcbf03c0004000fcbfff6f00f0fffebf0380ffdbff120000b0000000fcbf00f00010000c00fc6fff1b00f8bf00b0010000070000f000e0ff02c002c000200000c00030009cfffabf024000f0ff02c0030000000007000200002000040004800010001000040000e0ff02c00030ff0b00fbbf0080ffcbff02c00180ffcbff160003c0000000070001c0ff0b00f8bf0140ffdbfffebf010000f0ff02c0ff2f004c00fcbf044001b0ff0e0001c0001000f8bffbaf0010000400000000f0fffabf007000e0fffebf00f0005000f8bf04c0ff0b000c00fc2f00000010000480ff4b000c00feaf000000f7bf007001000004000030001c0008000600ffebff0e000000000c001700fe2f01000003c0fd2f01f0ff0e00ffefff1b00f0bfff2f00fcfff2bffcaf0020000c00feefff0b00e8bf0380ff2b000000fd6f00d0fff6bf0440ffdbff060003c0febbff0200ff2f002000f0bf0280ff1b0010000000ff3b00f0bf0030ff2b000400007000f0fffabffe6f0020000400feaf000000ffbf03400040001000fdefff7b00000000f0ff1b0000c000c000f0ff0600feaf0000000000ffaf0060000000ff2f00ecfff6bf0200001000f8bf00300000001300fd6fff0b00f0bffaaffffbff0200fc2f0110000800034000d0fff6bf0030000c00100000000010000c00010000dcff1a00fc2f000c00f8bfff2f00300008000500001c000800020000f0ff02c00070000000140000b0ffebff0600010000f0ff060000f0ff0b000700fe6fff0b0000000100003000f8bf01400020001000fd2f00dcff0600ff6f00400008000480000000f3bf0400003c0000c001c0000000070000300000000300ff6f01100000c008c0fffbff020001000000000f00054000c0ff02c0020000000003c00040ff0b00fbbf01c0003000f8bff82fff1b00fcbffd6f004000fcbf0100000c000b00ffef001000f8bf02400030000000fe2f000c00f8bf030000e0fffebf04c0ff1b0020000240ff0b000b00fdeffffbfff6bf07c0ff4b0018000180ff1b00fcbf00f0ff0b0003c000f0feebfffebfff6f0130000800058000100008000640fffbff1600fe6f010000efbf014000000008000000000000fcbf007000e0ff02c000f0fe0b00000005c0ff0b000000003000100008000100ff0b0003c0fe6f01c0fffabffb2f00ecff0a00030001d0ff0a00ffefff1b00f8bffd2f00ccff06000000001c000800ffafffabff0600010000acfffebf0300000000f3bf00b0ff2b00f4bf007000e0ff02c0014000f0ff0a00010000fcff0a00030000ecfffebf00800000000f0002400100001000feefff1b00080000b0fe0b00fcbf00700010000c00ff2f00f0ff160003400020001000ff2f00e0ff0e000030002c00f8bf0280ff3b000000020001c0ff160000b00000000700feefff6b0000c0018000f0ff1200feef01300000c0003000dcfffebf0100000c000400010000f0ff02c00000004c00fcbffe2fff0b0000c0feaf0100000800010000000010000080ff4b00f0bf007000f0ff0a000040fe3b00080000c000f0ff0a00038000f0ff0a00fb2f00c0ff1600fd2f003c0000c000000000000b00ffaf003000e4bf02c0ff4b00f8bffcefff0b000300060000fcff02c0feefff0b00000000f0002000ecbf034000f0ff02c00080ffebfffebf00b001d0fffebf054000000003c0ff6ffffbfffabffeefffdbff1600fc2f0000000c000000002c000c00fb6fff3b00080002800020000800004000f0ff02c0018000e0ff160001c00000000400000000acff0e0000f0ffcbff02000030002000100002c0000000070002800040000400fdef0010000400ff2f000c00fcbffc2f0030000400fd6f000000040003400040000000034000f0ff0e0004800010000c0001c0000000f4bf030000ecff02c000300110000000fe2f00e0ff06000680fe5b00f8bf0380001000f8bfffeffffbff0a000000001c001000010000000003c00100002000fcbf02400000001300fd2f00100000c000c0ff0b00f8bf0000ff0b00f0bffd2f0010000800fc2f01c0ff0200
+InRand = dcc79ac886c7ea2fb60721ed2c18a72a4684f1a2668c8bab4b7cd6de29e9834c
+OutPK = d2d75576a45915b2cfd75b4bf06b375114e4f74011e94172661f6644abce4f161ea0558ea13e358eb55f624a6191b25c6ae818f358443078ae43df8a800024254fd9191219b3ee6e2cea5fac0e0a0a5b8aff580b69972b592c311b65ea283267803a7407a663685e87419482505288759406c311ff79b69fd50923ba10120fd14849689471f3d74e74fbb17dd8a7c6e3315147b4d2b6e10b1d8e5fe5c0f9af15b7c80d2d165779a2ec26518bc9d8400def4707f2d8598e56f20501729f3fedd5fb136dba0e5539670a89906e9fab0327cd647d5a9c80e9dd5501469123deb9654d477b297cc4b4efa0f39aada4a37b54b94715a53f3b4bb2f2af109627504db876f505d020fa2103ee81862992a3be24b14749f52017460e83adf847a049108eca92294d117b1e6a146829a5b5699b73312d228a5808e1b11ff174484cf9920f20a016cb8aa461ad41ee13ada4f26d223d8e0678205a079e0de22b51a1265b86c015ab1132c19de6fb09650cb1a33f14eed944291b4629133a3c156e7bf85dfc0887a753a72a5930e8890bfb59fc1d5fe926fb30be72d520c8b6a5908cb5da4df7a34135b3862cb85c1162202dcea8a0a843ea441004d0d4a7ee90372174ba8a680b0137ec4887f44898e3c0a22e3696c33a7a76980b8f5c45ea126d769c6a337574384927e5c17090bf8a506edb6b60be7a9a7b5a32851aab83b2c4d8a66a44636261a6f0b5e72830c2edcc38069039701d58aa0f4730385f449cb3069e52b38d55f2d7ac981bfa15af4bad04200964b8e8aee47a7420f8e428ba9a5005ba89b323a8501fa3a5b0332895a865c408b24c7e8d8ae0f710880dbad5d0920bf676a1340c7e77b1fd2e890f3aa492ae2c2662bdb451f09e17623353d37eb0cd20a7c96abe0ffb2ffc42f88171374580e27b64a550ca636aed8e12758de313d2f22a6c6feec89dca4bd0cd69a5cb588b0a9f6d61a67d9ffd062627aba0653f5a5025385423a51bc5570afd0d88d196b2a8855ce606d2d5227cb1182a90b224ee39f52f5aa9d6b685210ec6db683caeaeddee41c30c26304464855b7562898482a361f4567d53c703559850d9436480c9d2923f1c4264721893798fe950b8dea6466eb51a045943faa88cf31c1e4dcac6a741ebad731a604ea3e04c558dcdbb82d361a1de843b59587c593f0c12a5b7c4acc325c41a8cc9271ba5d6763de51c34412aa3fc951bc4072c22feea35528d65a55eb554641d7ae6ce6086668e1d2758a8a7d50ddea987ad5bc2619e4be2cc8f49e10a13436225e08b7da09861207e2b7cfbd8c56d5b5dc7002fd6b3dae095189c591225153e237c703da222dac22b6897936d567222d66d2641b23037d0299b8a0e33e3c5839dc16a54e81499f2a13c305534283641e820e8363a17e62a86d49d7bb8eb85f5cfad9ea62dfc99374e0d75d5a1695bfd74b362ff561d41433a234b274c2dabdd5254561365b64968f105618aa8444daa44dae694766df7213fc4255fe4c3841ca975d10bc89b198e31531f7a14873cabfa048d00a53d8c3dca1cb1934d206ced70652fe0b592898ffa20244e23413f164ad90f7d43bf55ce346930efc89b1a4c02ccde523b408526c0970b4b6d8806510cb0d435ba7aada855c56ce66457ab562a124d591d9be210c4566bd54ce5091e39275cd2d49053b900518535a1d1c43b98a01ab99d8d41068a461831fc740a5c6a6a3bc25a16a7bfaadd80b5dd288058f341244b520b2ade65b6fd98dd197c14bd410e7b93eef102a45fc6d066610ff6af25414a7c96d9e625fbd28924bb9dd090f1f51f4b2de892ec0e536fa8c4eb80015136454c656566800d2871e4d5ce6a021db100c7296f2e0f066b336a880d24d6d5b7346cee9356f1f2426cc9d40100572a13eaa0f4d15ad5a4e24ecb94fbb2a85f0b06e9b2749758adcf88662836bfae9126f7ac9e941081288f944a84957ce3e5a9041f5ffee3990ca002596aa382ce515b27a171dc8c9cfea4ef282a25089aa99a84bd1d8e062631b7b6a00bb551f749466814f9a401b6b2a2b94986a618b98e1e076091144e628bd6619083bf8d33c36c2488be8194bcee7b95cd6480e097d6f6af604f864ff3275e02976995b7191b80b23f22cf60d11651775184f1c6088420edc352b5619f0badcc90f355575d2cbe5082e9775b01fe880c325ff688dc90e63c61acabaa1927fd89eecb7b99ce84b3ef0839887ad0bff75e3765e5ee2e09857106190e191e5437facc5a90798b442729f824cfadef839fe21daa64ba8a86ce72ce0e03e369c6b0e85aea721b9c534c900ef6db02773853eea69db49b80477efbc0e0ab92a37076a5314c181fb564affd4bfd011bc0e75a2357cc306796e0547951d0f771ec642dcc36b1e40ebfd51b06bb88a1bd7aa98d07ea217daa0ad9220d15bbaf460e30a7003a2f068e4783845230a3759ae509bbebe620a0be8807e28ceda71ed044354258f5461d42c76f510382da4f0140821527a23b220ad423126d3f6a1c18d725e55f
+OutRec = 00000030000000030000100008000000001000040003c0002000000002c00010000c000180003000080002000030000400014000200008000040000000040002400000000c0002c00030000000038000100000000140000000000000800000000c000180000000080000000010000800000000200008000380000000000003800000000400034000200004000040000000040001800020000400014000300004000180002000000002c0000000080000000020000c0001c0002000000002800020000c0002000030000c0002800030000c0001c000300000000200002000040001c000100000000040000000040002c000000004000140002000080003c0002000040002800030000c0002800020000000028000300004000180002000000000c00000000c00004000200000000340001000000001800000000c00000000100000000080001000080000c000200000000340000000000002000000000c0003000020000c000040001000040002800000000c0003400010000c0002c000100004000300002000040000000010000c0003800000000c000340003000040002000010000000030000200004000140000000000002c0000000080001c0000000000001800010000800018000200008000000000000040000c00010000c000040001000080003800020000c0003000010000000028000200008000100000000040001800030000c000000000000080000c0001000040003800010000c000300000000000002800000000c000040001000080000c000200000000300002000000002400010000c0003c000100008000280002000080001800000000400000000300004000200003000000000000020000000000000100004000100001000000002c00010000400000000300000000040000000000000c00000000400014000200004000300003000000003000030000c0001c0001000000000000030000c00010000300000000300002000080003c0001000000002c00010000400014000100000000040003000000003c000100008000200000000080003400010000c00038000100000000140001000000001800010000c00010000200008000180003000080000c000200000000280000000000003c00020000800038000300008000140000000040000400020000c0002800010000c0003c00000000c000340000000000000c0002000080000c0002000000003000020000c0000400020000000034000300004000000000000080002000000000000030000300004000100000000080003000010000c0001c000200004000340001000000001800030000c0000800000000c00010000200004000300001000040002400000000c00038000200004000280002000080003800000000c00034000000008000240003000080001000010000c0002000010000c00028000300000000100000000040001800000000400024000100000000000001000080003c0003000000001800020000c0002c000000004000280003000080001000020000c000080002000080002c00010000000000000300004000100002000040000000010000c0001800000000c0003000010000c0003c0001000080000400020000c0003800010000c0000800000000800030000200004000200002000000000c0002000080003c000300004000100001000080000400020000c00020000100000000200000000000002400000000c0002c0002000040002800010000c00030000200008000280002000040003800020000800018000100004000180002000080002000020000800028000200004000380002000000000c00000000800010000000004000180003000080003400010000c00038000100000000340002000040001c00010000c0002400000000c0001c00020000400010000200000000340003000040001400030000c000180001000000003c00020000800000000200004000180001000000000c0002000080003c000300000000040000000000003c000200004000140001000040001400000000c0000400030000c0000400020000400010000000008000100001000000000400030000800024000200000000180002000080001400000000c00038000300008000380002000000001400030000c0000000030000c000240002000000001c0000000080002800010000400018000200008000380000000000000c0000000080000c0002000080001c000300004000340003000080002c0002000040000400010000400014000300000000180000000080001400010000c0003c00020000000010000200004000000001000080003400030000000024000300000000280001000080000400020000c00024000200008000200003000040001000010000c000340000000000003000030000000034000300008000040002000040001000020000c0001800020000c0003c000200004000180002000000003000000000c0003c0002000000002800010000000
+Key = 4eba286d54cc289caf78c9964256be52db2f2cdc020ce12fb2c472f2e7913d0d
+
+InNoiseS = c1e9a276ceae5b944e79f8c57ab825a58ba9d01a23cedd5b2b2172a3f8ac35e80b5a3f84c034e226219e78e800453f3ab95329bfe0f4c17246ab6193db9dbe324b5f07f0998d6d83d24208d1b51298b5166c66258d26d86278843e3ddd13da7ebe0ed24902765149465113fee9461a84af1a68c8bf76769603e82a21a693fb0442bb70f599d8982076b9fc36a42c46b75db8b1699544e557fe21330ee6b53bd2310e6dee459b7a6fb55cd640ab1881334542aa920a8ac4e77c87c60ab1c98ae888f42134db67a7b809c69fc81194c487f24b61a011b086d058cb4556b582c54e4f047f50531416539ea7c1f04e7db95bacd3afb616812285354344167ee4745512601dfdae2a9afaf531b40e16d86569420b2805722ad890ed17308035c8943a0daad4e8c8325e8cd7d0263803879ebf420df2b761a86939b4e19ab161ae22bc045acd0af1985dca8230a752150191b20890d0788b9e8e299d08fbd7664e9645c43940c1b06d1c8251cf859d158fb5b515e40c0aaccd90b370020383b71298cdb335803d4b58fd3c8217435218b6b970d180a284d17b7f61ebeb9a46b8bc476bf321010f06128c02e171763dcd10b655aa2542213b6467800f134284da21622f6c20c522d1d05adf9bed5b7a6d63a3ab7236074e1f9b999138ac258900eeaf68a8328ed5084a23cf7cbd851ba7c222d1975363a0770cc446e7c4ef51e49457eaab2ef1fce02a1629c68b12d1aaa3a9bf041a765030d0e2a719ca712fec479ae3f5a4c2caba024ddc2c4c2c354bfb5c55b62daccb7a068adb03253437f87438643ee9d86929d5681b52b87664ace83a2672daae7c1f6c6aa2c486f9e3bb31c4f27b32d047a6af990e08d36e3a8fadb376cecf67989c4977d33d56db106107de6e89849646132a23858514a8931ebd4383d2635f90b2f17b7d92eae259e6ab4da034992a1b6ff215254e78a930fa6cf12283b7d23c73e08788a645b55268ca37e6c49227bb5f2f536caeab9344b7904519509990616250f127201bf5631ec28f5b9b7897870282b69bb46a8854bb5a66f626f9b5a394e062e4208c194cd1b963747216d8975f28a2480dc04a0f31462287d463ab14969827aa2f4fc4c30e977153e9e992688c8ad0b5c3efd17a4b95ec910881311649e223dd8d9348e11f0183560b345a4064c1205d4d41fa5b2b5c60e00dfdb2f31199d8897ea960fd78e6000b7bbb94720d275d9bbc819ca124dcf706a27615209cea60b952fb90455a2bbe3d311b9da08798491684a6291e915aa80b1983d6190610a094173575a7772587408338571e8e248a0b255c18a2cf4684040d215f88da53e9a6114903c3683d3eed814de857742e76a95282d87877289abbe54efdbc9d1961b1176cb5066d3f0bf7556be86106d1d6e9a8bfa8d5fbecf460095821989abd55b60261c8287a137feaedb0515e45694721081851957e88d105db0d974d5d5cd5a9386a8a037f315abe3b809b7f1b6656ac2d269452a39868e66b8e49543584f0667614a9f0aef09a7d956370a6a58353b70196498924bfa073ad687b1ee1a768ecabb7ab15f22fbc71579f7463429d69670d2ec605119f319574e572ee229f6241fab912addb1b83d71bd143149408abb1c15bde84ef93e6d2693c9423d99128832629e6d75b682e0e0181a0dcf442b4c27c32846431a3a6d8690f1c188a9a4274bf284bf12bf0a0dc9672d358b1b6243a631fdefa6464f9463c89f7e423ce03fcd5dd22fd606372296b024baa86c8c922071842a5084a799392ad39880a8b50d9386c7d60f3920db18c1feceda8d72e36e3db48858c00b0e921e35a09e1b16bc54428e0f119b7cd07466af576ec1908f489206e8fcb16580a8271d612ef272f8a5e18c947e10ff2263b08e46527b42d1c993774ed4139ccc0b39566adbacdd1aacb0eb2aceb6dacaa2cb1818b53e8e4b2995ddbc4f399f86d80e6644a2550d129f0a21e84f8950aed8cdd59fd1d09470ea43a19ca7f6a8de69422f0b3078a87a3129a8d819478a470d0624593620182087f57c62450c5f1121486c377648c3e5118e59659c56fd408dee705beae9b412467884904c1488cea3fc51696471ef154f9547ee6ee4636ae578f0611b4311c83e744f186ce2013e8eb00633a3a9223e39ea9107a13639a4dc0457116d20899da92e623b64240d090460a43d88476564c630f99a049f5ce5e34d645c8890e71099f16ebc72121aa044685fdf187e166155736bc1429c85cab2c808c0a1eda3bfbcc737395b4845031807b872407381212efa6856b69b145db0c4fa936ad6f05a824c10f500ad9e91cca8b7c0d57e38c3b82a8bc6d8132b6ae16381604ebfbfd8e8416177ca560e2983963fb1b25ae28d85071d251493e4c27a34319f04eb387a592e62c95b7e8b426dffe2b6d2ca89a71e091bb15c542ad9cb4211cd789b95c13972b9aea65e12051af44020f52971e61324245e9154d528879e559644ec8f7470e06a6d897cb84a13a656ecd55a69dad7234c79da3450a4d
+InPK = d2d75576a45915b2cfd75b4bf06b375114e4f74011e94172661f6644abce4f161ea0558ea13e358eb55f624a6191b25c6ae818f358443078ae43df8a800024254fd9191219b3ee6e2cea5fac0e0a0a5b8aff580b69972b592c311b65ea283267803a7407a663685e87419482505288759406c311ff79b69fd50923ba10120fd14849689471f3d74e74fbb17dd8a7c6e3315147b4d2b6e10b1d8e5fe5c0f9af15b7c80d2d165779a2ec26518bc9d8400def4707f2d8598e56f20501729f3fedd5fb136dba0e5539670a89906e9fab0327cd647d5a9c80e9dd5501469123deb9654d477b297cc4b4efa0f39aada4a37b54b94715a53f3b4bb2f2af109627504db876f505d020fa2103ee81862992a3be24b14749f52017460e83adf847a049108eca92294d117b1e6a146829a5b5699b73312d228a5808e1b11ff174484cf9920f20a016cb8aa461ad41ee13ada4f26d223d8e0678205a079e0de22b51a1265b86c015ab1132c19de6fb09650cb1a33f14eed944291b4629133a3c156e7bf85dfc0887a753a72a5930e8890bfb59fc1d5fe926fb30be72d520c8b6a5908cb5da4df7a34135b3862cb85c1162202dcea8a0a843ea441004d0d4a7ee90372174ba8a680b0137ec4887f44898e3c0a22e3696c33a7a76980b8f5c45ea126d769c6a337574384927e5c17090bf8a506edb6b60be7a9a7b5a32851aab83b2c4d8a66a44636261a6f0b5e72830c2edcc38069039701d58aa0f4730385f449cb3069e52b38d55f2d7ac981bfa15af4bad04200964b8e8aee47a7420f8e428ba9a5005ba89b323a8501fa3a5b0332895a865c408b24c7e8d8ae0f710880dbad5d0920bf676a1340c7e77b1fd2e890f3aa492ae2c2662bdb451f09e17623353d37eb0cd20a7c96abe0ffb2ffc42f88171374580e27b64a550ca636aed8e12758de313d2f22a6c6feec89dca4bd0cd69a5cb588b0a9f6d61a67d9ffd062627aba0653f5a5025385423a51bc5570afd0d88d196b2a8855ce606d2d5227cb1182a90b224ee39f52f5aa9d6b685210ec6db683caeaeddee41c30c26304464855b7562898482a361f4567d53c703559850d9436480c9d2923f1c4264721893798fe950b8dea6466eb51a045943faa88cf31c1e4dcac6a741ebad731a604ea3e04c558dcdbb82d361a1de843b59587c593f0c12a5b7c4acc325c41a8cc9271ba5d6763de51c34412aa3fc951bc4072c22feea35528d65a55eb554641d7ae6ce6086668e1d2758a8a7d50ddea987ad5bc2619e4be2cc8f49e10a13436225e08b7da09861207e2b7cfbd8c56d5b5dc7002fd6b3dae095189c591225153e237c703da222dac22b6897936d567222d66d2641b23037d0299b8a0e33e3c5839dc16a54e81499f2a13c305534283641e820e8363a17e62a86d49d7bb8eb85f5cfad9ea62dfc99374e0d75d5a1695bfd74b362ff561d41433a234b274c2dabdd5254561365b64968f105618aa8444daa44dae694766df7213fc4255fe4c3841ca975d10bc89b198e31531f7a14873cabfa048d00a53d8c3dca1cb1934d206ced70652fe0b592898ffa20244e23413f164ad90f7d43bf55ce346930efc89b1a4c02ccde523b408526c0970b4b6d8806510cb0d435ba7aada855c56ce66457ab562a124d591d9be210c4566bd54ce5091e39275cd2d49053b900518535a1d1c43b98a01ab99d8d41068a461831fc740a5c6a6a3bc25a16a7bfaadd80b5dd288058f341244b520b2ade65b6fd98dd197c14bd410e7b93eef102a45fc6d066610ff6af25414a7c96d9e625fbd28924bb9dd090f1f51f4b2de892ec0e536fa8c4eb80015136454c656566800d2871e4d5ce6a021db100c7296f2e0f066b336a880d24d6d5b7346cee9356f1f2426cc9d40100572a13eaa0f4d15ad5a4e24ecb94fbb2a85f0b06e9b2749758adcf88662836bfae9126f7ac9e941081288f944a84957ce3e5a9041f5ffee3990ca002596aa382ce515b27a171dc8c9cfea4ef282a25089aa99a84bd1d8e062631b7b6a00bb551f749466814f9a401b6b2a2b94986a618b98e1e076091144e628bd6619083bf8d33c36c2488be8194bcee7b95cd6480e097d6f6af604f864ff3275e02976995b7191b80b23f22cf60d11651775184f1c6088420edc352b5619f0badcc90f355575d2cbe5082e9775b01fe880c325ff688dc90e63c61acabaa1927fd89eecb7b99ce84b3ef0839887ad0bff75e3765e5ee2e09857106190e191e5437facc5a90798b442729f824cfadef839fe21daa64ba8a86ce72ce0e03e369c6b0e85aea721b9c534c900ef6db02773853eea69db49b80477efbc0e0ab92a37076a5314c181fb564affd4bfd011bc0e75a2357cc306796e0547951d0f771ec642dcc36b1e40ebfd51b06bb88a1bd7aa98d07ea217daa0ad9220d15bbaf460e30a7003a2f068e4783845230a3759ae509bbebe620a0be8807e28ceda71ed044354258f5461d42c76f510382da4f0140821527a23b220ad423126d3f6a1c18d725e55f
+InRec = 00000030000000030000100008000000001000040003c0002000000002c00010000c000180003000080002000030000400014000200008000040000000040002400000000c0002c00030000000038000100000000140000000000000800000000c000180000000080000000010000800000000200008000380000000000003800000000400034000200004000040000000040001800020000400014000300004000180002000000002c0000000080000000020000c0001c0002000000002800020000c0002000030000c0002800030000c0001c000300000000200002000040001c000100000000040000000040002c000000004000140002000080003c0002000040002800030000c0002800020000000028000300004000180002000000000c00000000c00004000200000000340001000000001800000000c00000000100000000080001000080000c000200000000340000000000002000000000c0003000020000c000040001000040002800000000c0003400010000c0002c000100004000300002000040000000010000c0003800000000c000340003000040002000010000000030000200004000140000000000002c0000000080001c0000000000001800010000800018000200008000000000000040000c00010000c000040001000080003800020000c0003000010000000028000200008000100000000040001800030000c000000000000080000c0001000040003800010000c000300000000000002800000000c000040001000080000c000200000000300002000000002400010000c0003c000100008000280002000080001800000000400000000300004000200003000000000000020000000000000100004000100001000000002c00010000400000000300000000040000000000000c00000000400014000200004000300003000000003000030000c0001c0001000000000000030000c00010000300000000300002000080003c0001000000002c00010000400014000100000000040003000000003c000100008000200000000080003400010000c00038000100000000140001000000001800010000c00010000200008000180003000080000c000200000000280000000000003c00020000800038000300008000140000000040000400020000c0002800010000c0003c00000000c000340000000000000c0002000080000c0002000000003000020000c0000400020000000034000300004000000000000080002000000000000030000300004000100000000080003000010000c0001c000200004000340001000000001800030000c0000800000000c00010000200004000300001000040002400000000c00038000200004000280002000080003800000000c00034000000008000240003000080001000010000c0002000010000c00028000300000000100000000040001800000000400024000100000000000001000080003c0003000000001800020000c0002c000000004000280003000080001000020000c000080002000080002c00010000000000000300004000100002000040000000010000c0001800000000c0003000010000c0003c0001000080000400020000c0003800010000c0000800000000800030000200004000200002000000000c0002000080003c000300004000100001000080000400020000c00020000100000000200000000000002400000000c0002c0002000040002800010000c00030000200008000280002000040003800020000800018000100004000180002000080002000020000800028000200004000380002000000000c00000000800010000000004000180003000080003400010000c00038000100000000340002000040001c00010000c0002400000000c0001c00020000400010000200000000340003000040001400030000c000180001000000003c00020000800000000200004000180001000000000c0002000080003c000300000000040000000000003c000200004000140001000040001400000000c0000400030000c0000400020000400010000000008000100001000000000400030000800024000200000000180002000080001400000000c00038000300008000380002000000001400030000c0000000030000c000240002000000001c0000000080002800010000400018000200008000380000000000000c0000000080000c0002000080001c000300004000340003000080002c0002000040000400010000400014000300000000180000000080001400010000c0003c00020000000010000200004000000001000080003400030000000024000300000000280001000080000400020000c00024000200008000200003000040001000010000c000340000000000003000030000000034000300008000040002000040001000020000c0001800020000c0003c000200004000180002000000003000000000c0003c0002000000002800010000000
+Key = 4eba286d54cc289caf78c9964256be52db2f2cdc020ce12fb2c472f2e7913d0d
+
+InRandA = 115dd662e4a18f069d8ef08e92843a45f73aecf6409390a45b46d41b5f92c6a85fe601c90487263afa39a28fa153054098a02fe501abb9abff56ac36378cb6cec3f2a962f6a8072601481922bde99367e2f0b4330ed70bd8c24295c31c9965b5917ed0ed48250f42468f22bb92ed3961b6e248848e2a2565def2a0657c8b49d027a5457d1f824fd23bfaa9a813eac634dc31025fe16bc067e640da864cf22621b422ee506a37343e41a23a56b2025d325d6129ecbd47f984fe0950c45c5d2a1bda0048b8fb91984b66d4930d667ad8f67d0ad2484ecabb3e4a6a4426d225846449457e21cb429bffe97c9510822a8bad238bde2a453e193b9a6b5d1dc8ab36d9ee36633298b6754e710b52afcf043ce9b9ccc2e902ffd6617442e902e4e529afccfa91b70984921c4809e39d9eee9d5be346988ee2da5cf9863864504fcda0ac8e9dea662555476647a8232564fd46ae420463137d947915d8d3c1207a6b5a0fdb9531a559169730a9fd7e6b70ce388673cd80586d10a4a7a08d1504cb4ad8ed3c3a14b667aaf477b4155c8afe75775299cd7388f57dcc590c0ae8cdbc0e95bdc9c9f5bf0e82dbc2726cb9a60be67395febcf3ec47802ad5b0eee7a1734d016fc41bba9056568cb5ae15c71a82acf6a6f9d53e643196ed6d680a4c8e5dea93cb80e03f6203c4f1e9ad1dd2e93968eb2959095d8c91c36c8e7e98a3ea23441f1a4b9a5a3ba24592a69d386bc8a516cb4cd0498905506ed6d26c68b7ba6291a584468b708f8731d13e8634dc2ea7663825aa6e7d27370866950ae18737049cd84f0763499223b2473ed72a5207b60aadeacc68a9d3934a55c8be32b2d44f253e0daf2c6cbf6a777e4784c34de26eb2ab1656210235813817a8793108317c05a569f1b74e2f47cccf691858b28c535d873f507e65a9b9e1a6da65532af12028ddabed18dc4bb8882f8c848c9bb23c7f99d893b9375e6b14dc71f834747cca9e081198c90e589d738895fd06eb1a9674b9b939b5e7b42a2c0d1167e13c13c8e27cec18c13506de7205917d59da589c04c1f45ab5c0b3a80120f86c7021dba9bf4a05c65ad1d27e153e2e44706caac82d99a8cf40e6c59cfeb7ec07e0db3ba0163e2ed5b05c60764562d60500a69a59831178a616b1f35ebd15876062f9437f8a8e78247d0cdc41f658672f4ea16a087c0a415402792838598eae4895ab79b1c4c69d5b144c4e82eabb748eec724454c3f6f0c935349a7d51d8e5a86a50ff5146e6a4c22ce0456f6d0ad50d0778d500326ad33bf7933d62cfd334316bf182ce109b51615679c02e0165d5f8ae54976cd837661324e4765792e4681e2ef7d134859424958ca5d6e1220fc00620df4295680b84574e985e1ba7e08b752805374332867659a273d91ed99dc5774ec798c06f8298ccab90d53bc950bbea2e25492e8c67deb3874bc4368b079d2a73499fc3c51c16c6b8b704967a71b795034d1e2da91cdcb246149c270095999e6be233d86538e0e572e3ef7190d58256a188f88628c81600337a563d4179c1d9a18744cea2279551af93aa278bb88a5ffe45e3e99a492ac86bd5c8957a7c018dcfb9ff56489084af406151658fde5f0b9ca6145098c9c1edfd08f7e0e3d4c162a58628a7d23009a4e4560723a694332fca49b902396b98d014bbabd262f21b780b4a056a878b55a8921293bedf45602eed1b4b4d80717492a9bcd9b8e99ef152bfe21c205b719a1d4d54a7df9579cfaa999404a13178efb236029d52e0a261a1973c5efd966b2219847b14065856272dac65c2d2614406740aa5f9145c859a7be9d6a48b8689b2ced1959b5c8d4b18f735268e70c65b4664481801916400d2b5d0739544bbd178d12cd2d718ea06f9649feee0850fb1584d1e18568e26833bc93d53261a488d261c295d2963b706d992e01eb2d78c5e548b2d483e410ccbf74ab5aad7d0e2637e0d3660fe3115cd5cea046f4778b426d5e079f9c7f09ac448a6d5bed819ec5b8bc525e504b8079650b10ca4036557b4f91c870fa56c200f220216125739e52ebac76f85abc64e1aeb5f3dbb250e50f69756a708cdac4aef845ae31c9a03091ff6d3123a65878e08dc1cb768a6f404ef9d52da0c2ce1f52431cde64e3432982b744710550c023d699b376054445df81699d411648e74cc7506b1506df3aceb7ba80aac6b21379062346c77d5cf68dbbc12e316f823ce2c33cc24c6e22afd7ed62134d744155cc9d007e010026c1e91121292a27efcc5d0213f1996458994b02e886966e97ff8a84d106c09f84aab516cb1d0f7ca443126c30dc0062598a3a21d32cb2fea35fe51a7a83892be55ca24971ac4863b0f4d557cd9a3420ea71b1f1a61de8912d2d6d59f23c425f9ac6077e86e50c333da23c7da73a5e47a804016819bf1c2a75f6c33522a505a1a9a5e313c901214cf33533ec8a6d2218900f2856b858b9bb49255236e090a90c49c84f32bc5f123d6072517e0ea091e6a04117c60639d2ada6f5d0bcd8d5729efa7394bfc85
+InNoiseS = b25e0026c0f1ac209932a42dac2b2a94f3d3a08078080b8ad39ddd85fe04106bad6c591655d7e6dc9936362a1442a112bfddef1594169d3b929b77663dae11971e713bb5d06882cc5933a4b55be9154f6b2da674e96cbc3ac56145875888931f64669d57c5637dbd469bd3b6504124227e5e86789b7403c7dcda60e2012bc20b28d116209cd9d26be498249ad7a933e63e587d4f8c8c728ef5a0e64fa532c8c56db5d629a803c451d0cabfa7fe185c559da2f73136b79418dd245cdd990fa948a7297591195b1fa8d6b953b3a4dc91692c84bada53c4ec8539394de26358102b509549a1dbaaa0ecd9a614b4e96f17d26ce3507c510d1798d11f218ce41a7900249e0ce70ca624560d0a74a23591f8fa553c1cda6b995c951ad4d965a8fea143523358b3147412422e629de92d64820fdb897a9ee22b5be0190e6ca889bf8b27914c61568bda84651b17a787d700aa1c8d0eed5b669d69b644b1283f61266f6d369a50f446e59c7bb911d1515023e484e7d949a9c6498368fd4291433629adfa93c993f5732e7e12a0cc3f79b94dbd84010f5711103f5d622fcbcbac55d511f8ba02ce47e00a4ec84d10af6684829275598c635defc620f59c5a1ce97399d12de74e9f84b8c25ccc87b4e4b7691d6cc595b40b6e7a2d0ea93773d60edb498ba0dc59906a930557d0529b4d975d68e1d0850f601b490f9a107847e909f8c8573c61927374d9a6bfac48f4ddedaeacc39c3037ecb7d251ebb98231bda7035ec9e2349ac3537496f609016d6a79d394ae43e951abe87fad7d7344148943fdb2b76b56c8e6316315a94eda5a3151a65e7608b80968442e33a7cfb1872ce5e2a1f462bd6d65c8d09a8023e944ccd88050a0c1d488843add51135b4ae73d90aef5143bf2016a668ccbfc6bc5d2275302ccb225a269dc08b26a83d96d16ab68e36eb19da009a87195e9200045d07172984ee427b983ec54af056df6caa32e24b2d579862ce60eac0a13a97da0312edf20d38cf94551a8fd61a78232b387a8b217f98ebb29737793d98a364c78a471dc04b0a3eb48cc9e43b6ae6d3875025d58e2aee7a95e69902f4c8bf34e73ce072572883aa930c1665055a07fec86c229dd9d5d4c8c80d227b278fadca1b00da0885b04c6959b96bedb6a5aeb5322a18cc116f29d3c1574cefd7513945479937a20040402011bacf9ddd010da0c7e19e8a65977d4bd96726951c18bd380c62e2fc861e338ab86587a69e49699c1587fc5737613405c50ca11a365b40ac58eb867f37d9aa61157621fb09737970451286e4e1e9d2cb01a1a0c1187bc491e2e1d75e08c02bcfe5cae870bd073ba05bf2b2f4be0d61a4b461970a5d930b5c9bf111b11252e61d3f4a7bd549ec44c0beff42a9c6273b03cad315907f490808144904388d4760e446e6bdadab21593a363f2db448987425f6963012e2803a4c50500ca9a1f22f9d8b64a4c59545bcba76813b7d41fa40d741ffa0d1ef60a040b4441951245c1b4aad9af707c1815959d0bd0bcceb80cce721b83ad1cdb9c1d5b45ae816403d63794cd285f169ec609791aa24f82d58e04436ec63d4a6086803ba584c83446519207c072d24a6ec7a696625e1cbff76c54468e458190e28e6848a4b6a52ab867fb9c0ec845bd26927d1d8b9f24f7afdc72402e65a1e0de44f45eec51585c594eebfee849f63ddc54ce073081837945a121f92e02f104c386df92b927ad02aba9ccbc2857f2557c7aae8eaf8524cae5620d86a2ebe43e40b108ea592b5450f10fcff13bf068771cc7440e7d6ae66c9af4a3340b6fcabee9ef459d8f8dd4b804717b3ec54ae2246abb7a2bd5647712a1694262eb4886befb8a11d4fd297f512e18b819121f4de1af51036a64fb97a111385d7a218ba794b9ddb7066fce7bb3f1b86590b7eb1b753a29d3bc584ecd300fdb33db715c5a15cc1bc3f2fa49a9abc52815c464af878781e85e15fee92788950005deae6822e084a4c9cbdae862c58f76a6fd25262a3a42004881a7160bf546e066f376163ee028b587014a2b2b269a19dea85c4a7690f3d2065dcb200af1e6714199d7498f3858e61d0d11e8bdaa85288c256cb8bab2982e038a084f459ba0697e7e9159ca0de7b2ecab32a8a0e2b3e26097e321868aedb9318c7972bf6e011e03db452ef8a07ce49d129d12b7e55818e9c4ada4dad00e8722764009ec09082a7870402abd180d050dab6cc5e110a290db641ae620ed5ec58a7f97821e07cb54de427454a5d90d28926af2008525d9f053487aea87972764023751e5cc959a793aa986230814082e8d0747d908027b0e0baf36e8768776a79a7056b438b8a7d3a134da4b698c8dfad12e418b2435f4aeda6cf0a6d4d4906e3d4845606947f87963c7238592e81aca8b03405365408383d120fc3178696d6599ca124fc6014ec6f2e93d274a8e28e3c64a395e433043283d81a91839d8984f642fa1c1043932596fade0cb561e08cffb08af0861535276d622b225d38c755b969c1971e24d600a9a5c
+InNoiseE = 410847f4c6bd1eed95a6d38272884feff2d3d58c25185437064cc584875e0901c0fe1d81e802e4efaa0e8654f95005f206854dc318e06a6bcb022923c26e521a6d98d8b15589e4efb1d5c3f57719dcabf362f9bfff4955b81759aad88856b08c3a08d661a50bf4e5a6ed00e4100bc0a483e460b138361c0806fdc791712a840dc500bbba42f60b87b52a963d15e6f4c7053d716d0ea5c27de87d2b00d4d60838760f56c570fd6942340dc0733f708493a99f78e81840da8fc4d94c914e01ce5cc4cc8183d6972ff4029537a18c756bc35a24588e3fe05abc340c6d593b68585293c04afbc18c179d8585c2a5f0aee36c0ae37ea8694fc79c51c5a87faf6126b766303a6963844b8538976752a363847064724018c939e1763c14a0b3667d841651f1b3753966d22c9bf76d2e0de9ab2091f1d439490fb796acdc55a34dbd02417d5914a55fc1271827c6d77862c330bac48c9ae334d20f499555c872716afdc9f6b219a18f7d47e608ebda1617c547903d6513cba84ed05132ab08272985778654bd1220534ab1134b5595b1880864224c316126547a9bde73001dc49e0b86516aa99951af2ab5e5417d2ba51032976d9449b58ab8d13d5e78a219beb77159072a27690842b134321f2a21508821c9810ed5bd4c1715d8bc02108538a01cd9517428a4cd4331f3a216474825ecd7607e3b2f5e6f08bb851e405b6995b11a5dbf2a72c4a0624446dac7c4e0d89eede099c9292567b318c81702268e1d9932b87ebebecb4ff258a428ab724993583f7e5123ccf2799e091d81a2e4723d9d71a8e40dcb29d8846dd910fa433436b005b624f16932d38321e14c6a41494ef3446c85b8f1d4607943868ddb9556ab50f1a6c10fe30055c699501a3c9525e60b7de7ca304a929b71eac5a903dea06f442882ef5594f453cd15c1be16b1cabdb200813c00e9cc0939349ba25643c968091de29e35d20015a3c89fe5c38f9c9e06402524eada65c7d344249a0c7c315b841bf5402c7241371718b22755ce4cc6d7b056031fc902ccd43f089db16b2b0e98fca82085ba4d8d8e1a00a4751c3b39d8956adb4154d42e100ae3916ae107ba130cb64a756666e4d9655f27d1e4f075a1170b24c873c919000222a413ba0d57a8cf2ca2d3313e3410be1369e06bdd4bab58d8843dda874d5420e458f32fb7c4e7d5b281a27aea3cf82a85d416c79b7a59cbd6ee2929c0307d13f0e8911430ce1b2f778481bc451da9a4677cb28858ab34f5983076c720871a9e1d0853af298369b6906cef6630c802ce4d868996e82d28c5583870e98d5695928abd709a2501b9c383b6022109223ba1b8a7d66358c37ef0518d484f7afb31199d1f4b0bb8509ad02fe8f52e3095f5088db3419081dcc4c66bc46558e8618e2ae52ca3bba1e2423824ad496046a3c72c4877c178478bc635061bcaa39fce6eada2cf50463c8023dafb634a5094179a208b18412a145aabf2f018a9fad81d941d529d46a534d8fa827525c363ea52463473e22ea27f3002c362f96a8e8284a9103db4b7328790dd537a6a387810e777b6c52c7cd989a208911a2d8d9e3e36adf4baed646b34fe397e1754981b4afa1d7917d11b6a623832113883c88d00766bcb044888bd76dda1b08cd47e0d6bf8a8e6c5675e9406682daab1a78cb736e22ea477c6b99091e53c4f41d278d37d9b6926488a54c93100698731a14927c4a9743980964fcb29f2641ed6534a0b21879776518711efd92635790ccefea8acdc73eeedecf345a1a92085f0bb3d34919e85cbd8c84a752ad9ccbb192911645c87677e3e1c61c556871ca9b09ae567c488d888088fb11130615dba6448c7b14d9b4b533ee1036451f3084714d8a2974c2448295e4479d76bf8e0bb4a4858a02924c49e7ce5c80111b4163139da0942aae538198d72d328d8bee651b85b11225a572f1c399d2e7309ef52770a085e241abb1969de0047574c46176a687a58de29b41a0ba02531586912397eda0e783dac53ffd9424b1172b0349ab3d16138079de655f95c9644640d4d5b8b82ab2b1ff8644d8485f461deb18579753b1ba189820226d7dad76627769e909bf6e6c10aad8c2e89db4b6d09481bc938223a46ded67842fa3c0d02abf02674bd147c022ce97fb67ccf827de700012c494223da7d6d60d86ef0c224714ac2858013e0690c48e75430c31689ee55240be39843bd6d75954dec140be06053073818374c08465d629ddbd6810966788e76e88cc4057024eceb2465200971d29d13d906d1584de81b5a4d19b78ec654202379a3780ada0937783fcc2fe582c5c92a04ef9223f9be72ee12f73b1d815863987cc07662450f41edc90e923c042d748559265e8bdffcf1e3a0220c2146417038565ee46dd5b9393dbb2c1a36a3a80fa04b91d623e89297e31979b70e4d53ee7472c5e69e18c2e62ad0fe7f51488df6b06e0ce96525d6862c322f40e069bf843ea6d511aabb92441a0d4ac7e2627c28e7ae654f12997babb4399ba84bd923d750791c9a
+OutPK = 7d49b21bf5e4a67ccde547f4783aa0000ca4174eb3e1557c33a9e934e0a29294662961ad6c55a4f301adf396d0ea8a7480291bf130682239040830034b247e2f5db7a8fba80689d9dca8b9403414ef2963cf600c2ca8b219606802fbcc691145cd38dde3330073c112658cb3f49d6d1a0a88f0b21114af5320a2b9273640d9131e78f60189122f26983c1a285ea26b6b23f0bb30e619a9dcda9dc3ebd885866271476a6ef088e26c4d1400c707d6455663944278347942858990c8597b38cad094e9118a3328cdd55a3a36a14e5594e0750c0316ee00b73e476e49dfc23ede180b621f0b4e294e045d6d40de291736192f93dc2996560561641a1ca94847d301a3982c06daa93a27ee1099659c866766599dc66d970ad48dfd92cdf611414910dc62e43f9192da51f3f62b9cb1639731082dfaad3a1851368620720f271aab645ea69aade694f3b1b8d556354aa25553d41fd9d6b1807fda9575fac5361c7c659eb487948046983a0b3a3c0d79edeac375e4179851eb20d029a49f55f3cab6ba07f1d9b8104bb11816a03dd700e2349eeb1ec5bec50b3fc32191fbccafdf90baeb5971b277c23e43d3205db85b5dd52f1d712a18c89bcb5416b9236e045de1b86754f3b24fa84cd82206218622ac2bdb90f9745d57fda12ab4b8466d7c86cbf57b65b103cf002199854925d38eea4a7e8b52def9049a41a6808481f4b514312797c6e22ea12740951fe06ce938dc249085aa31762225f9379250a4cf2b30e64b5a9bc04b3f2b69e505a9ca102765c9ae740daea6149db775e61f1b4a2db7a251b851eb394971d6320848dd1ede24d4c68b7139c40e5303fde09edbe6aa200802ac3d9d1411d0ce6ca3d8c793895a81cbe420719e2c45696a4ce8b9c0791cc9c999be0d22512b6c649dc24fe111ad97545a7f1cc72fe49d0c96d688fb0b8131b420cda989b5dc172922b11972dc1db5115483739888d7e5da77292534900cc2f2ae3dab61142bda269d20ef5414bb0fc9375e486158a5b41affe4862904f407bde90226c0308dc22bf63467fd02fa4696b1a2424061460b41feee968fd396b6cd12a3bfe067d831e541c8e29a9a2d724440acdc545b7ca593a5fc71f1fa069aca45cb28348eb450d1fbb0a55afd436feabc545c749c2f39065684e84013885c8452bc22a4ea411a93692bef741035bb5dd643c61a8822fa04a51751d8a005a91c36904a86172b11a52bfd18ab167741a27e82699763a8832ea73d5d3daa51a02b791ec062860440b029b3008e2e5c2846bf88388070b39e2156a1c28f1bd91846153c9a3449756b90810ac46a8c404af2bad14f71b636929a319ce7028a8556541fb2962995ab3561833a0e80629d8c9679fd5941dcc3972845f05e0f560870a12c29feeb104722f13410d7d9cb0c9a80518e0270883654d0e7446512ac3dc8563421eac4a5a50f33f84ee9afa82e451b9c469e26d862d7f2ee450c2ad7b050b9b76fdd5cc12f148517c8fd275a2da7a6a54eaa990893ad97b8234bb63340e2ada835bd051a6bc3eb9d7a5b1e5b89a2bce85fc541d5b542f054a2e495f4a5a07ea0a87522781c7312df0bf5c130927f1df0890e681bf3a986f63f500b9c4f8884873e12aa2c4c69b8982cd4530ddb0c914b6b1eb5e1bfc44f32d68e737f8e76aac22c51a76c8b1a83dba8ddedaa0b87e7d2dbda6ae667e2d3fc280defa6745a2a92b61941e3e83b2d053557f7fae24c907f9c6542805548f16664842e443c28c15b45fe5e2f7dd44485b120adab1445a55aa5a85025e52764213dab690a70319939ad971d81d5745d5fd4d03427b07d1b9d46859f3a67c6e556f5552a448ba312e61f4d32195fa2d8afd696ad2d5431c6a18ff02fd4281aa87d714350109d963f3e809cc4c9c51a3d6cd140274621af026df3663c1abad25a13092a9d42880dd2ce1e121c418f9b87c8b6bda67469d7b047e693c5ea3de27b272d30d39564082217c3aa294daf5de1428b3a1182e7dad9935e192d64c7f2ebb1357cb662ee6a67981f5ba73c8494c693d3280f47ae3ebf5fc6b9f52b044ec52bbaca15a82b169adfaa89c511df1be347829286846af2d797714bf866cd5aa44a557fa7f8cb40851fe39f3c468f8db78e867c917e0288625e271007a690f206cf443c7e52dc29710bfa4505912dc4930b7923d29bb304e13a26aa80e18403a4266c87e304b3a87a58a0f1864da113110236d371f63f4f9cb2724679bec457ed715f797ed6ab4c76de8da2ce6849858bed5d6c108b18ef2e75b5c22384286c8767c66f028cdd7b0043d6931eb12a0847ad660dfc030ded0e0acafd3d38214897c58cbfefefd8d1c07c18520082f9c63c45ff57aab3132caaaa5b94e289dc2b6f49e6d2d6a44bde58d6462424932d146d9aec4c30c0ac0e7ab0e986952f75e73e1e3d78e7e898c688a1f412a4c61f559fc8467f66bb5a7af8562e9415025dd8c70673d762bac81e4100a9b85d031a46d66df941f51c88468a820660170e032252811ce5625307e9a0
+
+InPK = 7d49b21bf5e4a67ccde547f4783aa0000ca4174eb3e1557c33a9e934e0a29294662961ad6c55a4f301adf396d0ea8a7480291bf130682239040830034b247e2f5db7a8fba80689d9dca8b9403414ef2963cf600c2ca8b219606802fbcc691145cd38dde3330073c112658cb3f49d6d1a0a88f0b21114af5320a2b9273640d9131e78f60189122f26983c1a285ea26b6b23f0bb30e619a9dcda9dc3ebd885866271476a6ef088e26c4d1400c707d6455663944278347942858990c8597b38cad094e9118a3328cdd55a3a36a14e5594e0750c0316ee00b73e476e49dfc23ede180b621f0b4e294e045d6d40de291736192f93dc2996560561641a1ca94847d301a3982c06daa93a27ee1099659c866766599dc66d970ad48dfd92cdf611414910dc62e43f9192da51f3f62b9cb1639731082dfaad3a1851368620720f271aab645ea69aade694f3b1b8d556354aa25553d41fd9d6b1807fda9575fac5361c7c659eb487948046983a0b3a3c0d79edeac375e4179851eb20d029a49f55f3cab6ba07f1d9b8104bb11816a03dd700e2349eeb1ec5bec50b3fc32191fbccafdf90baeb5971b277c23e43d3205db85b5dd52f1d712a18c89bcb5416b9236e045de1b86754f3b24fa84cd82206218622ac2bdb90f9745d57fda12ab4b8466d7c86cbf57b65b103cf002199854925d38eea4a7e8b52def9049a41a6808481f4b514312797c6e22ea12740951fe06ce938dc249085aa31762225f9379250a4cf2b30e64b5a9bc04b3f2b69e505a9ca102765c9ae740daea6149db775e61f1b4a2db7a251b851eb394971d6320848dd1ede24d4c68b7139c40e5303fde09edbe6aa200802ac3d9d1411d0ce6ca3d8c793895a81cbe420719e2c45696a4ce8b9c0791cc9c999be0d22512b6c649dc24fe111ad97545a7f1cc72fe49d0c96d688fb0b8131b420cda989b5dc172922b11972dc1db5115483739888d7e5da77292534900cc2f2ae3dab61142bda269d20ef5414bb0fc9375e486158a5b41affe4862904f407bde90226c0308dc22bf63467fd02fa4696b1a2424061460b41feee968fd396b6cd12a3bfe067d831e541c8e29a9a2d724440acdc545b7ca593a5fc71f1fa069aca45cb28348eb450d1fbb0a55afd436feabc545c749c2f39065684e84013885c8452bc22a4ea411a93692bef741035bb5dd643c61a8822fa04a51751d8a005a91c36904a86172b11a52bfd18ab167741a27e82699763a8832ea73d5d3daa51a02b791ec062860440b029b3008e2e5c2846bf88388070b39e2156a1c28f1bd91846153c9a3449756b90810ac46a8c404af2bad14f71b636929a319ce7028a8556541fb2962995ab3561833a0e80629d8c9679fd5941dcc3972845f05e0f560870a12c29feeb104722f13410d7d9cb0c9a80518e0270883654d0e7446512ac3dc8563421eac4a5a50f33f84ee9afa82e451b9c469e26d862d7f2ee450c2ad7b050b9b76fdd5cc12f148517c8fd275a2da7a6a54eaa990893ad97b8234bb63340e2ada835bd051a6bc3eb9d7a5b1e5b89a2bce85fc541d5b542f054a2e495f4a5a07ea0a87522781c7312df0bf5c130927f1df0890e681bf3a986f63f500b9c4f8884873e12aa2c4c69b8982cd4530ddb0c914b6b1eb5e1bfc44f32d68e737f8e76aac22c51a76c8b1a83dba8ddedaa0b87e7d2dbda6ae667e2d3fc280defa6745a2a92b61941e3e83b2d053557f7fae24c907f9c6542805548f16664842e443c28c15b45fe5e2f7dd44485b120adab1445a55aa5a85025e52764213dab690a70319939ad971d81d5745d5fd4d03427b07d1b9d46859f3a67c6e556f5552a448ba312e61f4d32195fa2d8afd696ad2d5431c6a18ff02fd4281aa87d714350109d963f3e809cc4c9c51a3d6cd140274621af026df3663c1abad25a13092a9d42880dd2ce1e121c418f9b87c8b6bda67469d7b047e693c5ea3de27b272d30d39564082217c3aa294daf5de1428b3a1182e7dad9935e192d64c7f2ebb1357cb662ee6a67981f5ba73c8494c693d3280f47ae3ebf5fc6b9f52b044ec52bbaca15a82b169adfaa89c511df1be347829286846af2d797714bf866cd5aa44a557fa7f8cb40851fe39f3c468f8db78e867c917e0288625e271007a690f206cf443c7e52dc29710bfa4505912dc4930b7923d29bb304e13a26aa80e18403a4266c87e304b3a87a58a0f1864da113110236d371f63f4f9cb2724679bec457ed715f797ed6ab4c76de8da2ce6849858bed5d6c108b18ef2e75b5c22384286c8767c66f028cdd7b0043d6931eb12a0847ad660dfc030ded0e0acafd3d38214897c58cbfefefd8d1c07c18520082f9c63c45ff57aab3132caaaa5b94e289dc2b6f49e6d2d6a44bde58d6462424932d146d9aec4c30c0ac0e7ab0e986952f75e73e1e3d78e7e898c688a1f412a4c61f559fc8467f66bb5a7af8562e9415025dd8c70673d762bac81e4100a9b85d031a46d66df941f51c88468a820660170e032252811ce5625307e9a0
+InA = 115dd662e4a18f069d8ef08e92843a45f73aecf6409390a45b46d41b5f92c6a85fe601c90487263afa39a28fa153054098a02fe501abb9abff56ac36378cb6cec3f2a962f6a8072601481922bde99367e2f0b4330ed70bd8c24295c31c9965b5917ed0ed48250f42468f22bb92ed3961b6e248848e2a2565def2a0657c8b49d027a5457d1f824fd23bfaa9a813eac634dc31025fe16bc067e640da864cf22621b422ee506a37343e41a23a56b2025d325d6129ecbd47f984fe0950c45c5d2a1bda0048b8fb91984b66d4930d667ad8f67d0ad2484ecabb3e4a6a4426d225846449457e21cb429bffe97c9510822a8bad238bde2a453e193b9a6b5d1dc8ab36d9ee36633298b6754e710b52afcf043ce9b9ccc2e902ffd6617442e902e4e529afccfa91b70984921c4809e39d9eee9d5be346988ee2da5cf9863864504fcda0ac8e9dea662555476647a8232564fd46ae420463137d947915d8d3c1207a6b5a0fdb9531a559169730a9fd7e6b70ce388673cd80586d10a4a7a08d1504cb4ad8ed3c3a14b667aaf477b4155c8afe75775299cd7388f57dcc590c0ae8cdbc0e95bdc9c9f5bf0e82dbc2726cb9a60be67395febcf3ec47802ad5b0eee7a1734d016fc41bba9056568cb5ae15c71a82acf6a6f9d53e643196ed6d680a4c8e5dea93cb80e03f6203c4f1e9ad1dd2e93968eb2959095d8c91c36c8e7e98a3ea23441f1a4b9a5a3ba24592a69d386bc8a516cb4cd0498905506ed6d26c68b7ba6291a584468b708f8731d13e8634dc2ea7663825aa6e7d27370866950ae18737049cd84f0763499223b2473ed72a5207b60aadeacc68a9d3934a55c8be32b2d44f253e0daf2c6cbf6a777e4784c34de26eb2ab1656210235813817a8793108317c05a569f1b74e2f47cccf691858b28c535d873f507e65a9b9e1a6da65532af12028ddabed18dc4bb8882f8c848c9bb23c7f99d893b9375e6b14dc71f834747cca9e081198c90e589d738895fd06eb1a9674b9b939b5e7b42a2c0d1167e13c13c8e27cec18c13506de7205917d59da589c04c1f45ab5c0b3a80120f86c7021dba9bf4a05c65ad1d27e153e2e44706caac82d99a8cf40e6c59cfeb7ec07e0db3ba0163e2ed5b05c60764562d60500a69a59831178a616b1f35ebd15876062f9437f8a8e78247d0cdc41f658672f4ea16a087c0a415402792838598eae4895ab79b1c4c69d5b144c4e82eabb748eec724454c3f6f0c935349a7d51d8e5a86a50ff5146e6a4c22ce0456f6d0ad50d0778d500326ad33bf7933d62cfd334316bf182ce109b51615679c02e0165d5f8ae54976cd837661324e4765792e4681e2ef7d134859424958ca5d6e1220fc00620df4295680b84574e985e1ba7e08b752805374332867659a273d91ed99dc5774ec798c06f8298ccab90d53bc950bbea2e25492e8c67deb3874bc4368b079d2a73499fc3c51c16c6b8b704967a71b795034d1e2da91cdcb246149c270095999e6be233d86538e0e572e3ef7190d58256a188f88628c81600337a563d4179c1d9a18744cea2279551af93aa278bb88a5ffe45e3e99a492ac86bd5c8957a7c018dcfb9ff56489084af406151658fde5f0b9ca6145098c9c1edfd08f7e0e3d4c162a58628a7d23009a4e4560723a694332fca49b902396b98d014bbabd262f21b780b4a056a878b55a8921293bedf45602eed1b4b4d80717492a9bcd9b8e99ef152bfe21c205b719a1d4d54a7df9579cfaa999404a13178efb236029d52e0a261a1973c5efd966b2219847b14065856272dac65c2d2614406740aa5f9145c859a7be9d6a48b8689b2ced1959b5c8d4b18f735268e70c65b4664481801916400d2b5d0739544bbd178d12cd2d718ea06f9649feee0850fb1584d1e18568e26833bc93d53261a488d261c295d2963b706d992e01eb2d78c5e548b2d483e410ccbf74ab5aad7d0e2637e0d3660fe3115cd5cea046f4778b426d5e079f9c7f09ac448a6d5bed819ec5b8bc525e504b8079650b10ca4036557b4f91c870fa56c200f220216125739e52ebac76f85abc64e1aeb5f3dbb250e50f69756a708cdac4aef845ae31c9a03091ff6d3123a65878e08dc1cb768a6f404ef9d52da0c2ce1f52431cde64e3432982b744710550c023d699b376054445df81699d411648e74cc7506b1506df3aceb7ba80aac6b21379062346c77d5cf68dbbc12e316f823ce2c33cc24c6e22afd7ed62134d744155cc9d007e010026c1e91121292a27efcc5d0213f1996458994b02e886966e97ff8a84d106c09f84aab516cb1d0f7ca443126c30dc0062598a3a21d32cb2fea35fe51a7a83892be55ca24971ac4863b0f4d557cd9a3420ea71b1f1a61de8912d2d6d59f23c425f9ac6077e86e50c333da23c7da73a5e47a804016819bf1c2a75f6c33522a505a1a9a5e313c901214cf33533ec8a6d2218900f2856b858b9bb49255236e090a90c49c84f32bc5f123d6072517e0ea091e6a04117c60639d2ada6f5d0bcd8d5729efa7394bfc85
+InNoiseSP = 55a7fa5b24024bb5e137b7da38998792e82320c91e6723ad06f209329f90c23707823be1ed092b16c44df82eded72c0819d42c484afa9575a11219e6a366a1eb9e6f659f458fb0432c888f6142be6f2f437ec4426b6d4f4103fe6428460e825d252b314fca0b32fd48d6afad55d842a0201aa9bb5ac664188ad119773d23f9cdce67850849cb42c76a2ac292a6dadcb60c5da1fd155419dedd9ef5d854cbd5910679ed5a51c5319f40dc5392de54b6a8d0ebd9b0c16ac8896d346572388c55c7fb9f3d6212eb51218b3c03644d6140a680270b51da06526c7ef4eb09c1043eb526a732e6509c0c0f6841da48467637ce94f88bf8adf841015aeeba5d979a783345f2652ae261d5fbf8957b0f20ab22f28d1edc65662adc042703deeb5d953855570937fdc226f76b444b05b85fdbaf615bcec839d0252021d7960923915d59a2ac6d1bcd8752c548aab3094fa27058bc5707bdc7a84488194c1c81e598bc2fd736eae2f945c3d07e6b9346203a48ebd7f79d4f8b172b74b79178f89bc766bcf63466571aa7548e66cf58ce2a0ec5a56dce10d006bd91c183e2a9ffe42f0e9496f713c905d0e4fe923cc8a2a85afb303a0d1bc429c68b209d9aa9a6aee3be4a8507e462b307ed443fcbb17a3172b4754a499a7384583a006897dc507589007bb20db84987d9d039b698af3392bf24b74e3ec59113f446cd972f4624465b81a5b6000dd89f88a694e941e7d2443f57137e78bdd66241801f8a90cca01148b3ab32dc057227f098936ea884a4b187889657cb9e81e1332caa24a806eacba46ade6022fbb82119f9d46b175c5a7493d59cf33bd5a4bdd0d1078e1c2348e4bde86b4071f6055f78c5109dd662c9fb9e98ad888e88a51e447b2f4a8ea5cbf8182083d7f2fbb93e248d39560e7a3e530ec72a4f8d4bd30fca930e4d7d4fc90ad4f5702bc9df4702521a2ae7a3dc701cf816bb5d24c0d17a56248a6ada95398d12ad80daee4806788c45017f500903c671b8305da3a5589ea5be3a5b6ce4435bc79215a82e23e2c4de860cc519701a94348eccbfc6473643d4093febd70e6fad8207f1367492e9de62b5e0722f76e914e4b670123c8ca5e61ac8a41e547dd22db952e4a71554fd304f1f45f841c71291c02054ea49b285360131d9914aa98cc3ed091ce0653aecd03653d6a4e393b190f1dc5d794214a294668415c99c5af27881acc54d6786aaa1bd2bb218c13a0d6c89a49689a983dae0a8655b6e64d66069b4b6c19623e34474b6bd0a020bde5a39314b5b91ead5852d9cc6e3bd45a4aa079f4199b293c9aaab8c41c1546c736b8f5b24b7a6a859410ea58f569e4edf3c953398bd490b32c9856c0b1891e17aa06e1c6788d6803496b50fd969b80f2152fb4263a1e3583d33e0aed9421d93c322c5869c341a4c109c092f7e2d5f544d344f688ddce65e3ad5a5bbccac709b963d02de9d8b6339923d0822eef1fff5b3a9957beb3a342c230c37b1e01938819bc2b70cacbebfe2493040969610a556711fac49dbe52cd71af4042a4431f574c43e846b1d7604c598d6632bd2962a3f48dd55da79956c1c4ca1c8ca8e79aaebc10723ed045b1c24249c36ab4cd0b6372ba9389769bc55f1c497ebd6b4ebf4e1b8528fde631ff4080d2eb3669d827c4864f7e96cad88b76cce3b02712bcf61d7194c31032b9a42018128bfa5af3d026146356f89987882e547d56301861f7c41574c984a0f5d637b0bd870205a2e3c1ae94605d5599650f50a9c8885db20c5273db062a1c3149826446d12d0d491ed95052c14433b7e1c52701ec8c2f555b79664e37550001148e241521af5b0d454e05100523ec28d8d57191c9e32c5365b6f7d8e750cd2c7aa461f8d97da4b75d94665a2c9566fc9a99064cbc6f012a04b8001a732f21ec5547160d37068005157f5d6696e16e198b1b1a1a450da9357a2f15baa12904695c4b202d5ecd8ab2990c7db893662ec6499461c043ae168b1dd1178cc78badd882aeba252229989de627954be86d685f567a459b624a9f3054553318b7ef7702656a8e13fe9a4feb50a91a15298908df8e89230f4c95b3f578710159007d49589e1428e1eef972f070b3c96efebfa87e0a942490a85131d5c4764968d0269cc6c6fceb5b897b2a2c7d9c9f8f4081bb1187da9db021dc8d8c87a02d45af155bb947fe6a381a9761641545e30539e92408170c7e5a5a3f3f0637a284d222988038e219aab72a036daabc785a7e57deb1360b789f0762acd555a5ab179970ccdf7483aa8d6681801f8524816ed00485e5e48a6a427f9368a60ca15da55b27d0c2c50bb4a312a1ac16dbc23c8e22fba9dd8d83bdc64d84dd2f7b8960feeede0c32fc59d442dfde25d1220898bddc2455ab1e10373e73c861efad11619d456152020e3653c56b275cf34f4775cbcf94047a4b9387ef3d8155af9303e868ec8926afa50418702c336c404a30d27062c4d31f8891022383e4951430a2bb1e99497ab54e1ba8871bf51b6c5eb208d88a437c5167929
+InNoiseEP = e1ead35290020eee908a1b102075c6c1e10b14684aef1e9591aa260b30d6e6d5fae61c8c2bb209e08ebc6de547c940657372687067629d50291347748fec50c4ee0793d4b8b6e515a20743580d856b42173784adc45101e4251e45b866423920191826cb512a87b5867b036e7962c0b842cb14188ec918194c5a68bfed117656752061202710141456c6acafb810bf0a0808beef8af48495e837509ee324e75191dd20b8e96bae2382daf1098f719090c15a46e55d1c8f2a4126e182881162d8529b60877ae1a2851b00330ec0d1062ead8f33d7188159d2741b6e5a71c7590353e7d293f204296fe050872c184f17eb1e682510633857cba3e1b57d21ca19867a9e18766601c434b1a74567c78767e57db9ddbe074db07f0d0ed00b68a26b2c6e2037b8e008b10db3d0145db460981d00aee53626ee575297901f780e4704b0ae258692c61805cd269a9fb5cb45fd8e864003975c05875ac08ff4dd34a51964ed366ccc4b58d60ebbd571600f5b2b3249508d77d96723fcfa90c30d19e04d51b9ff9332764e592595eb2a9bd8d4219a57ff803a6a04eba2c8e047896c82e24e3151b9b17def1f461d96529d58bdd456926b64165404faf20b461b7e9b3196b92042188144a9121414ef26395416725bd157c25e642b967e684116942fc1d59886ed30fb12f42b927e5e8a8a08d169301a08c794b9f29614062256f9ee300a1001ceb3e52291a98ab0487bc942510115706c9008735823d8a452af404ca1db9e4c72b6580e90351d639bd48e352c4d6e880dee2b45a11e9a0606da45751485d004e09c0e91e9951c3aefc9aed888f2a8db79acb117a3d81cfd812ec3c1f1f07c01e0a979c30b45b42ee7c979ab75b76816c38a19b581739cda62ca5e01344c0471c5c60d6be6dc22ec441add572d83940582842828b946b43857022f03c70425f169c825fdd24a9e11afdb75e6827216f7367a848d195d57761c106536d29f8a553055fba6b0c33d0198b05f52982bfc4e54205c4a56b69b5f4dec2594f18bafc89560ccb056ab2c5cd36f891cd0dfd0a9172dbd272f899934448a9cd32e8b4a483c84250c472f2e923cabd6a7a1cd73f41fe3640be880095afeea601c4b85e1d63ba4d5a6e88af2208c8c91e392f6b41aa1bea021f9845bea432b8d7440c4991a250e072a5ab50d2bd664a0af38967269f6173d1e8679840f064b4eba7f402a20462d44446bb093903482d506579459843b054e579986627803e1854ad5ed3de36e23d5dd14911c558255cfdd59c5e822113a248504e70537471a442dd4e2d11871aed58ee8060dac6073ef4f804cec2e7696be4155e1733c5ae969106455a2d02f02fbf06e4558eb33e3fa397562171862c55b4cad80080b86b0a98e6398dc1573699d5ef3bd369b8ca69178844c9ae7641951489506a1cfdec940fda8245fb2d83a19b105ef5079d8ce424a0cc2f964ca5b1aae8a5a7a7a647fd0d2279f8ebbb446d502346140ad14f7b5fce594f8d043b2968673af0f3e60543c783dc39157600120229b4f7259aa8d27080efae4d64aff5306d4eb02184b4ee30b36fa501f91ede3aca2483b0b62d4e6013e4fd47bc2bad8a02eedaa88b7bd2c4041168bff45092b27f8f8ceba2286cdacf5d6a55ebb2bd0d589a4a63e499719eda537a8ec0350afc27dad5c67d3de7d2f1497bf90f8e917424bc0b36a21647f1f507a38cd2435a7ab1aa14151c96ff40bb23065b322fb83464c79008055d24c6abf10d54c909995018992c3ebecde40c21ab7b8ea55b37fc57e11af58bdf2c5bfc071203d6daf4449de620a7148e2a9454c4537e86640e4dd4a44e4e2c049f9a19e68c8aa2322a6bc5df7606f727df98f9398099546011751ca49643ff3d4a6aaeab00702493a70dd345b72d6f459034e84041418348178bc710bd0e411107e5dcf4390deca0ebb081ab0c886117fa191388db4793f01ae4b8e0c8edc973a50621aa51d4f06e5f0c2a269eff52049300344d32f78e2029b7c1c3297d4984a180870c5b636954413e73bb6aebcbfc027375b4550faa37062969da41be13148bf8c08bd802ee5fd8963a847598522b977fb9c20db45905b840f6981a62403de15c5b7395999b450b967fdc124ea6f0ec840b488e51f68f9f53da25415be43ea864923ee3b40441a674721e435087e4b8ec108a2b7547f02089f718112b363a92f0207ed3d56c2b465e11d0f99a4c3d9d93463fa6beb4198547365d4d1429e5d81438ec8f316947ddba05bfb6c213871c4a2f101c04e9d81c531b89aa822ddb2c84f9c3b465130e2418e6069cb0698ae7954cac5498154402237d7d4908b587509664a549c458d5e564cf134e44235db3b60edec168585c638a78003c6ee44f67366b7476d8ae3dcd24389e51bc0354c8066ddd830971aa538929d7925ae6c83c65807309ca2628e159641dc669b1e652359801aa3257d2109aa35f825c55b274e362e0005b1b5b0799f53d01a46d57ca74d93696b0a23370a56282a3c2c51eaaaf80e5e22
+InNoiseEPP = 00b001600000c0fd2f001000000002c000100000c000c000f0ff02000100000c0008000040ffebff02c0feeffe1b000800ffefff0b00f8bf0100010000fcbf00f0ff0b0000c00380ffebff0a00fc6f0010000c00feaf000000f4bfff6f0000001300fe2f001c0000c0fb6f000000ffbf0140000000080002c0feebfffabf0030002000f4bf00f0fe1b00f4bf0070002000040000b0ff6b001000ff6f000000fbbf03c001500000c0014001300000c00200000c000700fe2f00fcff060000f0ff0b0004000200fffbff0e0003c00030000000feeffefbff060001c0ff3b00040007c0ffdbff0e0000f00110000c000240000000efbffc2f00ecff0e00014000e0ff0e00fd2f00f0ff12000240ff0b00ffbf0300010000fbbf0280fe0b0003c0020000ecff0a0000c000f0ff0a000040ffcbff0600ffafff3b0000000200001c000800fdefff0b000300ff6f003000fcbf0080ff5b0000c0ff6f0030000c00064000d0ff0a00ff6f0020000400feaf0010000000fa2f000c0007000030014000040003c000f0ff02c0ffef002000f8bf04c0002000f4bf030001e0ff0a0000c0ff8b0008000200000c000c0000b0004000fcbf01c0fffbfffebf00c0ff0b0004000030002c000400fe2f000c00fcbffe2f0000000c0001c00030000400fd2f000c0000000080ff3b00f8bf0480001000f4bfff6f00f0fffabf01400000000400ffafff3b0000c004c0ffebff1e0002c000000000c0ff2f0120000c00fb2f0020000400ff2f00d0ffeebffe2ffffbfffabf02c0ff0b000800010000100000000280000000030004c00000000c0005c0008000f4bf01c000000000000030000c00ffbf02c000e0ff020000c0ff0b000400040000d0ff0600064000400000000100fffbff0e00ffaffffbfffabf038000e0ff02c001c0ff0b0014000280ff2b000000fd2f001c000000ffef0000001b0002c0fffbff0200feaf00100008000040ff5b000000ffafff2b00f8bf0180001000f4bf048000e0ff02000030000000f4bf0500002000fcbf08c0ff0b000c0002800000000400fdef00200000c00380ff0b001300ff6f00d0fffebfff2f01e0fffebf007000300004000000000c000b00fbef01500008000140fffbfffebf0100ffcbff06000980ff9bfffabf00f0fffbff02c000400000000300fdef00a0ff02000480ff2b000000fdafff5b0000c00300001c000800010000e0ff060000b0006000080005c0fe2b0000000580ff1b000800ff2f004000fcbf0200000000e8bf01c000d0ff060004400100000400018000600000c00200005000100002c0000000ffbf0030000000fcbfffef000000fcbf00c0ff3b000400fb2f004c000c0005400060001800024000b0ff0200ff2f001c00fcbf000001f0ff0a0002000030000400fd2f00f0ff120000f0ff0b00f4bf0140000000fcbffeefff0b0000c0024000e0ff0a000070012000ecbffeaf0020000400fe2f000c000400ff6f003000000003c000000003000480ff0b00040000c0ff3b0000000070ff4b0000000040ff5b000800fbaf00d0fff2bf00b000200004000180ff1b00f8bf00c00000000300fe6fff2b000400018000200000000280ff1b0000c0fd6fff0b0000c0ff2f010000fcbf003000bcff02c0004000a0ff0a00ffef00f0ff02000180ff4b00f4bfffaf00f0ff120000b000c0fffebf0180fffbff02c0fe2f00300018000500001c000000fdafffdbfffabf00300010000400fdeffffbfffebffdaf0020000400fb2f00000000c00100000c000c000000000c00fcbf0080000000f4bf0400012000f8bf04c000000007000080000000f8bf0030ff2b000000fd2f00f0ff02c000b0fefbff0600064000300000000040005000fcbf04c0ffdbfff6bf024000b0ff02c0fdafff0b000400fd6f00000000c00100000000f7bffe6f00000003000180ffebff120002c0fedbfff6bf0340002000080000000000000800ff2f01100004000030006c000400020000300004000480000000f8bf03c0feebfffebf007000e0fff6bffcafff2b000c00fcefff4b000c000140000000040001c00020000800fe2f00fcff0a0000f0001000fcbffeefff5b00000000b000000018000030003c0000c000300020001000ff2f000c00000000000000000f000280014000000001c0ffebfff2bf02c0ff0b00100002400020000800fe2f002c0000c001c0ffcbff02c00500ff5b00000002800010000800003000300004000180010000ffbf0070000000030004c000f0ff060004c000a0ff06000040ffdbff12000240ff6b00080002c0ff7b000800024000b0fff6bffdaf0000002300090000fcff02c0000001e0ff1600000001500000c0fe2fffebfff2bf0700000000ffbf00c0ffdbff0e00ff6fff3b00fcbf02c0ffebfff6bf0180fffbfff2bf00b0ff0b00fcbf00300010000800fdefff3b0018000080fffbff0600003000100004000480ff3b001000034000f0ff0e000140ff3b00fcbfff6f0090fffebf
+InRand = 20435d4bcb09f5a9b8188f056742ae4a0dbca938870e3bff327efb7662656001
+OutPK = b5a0956984e94dcb5756f9ff394f581586c933aa95db66c5fbf68c15d5687bf954d27ba22042d62f8a6311571a81210da078cc70f7d411bf9c2e2c829c280e6ace7022f0de83c98cdf92a1f816a585080bb7fd5ace54adf4dd60b17fc35d3742beba77a10729f9c175954515474a1d7b1e0b06013cf2092d113461c99921ba2d84658c22713f530723f44642af1f8c87fb807a89d10c050635216259050061aa8f3c2d0e102e8e6d99024ac72120593f90d4982dbe5d130d004491ae8ae95afc12ba5059fe1d288a21f178854b50744a069617c70eca46447a189dfec5e7399dd90aac0a639485540bd060f96c877750aa13a118663f186b4a96e890d9d40cdaef268571012fd93fe26f689211a15eda78feafd1b97cc01590190589433d651cc73400bebe3b65aac4858d501e24a7535481ac5b996ad77a5ea814f16082705236299484b3d7dc8606de6e95445be4594e6030d945906b5660dc35fd753735a44a0874dead0ac44e23649c51f62daa013bfc33029ae994678da2ba46cac2a0bd283f4f48e7e9a619e9cc5214d2ea08e893c2e3cb9c11b287dc7835dc237a58c504139a9a49d11ff96c7d8215d3599abee62c54c407ebddde4f3c6b669ace8abaa61fe23b0ea98bae9e5599563c5263cd4125657c83f0d9a2c243158a7c2c6680a8a88add6bceb8e5e00f850394e69d3d47369dc9e1aa86b000d27f4a78c28c624506e8dcfe43a957497310711c54d3f8f22ce12e840a32d146715fc4c4039116a86ee7eb0af30db5adf7999c955a6a0067cc6c33fb8e3ab5124b18687464fc12177b69e66cae866fa291385b8ad872730294958e035a2a5fd9489acd5509a0005eab82dd177bb81af96c03b78d5e94692fb2357ff1bd2b663933b7d9646bc9eb4545fe970a886c54a9915a6c6083d47f42311d841874394963bf0459ebdb354785ae2babb696318ceceb28cd358ef9d389036cf5abfa814cb6abe1508261c9787dc44a9b4038b2a2585a125fb25bc46a179a8b47f1f841137b873101306a2556831bc110493d1c40c688227202c49ff290a0002ff0e56b859b3e3f46e0b34a2c44b19f17275a93257b7ad01640423c80431408813e3d6e5f94e7f18b1c22506c1c1bf4812a9b860b01b248805a03fd588ec54b1adb78a6c4f1af0c547c1b1f8257f6a28c11ea3972f860ff6a1ebd94202d1daaba1077512bf5f5ffb22c63dfbcf2ccba0d836c7042c330028b537364da743f5fec8b646c1974652e8e165c384da662acf28e51089a94857a024a5e6ea27f45abd0115b67d72460405e8ee1b00116ed26bf9c68092eaa8510c45f4015e920f6890a8b3a1aa64ddb820a2e5a6bee9eb399ca7d42a8e8ad79b9a1214e27f90b1f494c77a620f8158e0b6353999446c9b0401ef9910dce28ac6d6a6413fe8398c6dc7615ac85e4d470d1ed394d0bc1273b07f50bbfee2c136c2cbacf6e9e770fc02c9e96d9f39d601aa854e1b7f18a1b260f201055fc844d800af062b163ae176a5b72728acf030139c11d9e075f6cb0c362b00883fa9083f20649e28b75b7aead19e4b347a1e6111300da4487796df4dfdd16e242ac114d37f71485bbcd50f7047a92074265c450c78e016013ed25256a632b646a0840817083c5676182eabc595766d6f7b123c49acbdabbbe5ddb29fc83422432acc397241aeda878c6b6fab3210037d3b9f4a00d2e6753d5583961226bd16910590a7cc3993ff61156097f5bcffb4fae741f878572735296f904292bb9dd834a80fc0422bc002255f09377ce2dde000f23a4b1114de2aa9053a2495048cd9300b07ae6520ad9f2226ac813cbe77e8587d5436bba996042b41a6926a1e26019a34f88f8b285e2a2dc60061a45fb87d7892b745a4766f05a3eaa973e51fff6b7759aadea8254a94d12d7114ee265e96e108060c1fc82b0fea73ac320c9236d5768a979991d2f43b7d2bbe10f9361b959785958ead416b0433e90e757852865a292816d451a2a6a2dd8c87fd828f28de91f8a70cdf9164da8c74a939d6897db47449fe0b7bed448fbbd4d7a12444ae0e865b3f5af4ab8163db69a422c74f3ca71f8996c9758940e5edef168f9867a1f860c64e38508d0256b047c40181d4cd1f68fbdbbe44340fb944a67f310e15aeb8d6a3b168afa78ed81ca536d63b498a679556fa9fe5981c65c5b0566460009a557a7442da41e4cf5d7e1749ac929c84733ce73ca5e7393fd58bb07df14f861420a3aa3f6a1238d46b39742b490a54c8fa67cba2c26bbb655ecc2b2be47aad966b09b6580916f4a9ac3fe6d4e1bbb6161b81f0850bcaaf23c21a7239184b6f9198f9c16a1bd555165e25791e6951ec22acd97bcd10ded28ed67cac18a2f4164318c21088255bc3ad7612364cbaee41cfab0d8282033a8e0b18256c004eb0e6c5aec15854c456146591065664a928816fbfb213a5e4b4477148a2487aa5368b4dede4b54dad78566d42276558149302089bb23af8271e00090a33d29c090692da678a428442f35d8f0e6dbf40f
+OutRec = 00000000000000038000200000000380002000080003400020000c000140003000000000400020000c0003c000000004000300003000040002000030000c00014000300004000280003000080002c00030000800038000200004000240002000000002c000000000000300003000000001c000000000000300001000000000c0002000080002800030000c000200001000040001c00000000c0002000000000c0003400030000c0001c00030000c00010000100008000340000000000002c0000000080000000020000c0002000010000400004000200004000200002000040002400000000800018000100000000240003000080000000030000c000380001000000001c00000000c000200002000040000400020000c0002c000000004000240002000080001400020000400038000200004000200000000040002c000100000000380000000000000000030000400004000200000000180003000040002c00000000c000380003000040001800010000c0000c0002000040003000020000c000080001000000002c00010000c0003000020000000024000300004000300002000080001800010000c0001000000000c0000c00000000c000340002000080001000030000c0002c000100008000280002000040001800020000c0000400010000800020000100008000280000000080000800000000c00008000200000000340000000080002000030000c00014000000004000340000000000003c000200000000040003000080002800010000c0000c00000000c000280002000000001400030000c000080001000080003400030000c0000c00000000400018000300000000080001000080003400030000c00018000200008000280003000040000c0001000040001c000000008000280000000080002800000000c000080002000000000c0002000040002000030000c000280001000040002800030000c000080000000080003800010000c0000c0000000000003000030000c000280001000000000400010000000000000100000000300000000080000000000000c00038000000000000200001000080000c000200004000380002000080003000020000c0003c00020000400038000000004000300001000000000000030000c0001c0003000040003000010000400024000300000000340003000040003c0002000040001c0002000080003c0000000040002c0000000080002400020000c0000c0000000000001c00010000c000200002000040000800010000800038000300004000240002000040000400020000000038000100004000080003000000002c00010000400000000200000000380001000080003c0000000000003c00020000800014000300004000200001000000000000020000c0000c0001000000003000010000c0001c0001000040001400010000c000240003000000000c00010000000014000300008000240001000040001400010000c0003c0003000000000000000000c0002c000100000000280002000040002400000000c0002c0001000040003400030000c0003400000000c000140002000000000c00020000000004000200008000180000000080000c00020000000000000300004000340000000000002800020000c000100001000040002800020000c0003000020000400000000200004000000000000000001400000000c0003c0003000000003800020000c0003c000200000000380002000040001c0000000040003c00020000c0002c0001000080003c0000000000000c0002000000000c0002000000001c000200008000380003000000003400000000c000140003000040000c00030000800014000200004000240001000080000c00030000c000100003000040001400020000c000180002000040003400000000c0003c0000000080003c00010000c0002000020000000030000000004000300003000000001c00000000800004000200000000200000000040000400000000c00028000300008000140003000040003c00030000c000240003000000003c00010000c0000400030000c0002c000200004000040000000040003800000000c0003c00010000c0002c0003000040001c00020000c0001c0000000080002000020000c00030000300004000380002000000000400030000c000140000000040001c0002000040000400000000c0001000010000c0003000000000400018000200004000240002000000000800020000c000240001000040002400020000400028000100008000080001000080003c00020000c0003800010000c0003800020000800000000200008000340002000000003800020000c0000c000200000000040000000040000800030000c000340002000040000000000000c0003400030000000018000100000000140001000000001000030000c00000000200004000300000000000003000000000800020000200000000000003000080003000030000000
+Key = ad539b834982f525e844fbdf56fd496ca25cac45c6b5718de7f2417b7ff6e3b4
+
+InNoiseS = b25e0026c0f1ac209932a42dac2b2a94f3d3a08078080b8ad39ddd85fe04106bad6c591655d7e6dc9936362a1442a112bfddef1594169d3b929b77663dae11971e713bb5d06882cc5933a4b55be9154f6b2da674e96cbc3ac56145875888931f64669d57c5637dbd469bd3b6504124227e5e86789b7403c7dcda60e2012bc20b28d116209cd9d26be498249ad7a933e63e587d4f8c8c728ef5a0e64fa532c8c56db5d629a803c451d0cabfa7fe185c559da2f73136b79418dd245cdd990fa948a7297591195b1fa8d6b953b3a4dc91692c84bada53c4ec8539394de26358102b509549a1dbaaa0ecd9a614b4e96f17d26ce3507c510d1798d11f218ce41a7900249e0ce70ca624560d0a74a23591f8fa553c1cda6b995c951ad4d965a8fea143523358b3147412422e629de92d64820fdb897a9ee22b5be0190e6ca889bf8b27914c61568bda84651b17a787d700aa1c8d0eed5b669d69b644b1283f61266f6d369a50f446e59c7bb911d1515023e484e7d949a9c6498368fd4291433629adfa93c993f5732e7e12a0cc3f79b94dbd84010f5711103f5d622fcbcbac55d511f8ba02ce47e00a4ec84d10af6684829275598c635defc620f59c5a1ce97399d12de74e9f84b8c25ccc87b4e4b7691d6cc595b40b6e7a2d0ea93773d60edb498ba0dc59906a930557d0529b4d975d68e1d0850f601b490f9a107847e909f8c8573c61927374d9a6bfac48f4ddedaeacc39c3037ecb7d251ebb98231bda7035ec9e2349ac3537496f609016d6a79d394ae43e951abe87fad7d7344148943fdb2b76b56c8e6316315a94eda5a3151a65e7608b80968442e33a7cfb1872ce5e2a1f462bd6d65c8d09a8023e944ccd88050a0c1d488843add51135b4ae73d90aef5143bf2016a668ccbfc6bc5d2275302ccb225a269dc08b26a83d96d16ab68e36eb19da009a87195e9200045d07172984ee427b983ec54af056df6caa32e24b2d579862ce60eac0a13a97da0312edf20d38cf94551a8fd61a78232b387a8b217f98ebb29737793d98a364c78a471dc04b0a3eb48cc9e43b6ae6d3875025d58e2aee7a95e69902f4c8bf34e73ce072572883aa930c1665055a07fec86c229dd9d5d4c8c80d227b278fadca1b00da0885b04c6959b96bedb6a5aeb5322a18cc116f29d3c1574cefd7513945479937a20040402011bacf9ddd010da0c7e19e8a65977d4bd96726951c18bd380c62e2fc861e338ab86587a69e49699c1587fc5737613405c50ca11a365b40ac58eb867f37d9aa61157621fb09737970451286e4e1e9d2cb01a1a0c1187bc491e2e1d75e08c02bcfe5cae870bd073ba05bf2b2f4be0d61a4b461970a5d930b5c9bf111b11252e61d3f4a7bd549ec44c0beff42a9c6273b03cad315907f490808144904388d4760e446e6bdadab21593a363f2db448987425f6963012e2803a4c50500ca9a1f22f9d8b64a4c59545bcba76813b7d41fa40d741ffa0d1ef60a040b4441951245c1b4aad9af707c1815959d0bd0bcceb80cce721b83ad1cdb9c1d5b45ae816403d63794cd285f169ec609791aa24f82d58e04436ec63d4a6086803ba584c83446519207c072d24a6ec7a696625e1cbff76c54468e458190e28e6848a4b6a52ab867fb9c0ec845bd26927d1d8b9f24f7afdc72402e65a1e0de44f45eec51585c594eebfee849f63ddc54ce073081837945a121f92e02f104c386df92b927ad02aba9ccbc2857f2557c7aae8eaf8524cae5620d86a2ebe43e40b108ea592b5450f10fcff13bf068771cc7440e7d6ae66c9af4a3340b6fcabee9ef459d8f8dd4b804717b3ec54ae2246abb7a2bd5647712a1694262eb4886befb8a11d4fd297f512e18b819121f4de1af51036a64fb97a111385d7a218ba794b9ddb7066fce7bb3f1b86590b7eb1b753a29d3bc584ecd300fdb33db715c5a15cc1bc3f2fa49a9abc52815c464af878781e85e15fee92788950005deae6822e084a4c9cbdae862c58f76a6fd25262a3a42004881a7160bf546e066f376163ee028b587014a2b2b269a19dea85c4a7690f3d2065dcb200af1e6714199d7498f3858e61d0d11e8bdaa85288c256cb8bab2982e038a084f459ba0697e7e9159ca0de7b2ecab32a8a0e2b3e26097e321868aedb9318c7972bf6e011e03db452ef8a07ce49d129d12b7e55818e9c4ada4dad00e8722764009ec09082a7870402abd180d050dab6cc5e110a290db641ae620ed5ec58a7f97821e07cb54de427454a5d90d28926af2008525d9f053487aea87972764023751e5cc959a793aa986230814082e8d0747d908027b0e0baf36e8768776a79a7056b438b8a7d3a134da4b698c8dfad12e418b2435f4aeda6cf0a6d4d4906e3d4845606947f87963c7238592e81aca8b03405365408383d120fc3178696d6599ca124fc6014ec6f2e93d274a8e28e3c64a395e433043283d81a91839d8984f642fa1c1043932596fade0cb561e08cffb08af0861535276d622b225d38c755b969c1971e24d600a9a5c
+InPK = b5a0956984e94dcb5756f9ff394f581586c933aa95db66c5fbf68c15d5687bf954d27ba22042d62f8a6311571a81210da078cc70f7d411bf9c2e2c829c280e6ace7022f0de83c98cdf92a1f816a585080bb7fd5ace54adf4dd60b17fc35d3742beba77a10729f9c175954515474a1d7b1e0b06013cf2092d113461c99921ba2d84658c22713f530723f44642af1f8c87fb807a89d10c050635216259050061aa8f3c2d0e102e8e6d99024ac72120593f90d4982dbe5d130d004491ae8ae95afc12ba5059fe1d288a21f178854b50744a069617c70eca46447a189dfec5e7399dd90aac0a639485540bd060f96c877750aa13a118663f186b4a96e890d9d40cdaef268571012fd93fe26f689211a15eda78feafd1b97cc01590190589433d651cc73400bebe3b65aac4858d501e24a7535481ac5b996ad77a5ea814f16082705236299484b3d7dc8606de6e95445be4594e6030d945906b5660dc35fd753735a44a0874dead0ac44e23649c51f62daa013bfc33029ae994678da2ba46cac2a0bd283f4f48e7e9a619e9cc5214d2ea08e893c2e3cb9c11b287dc7835dc237a58c504139a9a49d11ff96c7d8215d3599abee62c54c407ebddde4f3c6b669ace8abaa61fe23b0ea98bae9e5599563c5263cd4125657c83f0d9a2c243158a7c2c6680a8a88add6bceb8e5e00f850394e69d3d47369dc9e1aa86b000d27f4a78c28c624506e8dcfe43a957497310711c54d3f8f22ce12e840a32d146715fc4c4039116a86ee7eb0af30db5adf7999c955a6a0067cc6c33fb8e3ab5124b18687464fc12177b69e66cae866fa291385b8ad872730294958e035a2a5fd9489acd5509a0005eab82dd177bb81af96c03b78d5e94692fb2357ff1bd2b663933b7d9646bc9eb4545fe970a886c54a9915a6c6083d47f42311d841874394963bf0459ebdb354785ae2babb696318ceceb28cd358ef9d389036cf5abfa814cb6abe1508261c9787dc44a9b4038b2a2585a125fb25bc46a179a8b47f1f841137b873101306a2556831bc110493d1c40c688227202c49ff290a0002ff0e56b859b3e3f46e0b34a2c44b19f17275a93257b7ad01640423c80431408813e3d6e5f94e7f18b1c22506c1c1bf4812a9b860b01b248805a03fd588ec54b1adb78a6c4f1af0c547c1b1f8257f6a28c11ea3972f860ff6a1ebd94202d1daaba1077512bf5f5ffb22c63dfbcf2ccba0d836c7042c330028b537364da743f5fec8b646c1974652e8e165c384da662acf28e51089a94857a024a5e6ea27f45abd0115b67d72460405e8ee1b00116ed26bf9c68092eaa8510c45f4015e920f6890a8b3a1aa64ddb820a2e5a6bee9eb399ca7d42a8e8ad79b9a1214e27f90b1f494c77a620f8158e0b6353999446c9b0401ef9910dce28ac6d6a6413fe8398c6dc7615ac85e4d470d1ed394d0bc1273b07f50bbfee2c136c2cbacf6e9e770fc02c9e96d9f39d601aa854e1b7f18a1b260f201055fc844d800af062b163ae176a5b72728acf030139c11d9e075f6cb0c362b00883fa9083f20649e28b75b7aead19e4b347a1e6111300da4487796df4dfdd16e242ac114d37f71485bbcd50f7047a92074265c450c78e016013ed25256a632b646a0840817083c5676182eabc595766d6f7b123c49acbdabbbe5ddb29fc83422432acc397241aeda878c6b6fab3210037d3b9f4a00d2e6753d5583961226bd16910590a7cc3993ff61156097f5bcffb4fae741f878572735296f904292bb9dd834a80fc0422bc002255f09377ce2dde000f23a4b1114de2aa9053a2495048cd9300b07ae6520ad9f2226ac813cbe77e8587d5436bba996042b41a6926a1e26019a34f88f8b285e2a2dc60061a45fb87d7892b745a4766f05a3eaa973e51fff6b7759aadea8254a94d12d7114ee265e96e108060c1fc82b0fea73ac320c9236d5768a979991d2f43b7d2bbe10f9361b959785958ead416b0433e90e757852865a292816d451a2a6a2dd8c87fd828f28de91f8a70cdf9164da8c74a939d6897db47449fe0b7bed448fbbd4d7a12444ae0e865b3f5af4ab8163db69a422c74f3ca71f8996c9758940e5edef168f9867a1f860c64e38508d0256b047c40181d4cd1f68fbdbbe44340fb944a67f310e15aeb8d6a3b168afa78ed81ca536d63b498a679556fa9fe5981c65c5b0566460009a557a7442da41e4cf5d7e1749ac929c84733ce73ca5e7393fd58bb07df14f861420a3aa3f6a1238d46b39742b490a54c8fa67cba2c26bbb655ecc2b2be47aad966b09b6580916f4a9ac3fe6d4e1bbb6161b81f0850bcaaf23c21a7239184b6f9198f9c16a1bd555165e25791e6951ec22acd97bcd10ded28ed67cac18a2f4164318c21088255bc3ad7612364cbaee41cfab0d8282033a8e0b18256c004eb0e6c5aec15854c456146591065664a928816fbfb213a5e4b4477148a2487aa5368b4dede4b54dad78566d42276558149302089bb23af8271e00090a33d29c090692da678a428442f35d8f0e6dbf40f
+InRec = 00000000000000038000200000000380002000080003400020000c000140003000000000400020000c0003c000000004000300003000040002000030000c00014000300004000280003000080002c00030000800038000200004000240002000000002c000000000000300003000000001c000000000000300001000000000c0002000080002800030000c000200001000040001c00000000c0002000000000c0003400030000c0001c00030000c00010000100008000340000000000002c0000000080000000020000c0002000010000400004000200004000200002000040002400000000800018000100000000240003000080000000030000c000380001000000001c00000000c000200002000040000400020000c0002c000000004000240002000080001400020000400038000200004000200000000040002c000100000000380000000000000000030000400004000200000000180003000040002c00000000c000380003000040001800010000c0000c0002000040003000020000c000080001000000002c00010000c0003000020000000024000300004000300002000080001800010000c0001000000000c0000c00000000c000340002000080001000030000c0002c000100008000280002000040001800020000c0000400010000800020000100008000280000000080000800000000c00008000200000000340000000080002000030000c00014000000004000340000000000003c000200000000040003000080002800010000c0000c00000000c000280002000000001400030000c000080001000080003400030000c0000c00000000400018000300000000080001000080003400030000c00018000200008000280003000040000c0001000040001c000000008000280000000080002800000000c000080002000000000c0002000040002000030000c000280001000040002800030000c000080000000080003800010000c0000c0000000000003000030000c000280001000000000400010000000000000100000000300000000080000000000000c00038000000000000200001000080000c000200004000380002000080003000020000c0003c00020000400038000000004000300001000000000000030000c0001c0003000040003000010000400024000300000000340003000040003c0002000040001c0002000080003c0000000040002c0000000080002400020000c0000c0000000000001c00010000c000200002000040000800010000800038000300004000240002000040000400020000000038000100004000080003000000002c00010000400000000200000000380001000080003c0000000000003c00020000800014000300004000200001000000000000020000c0000c0001000000003000010000c0001c0001000040001400010000c000240003000000000c00010000000014000300008000240001000040001400010000c0003c0003000000000000000000c0002c000100000000280002000040002400000000c0002c0001000040003400030000c0003400000000c000140002000000000c00020000000004000200008000180000000080000c00020000000000000300004000340000000000002800020000c000100001000040002800020000c0003000020000400000000200004000000000000000001400000000c0003c0003000000003800020000c0003c000200000000380002000040001c0000000040003c00020000c0002c0001000080003c0000000000000c0002000000000c0002000000001c000200008000380003000000003400000000c000140003000040000c00030000800014000200004000240001000080000c00030000c000100003000040001400020000c000180002000040003400000000c0003c0000000080003c00010000c0002000020000000030000000004000300003000000001c00000000800004000200000000200000000040000400000000c00028000300008000140003000040003c00030000c000240003000000003c00010000c0000400030000c0002c000200004000040000000040003800000000c0003c00010000c0002c0003000040001c00020000c0001c0000000080002000020000c00030000300004000380002000000000400030000c000140000000040001c0002000040000400000000c0001000010000c0003000000000400018000200004000240002000000000800020000c000240001000040002400020000400028000100008000080001000080003c00020000c0003800010000c0003800020000800000000200008000340002000000003800020000c0000c000200000000040000000040000800030000c000340002000040000000000000c0003400030000000018000100000000140001000000001000030000c00000000200004000300000000000003000000000800020000200000000000003000080003000030000000
+Key = ad539b834982f525e844fbdf56fd496ca25cac45c6b5718de7f2417b7ff6e3b4
+
+InRandA = c664383843e8befe514ab2bda15c5aad395931045b4b1c235b7bca75ad04216935f18f64dbf1d22c2e410c50e84468859fa80efbd78b1ab2cfcba7f235b471e5107e3337aa4de117333b3de593075f083a31f22e59964846dd454df9d992372561218a20d1f59a6628c65bf060d7a6956e0bc2e679c6b85b44ee1b07a13faedcde44724d4c98ef58516be8346ea4422008e96d68225fc9e0eebd5d8e149956cd1660c5eaab33387c6c17774073e9516009a007de75172991609901deb2808a3b93a15cae615e19852ab9a8fc415ce6f2ed203fc1f785ef6e77739d44eab1720ada4a7ad43cd96b99ad29b15c80b42f0566315841035e246e6b2358372c5257a4b97c3bf6dce693cf5c3f8acf468ac9ee2903a075eb829d9506e0b21504699f7cd7dbd72cbe0a36cc7e6b47f28a00e5e2a848bd95bbcaa9e14f9a72cc9edd253a61419e24dda294fe0de54df1fb14227b73d7cefad3bcbbcd41e74199797eab8089e7e56990f86eed4a3c8c7f39df1a70aaee6fd429d39854286e52d1bd8a0c2a8403ea58b010f0a175d0a974365a2558446b3522186cc2e0ff1b604caf2b211eb080f507ded619594de87d7f2655a2ea918dc384394a362a5a985c6bb935c14100acca189e84494ba27373ab1e955b228122807d78f1cb4a44b64459c90921308a448a83e14556129464459e9204cb2a90e3295833701d0bb6e700d9b3ed30f9599a31d6e00d871bfdf7e3e5a4e2a4317b233e4cded198074395092d9c9c513fd295e71cf4e0e85e2989eb4a31c752b5791c66842db51e4e8e150b23ad4c5724bff7a4f9061e5ae5c91a69615aa36fe6eb044b374fd2b88d5a532c608c8aacb091d08cea8a67a9028e620d7b41047d7a88d07b39050aaa67703101a492be1cc1f16224a91c9ce75b5e48ac5389aec2c7fd44b3521656a38e849b52d7c1dbd9138f868f78cb405c830a00a60f0e6a814efd8599726fe913b7b4fb36b2a94eacb7d938a1212d5f2aca551a2166f32ae45c2933ed945476014151448f649eca8b1b2b07c181e9153f4d7c78eea1b4ee00c4316fd073a1c9da8bbc2876f256e3d2218a180b2efc04fdfe61d2c417093e483bb0535a6892d52515ddbdeab4544b8b45e945650873f24025a6a65c3fc2202a244c695acd60f555f8b5ba196336daafd899ea09f1a8df918277889118383c12e5a8dda938ba5d0214148a16daaf196b6f12a20d17a6d1b57882b4437d9f0099cc483e731fabd2151e4febef2d55bb881f271a343306345096e8c4658a583cf2682d41ea924504ad0069c1764a5fc2c959a14d93ecadc18635e476b7d639d2bb008fb1e05ab6e454a30143f859f43477e7cc6253df152e2fa42958d67446dc9843c42e294b6196eb17c928811c0f686902d52cc24652e43344a6da135f6b2df84b4a802f703965274f8d5566469d9a146a65978d1d453f581881a52680f3eb9a89677563082bbd312bf53a569dc5c6f1c13279de627120fe804f6305a897fe479b1a5729836db61c9bf9c3cc96b9eb52a4836ce0608be6be33f1d2355bd45be2449d10e4012e3a92e420531056ea532039f8ca2daad8d0051d5b201b262db64e0c60901ae91d22126ce3390692a61b6e13d9a4b6ec44019a08e9241ca5e0d261baa092161eb58fed33f94e91a2bc18b7d1dfddc122de3c8d93bd6619945987c8af349714109a65b3a0f9a946b8843b1677d867aa8c5b38a1324d4a5cffb8d98e94e4d837b16c0a823f04ea17d4f470f7c46cb49d01ba23e66f966f111a525e662a0b69818801b8c4c7398f21954168551580766d4882b0f6586f4ace742d2c07b96dba61dfc8763aac92289e84afb1ae4afa784204e82f2c2461bc073da91c3615ca970f195e37b9e5a11143e1317336b320d349b6402979cc6fa1984a843cbf1435a519ca957fcf45658ddaaa8fc130e1bd3ebe5c8b4164fe6a0b76d6e3f252d170889572babe5085a68fb42bfbf45a9419372a7e926fc604faab4ce138d34a1e6438c649ad282d4077ed990b911656c6192cad9a079764f995179eb3225fc67fa71b008aa1a4821a991133497e28cfe02ca4a87cb087c412a8998d22fb4e807bb51ebfab53a6c9a6602e9cc54f1a8f9c53ef95c5f0879256b1d6fe2aacfd488943a49135d49fc54fd326e5963ccc451583030dadf30086128bee2b74902c58d9c0b4a10bce90a3848b75d4751038dd3ae5827f95a83476e060f38779d151a8deb0517b6a526415447b48f66ce28615a5e3c10f971397375a7c0ac5264266f4b930c34faba354d29f795c9aca392413586218e567d9bdb95209c94322a1d96c9a628f9e97abaaf6332e4e61ed0d904b119086ed021401be72abd6c460d50dd2a7d29ab890528d31070b7d781f2a6912074bd1fde427f60faab61b263c2d52cf6a4092b66e9080617554aeda564da0f5c9586c987541ec2551a7ca0d512bee052be4fef66f750b7c9bda78350ca4812394545041af7d550d7142e579db6d954489301dc4cd9b405f685d69470c325c490b
+InNoiseS = 8159e4d8f3901f0cec2355ebc6511fa4993a1576af5257b606f5b5317703e6b78b4053961048db1d4661b68e7bd70c8a00f758c257fbb81ed7cc2aba5fb098a4a0e8d5b5466ad209a639d99c0408eaef04895cae0cc75a18838a2d4517b927807d1e83ef9dd6f1cc1d42ca623b720581b804bee5b95ea47f8a7440db5073166fc595b314a519c178bb37b14b7b18cbe4d68027c45acb6760ed815f035b7b108c4193e470611f2e413d50e7d0596537cfa86cb93c4400c8240978a9d2325f0d30776de50e351662f2d97c8878468dfa5555618c0e25e237fe268658069153d90ee7552296b0853f2e2787853e2a72accf3dda02b203bca258b231b8b60f5fc0aa02b5680b15d6122e8d8bf5a7c474fb867d4f9840a47a198ba81e0d20b55692c528f0d296aa6ddb0a0e868fe41c00c01ba21900740a9cb3469e0948774fd769215a2b8ce940f37ed2b3e989c1883c548a220b88020dad389e55175989f916e62edf3bfdb9569ba33f8242a19e1c58141966be01e50c9514179644bfe6e2b0352d6d17eb637a498a5fb0d57181eb5400260ca0737e59038053a543cec243ee1da72263a0bd3669d4198b62855aaa315a7254603326e4a209116ba66bf9e7abfd34619adbf4086528fb24ab9780e54690695646eacdbb7e2f111782e11001464c22e74e52ddcba7a653bc822f6aec2ac0b694c9809d21de4e404e086cb67e7164b5018d29c3f64da96c1e7291949028ee6d279fa4314b26dc4515f95cd8436dc61a1c0dd429fe3652c8048c09392999b93b96de1be819e833d40b9f20440132d94b2cd13789473b5b87b41c75a3a5da6d8880013d8246ead4983d33c21e1ca7a6ac45e60c0e536ccd348821ce5bf59829bbc8a6357b5839cbe6d9a47bae4bec2963a023766b7d835f21d25c0bcf43b064400969a5ec08a50d245954e8c433bfc06347df623aaf988b17680fe0709012dbe9f3a071f92919de80f6825284a35929619732367a166b065ec83f9fe53510c0b84714db410b391ea1851d1313af396d8112b1c608300123d8d1c47df0bae78f97ca03f988d3ef3697aa76a11ba72e013d316a83edce235e680d8da0e6009dd019f6652ee8111419ed60586a116a637c9d2fb8ddea48384945337cc9720b63f6f7af590e4410d7a6be0c4bdce16776e0385ae3536a81104920c449298a8a0269c2d731a1b561a4e302358445cd1647abb5e54f96b07982e60a5d6200b9070949e6f974771cb9e3080d4bec507e3b462e8fe72228656201828f98d31b736e6dd0de704501dd3e069e7a070ae89c2e66ffbaae926426ae8d507f469b348f0996fa70274a90aeeb22ae51f11365123d7aa93ba0f309ea161f66cad5ca3795563fdcd0717d8650cfcf49821f5a600444b067f7d9a9619f2da086d1877dea143a77097e6999612155e9544a4c88a682e5014a8086c18a6e88942bc38254ca4c3021641b434623a046138b9166039e46e52bc2654f52cc367917fcaa77c7ddf798e6930f6cff97d8305c5f1323047f826279a115abf31470bb6868a4cc9a1f099246758a9801b769ccf145809e4b0d77abd4997d1bc88d90cd1a26ae6383fbd7d2aa3026ef860f9624ad092839b7d5753f1e266ac02614e1dc23052bf8171268aa8ae6c67105a38a08cfd93d7a0a35f5071104f7820632c760756ec263784676aaf708d6699fe09534dc1865cd11b1a58c190a20d93e33204475daa45f7c11e61900754ba3e93827fe2a2212a0f9839c22924ae69102f1ca4c1e1b8125df684cbd1839541b856d75825dd24a1a615810541348020f56952d89435c006d4aeb365ee11ac9a14709c8a894642265d03022243bcef2826f94227d02a1e6851c98c124162681a5113eddd24b3d889b58c0fe2a396a67b8a952b627c20ce5c0d8d66985261ad13b7658ad0b36ce4e24435809b928dc229dadbefccced1746a616d8d202037160442edde9e0f730542355d9cbe81433ef1e8714276dafb05671149c9a77e69195856e9e315820ab07cf35492a0b8009bb7c913ccf34ab5589ad0d6d7b6840b9673945ba16667a03cfcd70a70d14718c5b228566b54fa15fd1100a7e7406d72c6494e14643030d35a44d93325a07083cad85ac1f51d05542402eed5bf08e4e1046c3b4607ff864e4681581376db62ba977815e28203e066702c911593ead01d6ac4c4a69505e56ce6d59ae149631dcf19c2b0d8f05846a9a33901cf078fa35aa5d3f67d52649769daa605282581dd8f4c0f6156b2208841bd3c1573b42fab7c74db0aa0f4f5927e24765d83a307b644700704bc0bca665e1a8c240a9e4296d0873a6041d18f9633738402682fc23752931c611b3e526f2d43d95a346da7835e0662a68daf4de5e2c7561b1b9e2a836144be8841e157f62e22aa0293cb07183e0b9e4b6bfcf6b7baa91353264ad91795e2458125d441a4fb04ec0245282a18abbb39f6bd6c695b392d7ea22499eb22c5a795223191848d46f5691615b274ef72bf28d4226928947cbdcb02a0bd8e28ed45a
+InNoiseE = fbc6ff58a75dbc6e5cf3845afc27d2e024f3012cb691484ec86571bcd098636a008285835cfb3353942b9ba32e97ef3e1e17d72cb53cc5aaaad50235ee2ebe324a50b911963da9db2df069fa3a9905cdc54f0a8e5defcb69d08447df66b34244b4b879a6a577ff1a473c00b08b6eaabdddce9214d64628b053bd47633e215fc5f28a3bb10c115dabb2561d818b0147f5bfdab802decb987d7cb6c503a55104965b5fded9cb1d8c7faf557edac6c45acacf2f91d7debde409fd0b583060e581e7c50542b528099b192cbcb220254e17959933cdd481f944e99a8f9b0736dc9a661540f2e11c503f3614d873e4929b5668be71c9291f2f4da753747a23fa49c139127202ad96ce29e3a247cb638d97c40967cbd1b1a0e1ce6420135f8907a5485c505c73946046add0ca78491c934fa7851acb4e857110b4dabc1da28382ca03f59d69906941829b2d2d72ce99731f108f78cb3956096911cb5f98e8a8a5a109a2acb22bce952721a6d47844183e0f8ae14b5914de6c82a8b821a96243d9cbb7404308abac47904a0ce596f6250ad299fbe8a546482c7afcdbd745b942814e8d7b5087113d5885ceaab6c1893e166bb447f0079b1746ba97d95de7cfbb09c2f884be4927369cedbf8a4e0140d3e4409324cb5ae536356467bf09ac6e2f2a483451f406093a8943d56cb8302e9f898abeea41490b42b9b6e086d088362105a5bfb7605a22a77c5947ec2bb07cec320523899b3c29aa5e146b064f3e959340f1c51e380e1f94ce13f25c568865ae7a1dbdac6d526db2cfa44a732853a2dfb90df51bb0147e257557901a3474f863e6c100086d3034055b596ac2debc72a9f1376ff536facc099aa88cb2968c5beaa4f48bc099ccd6b5f8b33b047997689c6a1b9bd48a2e893c2c5cda755759840ca8e227f9224c74ab6e881a841528c7f0086bad9af2d82375aae2809cd5b4f665a445c4cd2daa50d146c983ecd2e19d8eaf85d24321163b921869807e255a4da5a5800b51a84a0f7cd447587fb66e3f94f7f08359233676ba7d8e44406e7a593549b2c5a72148256c3490c65af28846eca88c2529018c1d0517557aca9d9a4f35eb35a5345f2e3caa0ec9602ee97dc18c049d1045603543c404b82424dab739a2a42be4c8f4d83442c3ae80b91425d22a4113bee47a61dbe74bdece5d302dc2459be992c840d0d6398068d3c0ce578d997168d81d1302e86c7843d93419483d90e7da02d97536ad0ca827ffc8bc5ad761c4da16bfcd866b103faa4040196c383f11822bc865e6288d27e98759da788a46c827a2f3662a205f98be55422c172c4fc2eaca3a8fa911e7ab157284141365170ea02c0461c7d000c11f781175a54f92694e8716f2089aa85c1df74bf8a547bf991454c13ab7d81dbe02e2cc4ea953d7849d59a649120c1a630c4b57d4f5e67ff67560c93266453e12cf2234ab34a90531c4fd86764d847addbd6921be4ba167534390808d742dd282c88a926fc21ec6e8b059b65e3bc8c4dc738425ef9a0ba10e681b1ed8ffde75b04f955bd3358f741c5be06bd69b222d00615a05006def7e01ef5992bf93209945ae13d6ee6f44a1c16340181688724e357669d6b04f61bad76742268c389a36cebbe609294729e4e364147c6204d2e7f6b1954a92172a10cbca1f47e0dce19e356d4a0521830f504058c6d035b471bbfd9bd3db70a87f621b59ea115e5d1b028cbb66288b49cd48b567611602931697117c94c65f51a07e700bcfd60ed54ebe18ef0a72f2e9fc293da7f332c709996d66d8e4b785a2e6199c08368d2e028e023686a933f6dbbea656990886e8eb9931bcbc16da0950498c0dfb43655689ee3794013a69e0ca65c3a5e1c4923db71ce7b6693048a9fecd8895ca310fa1d93fcac2093169c7e458714a2eb1ae319241c88b491b75f4ac567f40211eb68dd6adca53a368ef2e6c0b89570821ba5d9805bcc1fd141a8385e7884e65af2852f9411f01105068fd41605572f0cac986688a42bfa5c7472fc17c220e594b7194698cc87b4788c831df1afab81952295a631449c7696b66aa35e82c34466a5625b1d3584492ac15a05cd2abe26fcd647c526a226743fa7aec6e5ed90255aff582be19b80730550fb8e3a8218d924c5dda52b5f7cd6ba049192244b43c01eb98f7650e3fb99581892b50601282c2b085ec858c1fc90b0c7eb1a72557bace0eb536a42f3310a29e08cd84b3993895decad42bc1701fe8629464de55037d60e2d3f0c57fb98dc1f5533ab708a950020bae7aba840d7a7cc1bea74c37da9d3e767951d4c9a405a1410f1334c3bc058ca75052c17110b2e025f7323a66add069f0539d0b9edbf548d7c110de42c4b4ee194dd76ddc2b2dd6a577437f927cd6a80e57acc6e752beb1c9e6f39529966397deeaa7e956f39f9de62ec00bd2129eb6bae6877824e11565bd6c8f0773796de4acab01ce8acce5a44ed9a74827088e8990cdaa56c264751581d37555befd6e2db56df5a43943ed285186161729dc14804082
+OutPK = 3821857b649a3bd42b7258662d639824e8b22c7661d9e7be58001824e56bf942c51a7aa4cf2e064a7e0938df4aa774554d9023d7887196425a41d0ca79b166690154c32dc59e580675dba22a63a76894a216f96241a7391a9a3db565e906077c040ee29297a2cac16159cf7e0822c097ce2c47556eb807e109fa6adf886b3222213a159507d209d494aa2042d2af1ac8933cb573e26819f05c36468e33f0eab26466c0fb0735cdb97f6270f80dce78721c73c4bb840cc6c8475b1c8d83792498dac8353c30eb41e5bc1419fb8a4f11384431e0c4ab597a3d68b6eed71ba66a21d8d714d77d7e4c7d1fd994ae407d38c3f631631a1ee7a3872b4da184cc02f5f947d2ae8d96740a1f2840eeabb1e0890e42828a0da52b15679de6a7f519b5b6d60e808b1819861c0cb87401a47d4f27475510d9b67be9de19814c0c6cedf2b254190147ee115b97454401de4a0621fe5f4e544a29f2962a814c2991099207042552388145837886ff93c9ca76cca1ecb05eac9a45cc5f4861909596ad55d9d5d627972cb35b1b9941e6281bf29cf9a9f1cc2298605914ad858daaada41a9a0dbd16985abc8b22c064690ca2ed022ed847bd1daa98a76876368277c82921ce15a1916d1ba1b05a86a8cf6600041567049d51a9c416a5314b13a8ce753eba167ff497d08209509bf4206cad3f852a03c54d31d5dd5e37d13e96666ba9f3ebdd8bd7c5e851f73cbac90258a90bb91bde8e7d003b0c2b2786c966d6706e4adb3a81e4b1803c99a00bd94d45cb0c4307ecb9a42f9dae935a226e84472ad76ac59fbc5dfd662c7e917000d7a901d427490bb0f0555d59e39c4864a0c62a2dee0dc2b6a856695c8e90a34981e38d2239da79a853c979e7bc5146fc23ce8b945e15290f525932f409cd97ee41d4a0ba6bca6485e95d476fabebb320ea2b639a16d8cbdc6a55d72557f7509f9a26ad3053165b7ae23a652796270fa783d417e07376d41966ec36102b6bb175c2cd20ea5abf92366468c74e0196afce0f23579bb4575c235651ff10ab3a4f38813bc200de7e262e11ca31e8854f85c858bbb98fc16f60e730d2b817489699768a7dff031036894c39ed99c2818cfc85ac51e1617b8e7bfd9f7540c0e938798bc539b1509a10e2bae74d0a5f998e2c83a53a3b8c94bf65b96c98c4eff216d1f93593654844b6f0af158d032bbe86196541d6d466c2887cc874d2cb75bc06a68585dd0a96d4de25c21ff64d7c0c20716032981a23acbbfc6980fb6a8b53475d644640efa7eaf65a830e95f97bb97ada61b2a14bfa13f7dc4c4a26b53541c53f51c9319f272e36e4b9d855bb09277aea1693c6e82c27bd85509751af4a21b0595c2ab164b79176d2269cf7903e996ccdd4724148a0ebc47531d04881ef562769420596891717778968107c9a63c86d491ac5dd885b672908e7820a419118633896d67a3274455f16acf436bc838a2cfcc5dd8503a982101488457d63043cf83bb273abdf0daafc5d966029fdc9235a9df74d024aebf08b4a9aee68f2b16185ceeb73a4394f015263771fda7979d947e84c616f380a87935ab90f0d9afcd79a6aad65efe6893ca21016915ef66b26aac818ba75a9985045d8ab749bd4a6ac8e2512febc2827e18965e37c9467982f0ab6a57cf70056981d4810f7e21158ada05fe354c5f3b1926802a7a3f88c411c2d01d9e56c2263bc64cf3805f0767b5f199b3d6535d3002b244ee2b0974acaebe9aa155ea9ee9b021d473f8cc545e45e227e8ebd5b4542b527ea5b4262a04f8169ba78586a830cc649d2b78e6f726da1b8e56db1f5e01a48bc3a379967a9772796450fe5f3863da94cef9671f4f56a3461239c3579ce7d2d6194cb84504a7a9cfe00f96e29d1ab69313bf95c021801f0507c1801081484682a15b241f8e7f345517ded639390958b448869ebb50087482f26fb8c7d7aca0f6720ae0d59f21e22e1ea66af51800fe717f444d9ea224216460a2e92f09aa3298879d388d8f2540dcfe5e617190e26fa6e87b9c91685a1131a5a14323bcde0be36d78510872b79a17745733311236875c827ca094f0ac6e5917d9bd6d0e3cd2194cf79e39be41b8dacf804447a44c6862571f0f496d9c8a8e549619b2b2f8af4d116a195cc1a34571a41a62fa09adec4744cdbe505f289047302a820a1a03ea9a2b6e9793d8a9b90b962b96e205d684161918194e1c085db26d812908ec429c199527d2b7d03e6b40fdf551cb70aa0a7a224b3c01bbe95762ce941d0ac72a1c0394acc994b1424985bbd6d64ec119cc535a00c229f37f7c21e32e92b9d71eeb88a118015b454ae4a0bc23bc8daf5b589628dd23dbca40966e0a7cc1463758abbd7ebb260da1dbe944df451fb5cd5f1437467d408509b5d5e726f265d93801155f282f73998f653e643c4493d70125f2c006b402eae4629efa69aac7ba8e8dc04b67009da88f6d8dbf148874cf4733845895ae13fa21746aa899b138b30b034d5e733380f66301dd129e030d43197c1b7f373d126
+
+InPK = 3821857b649a3bd42b7258662d639824e8b22c7661d9e7be58001824e56bf942c51a7aa4cf2e064a7e0938df4aa774554d9023d7887196425a41d0ca79b166690154c32dc59e580675dba22a63a76894a216f96241a7391a9a3db565e906077c040ee29297a2cac16159cf7e0822c097ce2c47556eb807e109fa6adf886b3222213a159507d209d494aa2042d2af1ac8933cb573e26819f05c36468e33f0eab26466c0fb0735cdb97f6270f80dce78721c73c4bb840cc6c8475b1c8d83792498dac8353c30eb41e5bc1419fb8a4f11384431e0c4ab597a3d68b6eed71ba66a21d8d714d77d7e4c7d1fd994ae407d38c3f631631a1ee7a3872b4da184cc02f5f947d2ae8d96740a1f2840eeabb1e0890e42828a0da52b15679de6a7f519b5b6d60e808b1819861c0cb87401a47d4f27475510d9b67be9de19814c0c6cedf2b254190147ee115b97454401de4a0621fe5f4e544a29f2962a814c2991099207042552388145837886ff93c9ca76cca1ecb05eac9a45cc5f4861909596ad55d9d5d627972cb35b1b9941e6281bf29cf9a9f1cc2298605914ad858daaada41a9a0dbd16985abc8b22c064690ca2ed022ed847bd1daa98a76876368277c82921ce15a1916d1ba1b05a86a8cf6600041567049d51a9c416a5314b13a8ce753eba167ff497d08209509bf4206cad3f852a03c54d31d5dd5e37d13e96666ba9f3ebdd8bd7c5e851f73cbac90258a90bb91bde8e7d003b0c2b2786c966d6706e4adb3a81e4b1803c99a00bd94d45cb0c4307ecb9a42f9dae935a226e84472ad76ac59fbc5dfd662c7e917000d7a901d427490bb0f0555d59e39c4864a0c62a2dee0dc2b6a856695c8e90a34981e38d2239da79a853c979e7bc5146fc23ce8b945e15290f525932f409cd97ee41d4a0ba6bca6485e95d476fabebb320ea2b639a16d8cbdc6a55d72557f7509f9a26ad3053165b7ae23a652796270fa783d417e07376d41966ec36102b6bb175c2cd20ea5abf92366468c74e0196afce0f23579bb4575c235651ff10ab3a4f38813bc200de7e262e11ca31e8854f85c858bbb98fc16f60e730d2b817489699768a7dff031036894c39ed99c2818cfc85ac51e1617b8e7bfd9f7540c0e938798bc539b1509a10e2bae74d0a5f998e2c83a53a3b8c94bf65b96c98c4eff216d1f93593654844b6f0af158d032bbe86196541d6d466c2887cc874d2cb75bc06a68585dd0a96d4de25c21ff64d7c0c20716032981a23acbbfc6980fb6a8b53475d644640efa7eaf65a830e95f97bb97ada61b2a14bfa13f7dc4c4a26b53541c53f51c9319f272e36e4b9d855bb09277aea1693c6e82c27bd85509751af4a21b0595c2ab164b79176d2269cf7903e996ccdd4724148a0ebc47531d04881ef562769420596891717778968107c9a63c86d491ac5dd885b672908e7820a419118633896d67a3274455f16acf436bc838a2cfcc5dd8503a982101488457d63043cf83bb273abdf0daafc5d966029fdc9235a9df74d024aebf08b4a9aee68f2b16185ceeb73a4394f015263771fda7979d947e84c616f380a87935ab90f0d9afcd79a6aad65efe6893ca21016915ef66b26aac818ba75a9985045d8ab749bd4a6ac8e2512febc2827e18965e37c9467982f0ab6a57cf70056981d4810f7e21158ada05fe354c5f3b1926802a7a3f88c411c2d01d9e56c2263bc64cf3805f0767b5f199b3d6535d3002b244ee2b0974acaebe9aa155ea9ee9b021d473f8cc545e45e227e8ebd5b4542b527ea5b4262a04f8169ba78586a830cc649d2b78e6f726da1b8e56db1f5e01a48bc3a379967a9772796450fe5f3863da94cef9671f4f56a3461239c3579ce7d2d6194cb84504a7a9cfe00f96e29d1ab69313bf95c021801f0507c1801081484682a15b241f8e7f345517ded639390958b448869ebb50087482f26fb8c7d7aca0f6720ae0d59f21e22e1ea66af51800fe717f444d9ea224216460a2e92f09aa3298879d388d8f2540dcfe5e617190e26fa6e87b9c91685a1131a5a14323bcde0be36d78510872b79a17745733311236875c827ca094f0ac6e5917d9bd6d0e3cd2194cf79e39be41b8dacf804447a44c6862571f0f496d9c8a8e549619b2b2f8af4d116a195cc1a34571a41a62fa09adec4744cdbe505f289047302a820a1a03ea9a2b6e9793d8a9b90b962b96e205d684161918194e1c085db26d812908ec429c199527d2b7d03e6b40fdf551cb70aa0a7a224b3c01bbe95762ce941d0ac72a1c0394acc994b1424985bbd6d64ec119cc535a00c229f37f7c21e32e92b9d71eeb88a118015b454ae4a0bc23bc8daf5b589628dd23dbca40966e0a7cc1463758abbd7ebb260da1dbe944df451fb5cd5f1437467d408509b5d5e726f265d93801155f282f73998f653e643c4493d70125f2c006b402eae4629efa69aac7ba8e8dc04b67009da88f6d8dbf148874cf4733845895ae13fa21746aa899b138b30b034d5e733380f66301dd129e030d43197c1b7f373d126
+InA = c664383843e8befe514ab2bda15c5aad395931045b4b1c235b7bca75ad04216935f18f64dbf1d22c2e410c50e84468859fa80efbd78b1ab2cfcba7f235b471e5107e3337aa4de117333b3de593075f083a31f22e59964846dd454df9d992372561218a20d1f59a6628c65bf060d7a6956e0bc2e679c6b85b44ee1b07a13faedcde44724d4c98ef58516be8346ea4422008e96d68225fc9e0eebd5d8e149956cd1660c5eaab33387c6c17774073e9516009a007de75172991609901deb2808a3b93a15cae615e19852ab9a8fc415ce6f2ed203fc1f785ef6e77739d44eab1720ada4a7ad43cd96b99ad29b15c80b42f0566315841035e246e6b2358372c5257a4b97c3bf6dce693cf5c3f8acf468ac9ee2903a075eb829d9506e0b21504699f7cd7dbd72cbe0a36cc7e6b47f28a00e5e2a848bd95bbcaa9e14f9a72cc9edd253a61419e24dda294fe0de54df1fb14227b73d7cefad3bcbbcd41e74199797eab8089e7e56990f86eed4a3c8c7f39df1a70aaee6fd429d39854286e52d1bd8a0c2a8403ea58b010f0a175d0a974365a2558446b3522186cc2e0ff1b604caf2b211eb080f507ded619594de87d7f2655a2ea918dc384394a362a5a985c6bb935c14100acca189e84494ba27373ab1e955b228122807d78f1cb4a44b64459c90921308a448a83e14556129464459e9204cb2a90e3295833701d0bb6e700d9b3ed30f9599a31d6e00d871bfdf7e3e5a4e2a4317b233e4cded198074395092d9c9c513fd295e71cf4e0e85e2989eb4a31c752b5791c66842db51e4e8e150b23ad4c5724bff7a4f9061e5ae5c91a69615aa36fe6eb044b374fd2b88d5a532c608c8aacb091d08cea8a67a9028e620d7b41047d7a88d07b39050aaa67703101a492be1cc1f16224a91c9ce75b5e48ac5389aec2c7fd44b3521656a38e849b52d7c1dbd9138f868f78cb405c830a00a60f0e6a814efd8599726fe913b7b4fb36b2a94eacb7d938a1212d5f2aca551a2166f32ae45c2933ed945476014151448f649eca8b1b2b07c181e9153f4d7c78eea1b4ee00c4316fd073a1c9da8bbc2876f256e3d2218a180b2efc04fdfe61d2c417093e483bb0535a6892d52515ddbdeab4544b8b45e945650873f24025a6a65c3fc2202a244c695acd60f555f8b5ba196336daafd899ea09f1a8df918277889118383c12e5a8dda938ba5d0214148a16daaf196b6f12a20d17a6d1b57882b4437d9f0099cc483e731fabd2151e4febef2d55bb881f271a343306345096e8c4658a583cf2682d41ea924504ad0069c1764a5fc2c959a14d93ecadc18635e476b7d639d2bb008fb1e05ab6e454a30143f859f43477e7cc6253df152e2fa42958d67446dc9843c42e294b6196eb17c928811c0f686902d52cc24652e43344a6da135f6b2df84b4a802f703965274f8d5566469d9a146a65978d1d453f581881a52680f3eb9a89677563082bbd312bf53a569dc5c6f1c13279de627120fe804f6305a897fe479b1a5729836db61c9bf9c3cc96b9eb52a4836ce0608be6be33f1d2355bd45be2449d10e4012e3a92e420531056ea532039f8ca2daad8d0051d5b201b262db64e0c60901ae91d22126ce3390692a61b6e13d9a4b6ec44019a08e9241ca5e0d261baa092161eb58fed33f94e91a2bc18b7d1dfddc122de3c8d93bd6619945987c8af349714109a65b3a0f9a946b8843b1677d867aa8c5b38a1324d4a5cffb8d98e94e4d837b16c0a823f04ea17d4f470f7c46cb49d01ba23e66f966f111a525e662a0b69818801b8c4c7398f21954168551580766d4882b0f6586f4ace742d2c07b96dba61dfc8763aac92289e84afb1ae4afa784204e82f2c2461bc073da91c3615ca970f195e37b9e5a11143e1317336b320d349b6402979cc6fa1984a843cbf1435a519ca957fcf45658ddaaa8fc130e1bd3ebe5c8b4164fe6a0b76d6e3f252d170889572babe5085a68fb42bfbf45a9419372a7e926fc604faab4ce138d34a1e6438c649ad282d4077ed990b911656c6192cad9a079764f995179eb3225fc67fa71b008aa1a4821a991133497e28cfe02ca4a87cb087c412a8998d22fb4e807bb51ebfab53a6c9a6602e9cc54f1a8f9c53ef95c5f0879256b1d6fe2aacfd488943a49135d49fc54fd326e5963ccc451583030dadf30086128bee2b74902c58d9c0b4a10bce90a3848b75d4751038dd3ae5827f95a83476e060f38779d151a8deb0517b6a526415447b48f66ce28615a5e3c10f971397375a7c0ac5264266f4b930c34faba354d29f795c9aca392413586218e567d9bdb95209c94322a1d96c9a628f9e97abaaf6332e4e61ed0d904b119086ed021401be72abd6c460d50dd2a7d29ab890528d31070b7d781f2a6912074bd1fde427f60faab61b263c2d52cf6a4092b66e9080617554aeda564da0f5c9586c987541ec2551a7ca0d512bee052be4fef66f750b7c9bda78350ca4812394545041af7d550d7142e579db6d954489301dc4cd9b405f685d69470c325c490b
+InNoiseSP = bf801ef9346a2d2160cff456a246c4c10e277bca9ded456ed94a385883620cd8f78430cf918cf9706c333cad91fbe1c05d81a06ac855224d03a613c2f1512478dc66c53b8a049a12cbe518224bfed226643c21155a5f28d9d97d78e70b0cc0af0622b3e8889bd8093442237a74f4dc1877a56594fdf081326fc3ab5b6a8fd0441f9331b64ed648688641198f2c84d16886c45f8856b5b04a245aff2a2e45cc095d9e24ca9922a6a4a28b507793dc8b7b84ebe0626eaec7e2f0c6a5c547e7938925cd1d373ea9979a3d2236a8e13ebb91d481955697157c76a2644081f7e96e587224ddd09fad2c3349ea6a6406155aa5425a88ce6199c78ac65e6a7d1a093ef0b27003e69df3a7094149cf4aeeb6e836b55a170437506a63090deb09cb4090252caf5701350c62eef2a4283287c644227903ee9626262da3ba6a35be090868fe580081de6a470458004e663d00169d71fd4b8ec0d6c603a094ec4524941f36027494310d5a585d30845dc22b0993b8b0fbea878d5e007343e980341c70d0f2553f0e2358d64872a9b91af5109c080fa05304406571856be3ec83d0181b030b7be53d869c1065156a10c5a4fc9bd07b63400dbb0c8568b5d84139e597060ce99f8962f356123e398e819d2881309a28a94faaf8caa79666a9943eb912b1473988a91564d79bb704006e2269201b68f91c00b3816d427b524e8d882da57b4193a954aca5c88438b82e575513700883c57cc5ce78b7bcddfed635718e1cd5b02545c532802054886d486ffddec2930110042a27420a0cce66d1dffaa1f7e47c0f53d3f4c8fe469410ea2831d9131f0049fb88d5016a691273eb9c9784e8ce08b23155b7c2a230c5e5a33f6f31e3c291219b993d6822cd5b822c9f506cd6398708e68339c49fa61ecae19cce241190bd54b2092ea8476e9637447f812a8de17b6a0e94df0a97a9ca83206e08c9aa05076823aa5be46e24cb05bc6aa11eb09a633b295aaa47e862e642b98e917e4e7ab5734e3b8063632b933c362e52b3e64f0020338cdf36fe1a173094ea5ac75e2086082a5b315d8f559e30598430ac27e6ac51b854079a8bc06bb5582e2ce348f1041845376f23d8a7b55441aa8c898ca60ebf57c097acd405df4f34b08a7439a9518d31dc78bc1c53be8b20d53b686b94717cdd76dace26bb25424eae6d47e7ae558be4488fd0b348bf4e42c4756a129bb62db6d7b25949df425653bc59a691db2a8bdc4e291aca98316bce06b0df63a0a6ed93c69b7a1510486318ad3dea55f44a4595a268b87a2ed4cdb00543a4bb6614bf4a54450921d2a9c474a0263885554924f119d7030a899859473a441276de02b71dd1f07b407d90ad27280b3fad4203656b466f5832724903e7db4c3a794e43a4f4416f7a9bbec811aa0f798952a4bc484e65222ca76c1471d1a36261b7dca89e5ab26415d1952568826ace34067713c2d15d991c1a5639139319a11d5ff2b6eea8229d6134b23ca6acd2569ea467b58fb58694c247d901c76c76f0c11a4b131336fb8bed2440cdb7a18d145b74aca0441f2d3151d09692e02c3fe06ad9e3bca57f3407513207b4436b4ffc795e0da3e75d78e13b295efbe0776b61ce1e3b95d130f3720cbd024a829410528c8066450bf47fec2b4b8116e067800c7753741175994e957082b52ac2a0f1570955a85fc608906291013a20eb7449769e6b267dd5553e1344dd46a700b60b0316ac1a6dfa4dbb64c449e5fd5e3a093c2570da1d9e4163b9cbd249180046221cae2d365725d7e2a8330641a4d0b7fa2d696aeed0c95416b0a3a274958c43155f2110463da5da99abc19ba40338e59f530c220d2867b0f69d4e41d6c63324c88805bacf3b2ab38209045561b3a79098bd8ea1e6e16cae5fef9ff4202e01030f68c517f93cd6c8128b84b68d8f9b74d2594e649f59f727709db60d52b16100c0349d841958fc38019918de3896484befe67181cc6627eccb7ea18710463d240a555f7c6be493bd2592653a4e8cdc47c8302ea9cc908257cc874c28a550fac6618b92985258614f0eac9c9443929d58e6a165e5c8837fe43646933cb04c9efd0407c97a2baf9d71bd9c7a5b4504f22c728056216a54f19419d8e72555e378b8db136ee0502c07c4a15ea72b1862f7a40230cc9a69cb6a34e6fd727393e8a9a85d88540f16a6c3f36d9d2aa647c9c10c745feb0e638fca46cc650974b91585decb5cd983e222ce109852dba42bd5dcffc7fda94f80d9147598d864a7e26e920608069bdf963a377499e4869fb151d07a5c0c8f388f3aaf6447540b92f9606cc62fb0e5b457820b2ad2644e99ad937799a4dc584ddab30a2db62b0f9cde26a78a739e629d43c3cd4ede87418a2348a8c64413e800e9ba3c45fa2642b6bc824cda7b0ffc6053a7b878516286adc754d05cde3e6526973390e8346fdf4a74d64575726e1172c6a89210958819b5464a1f0b01a8adbc4243a4a3999cc9b750949e38d84870cd9c93f88b2d167ec185796a6e19d042da81fcc42d
+InNoiseEP = e09827a03ea2aae6aa6f42fc006f2f530c4820199d449c5316776d8d511421d603bd6b3ed5476500e481226b0ad6176a77811e346bd57cbbc404b4107239ac64ee63b5e89c53b8193bd9af8075b20d2fd49da9af0c01e908575e14f7144ad4454852812da1e5503897690469baee995969095e858096afdfd54fa4ec2aa9a21ac9a7ee4c1d0207932ac7104f61886b94a8e1617757f487e040976959afd026768a8d4d734adb3d35422363268fe98756a6fff5c29d3e8d434845de66a9b2692bfb19ba7d49c50f078c789bbae5ebc3dea9920d5fef37462a3d194b8f07ff186870047b5bc9ca9f658494db39ed5bfa820836789203615f0a61412e079ec76b671f9a79738944bb466d982101b296cf6e158d46432003a69ad89fd4c23f727fbc40fc62a69041b66b124a9f2978d451120ad11d1a81996bf2c8363ea0670244fee51c5218e800ac8838588979ca380c94698ba210dee9226f1fd49663bc422f646b04bd12b0d82cd212ad281c819f61a1cf1ca44e1508c8b67d9e6f2275879bbd2060c6f611cf952939561091109e2cc781723be2dc7a2c064429f4d6234596149466e02839043a7068f0aba01ee4b4d49da084402826de309a5313567b78e6041ec0ffab92ae74af93a260bf824b6da2f560a36842d92979469e2c660b4298b86b264fb18165f36eb60f95a036e1c7ae93028b90f49ec00fccc3de4678c25558d14238a9dea4e4498af7ba82785756a5610f4c920f1a5235e4c00b635ac80567216d444683d214a597e59bc7e4827514a62fc30b18c97f325a04208d059c2f1283f3273cb2bda28f666cf009ecad95b3d76d6ab0acbc3a1fd8bc5a8bfd87829e21000ec3564379710e6d6c0bde5e7c89d977e6fc393323d1a2db32d68866c4e5545bb6463f9c47528de934ecd18995562e6a5f50649b5b1473225d87ab7e16bbb0c6e149611213269272c9f0f2a7681776da3c0e6a1285bd43d930ba9e9f77e7601a16185895fa9df01937c11ab210b222c288d994d2f23a681ec270f41110648e46b414ec9ea62fe3ba0969796e9122d34d8099c06991a444720ca3ef7fb034c452fb6fe520954d5d806705e84b706ba685f4e0d199af682220b3b5ca72d322b55371e4b17185b5b5abe913cf2521f90cc548acde5c39efbd428362bde206a44b46a9ac756f2e00954ec212098e8bfdcdcea08d393532220c4899a9631b815bfb94da8dce69ffb02ef4b4a61840c771dab530d479f6730e2a94cc52f12d9caddce3eb48eca0555628b6320ead812ddd4e28845d755169ba0548289780533fa6e8cc4396570af40e412f36930ea994e8b459c78be17a7caa4454dc5097fe6ee1e66587337240710e1d6058a4147de4a9e122e5ad84d7741a700472b6025d5911c28cb30989024b88a379193123fe25041edc933072c17da306d911c34ea31b485a85b62c9ccb948695c3795a35d50af9a926465212e76332104a04c468264ad679e6cb7924bd421eeb8c034987916696d5b345e69e24e59f9645a016039dc13f97be926f1b4ed25a5d4489ddce30f77df143846e6b66f2a2843b6f28d466a8026fa70db095095f1862c6a3042561a6671a16bbd6bd0e9651227d502ea5cf014a52fc6e22a0fe7af8b075d94cb5611aaeb97b6a51f42b782ff661d6646db15cdca511e2dfb0b76ba0acb77f209d42e1ace29b4eb1bd98b3d98b9c44c903261b480815ce0f4db8c7f0306adeeec79ebe4b331e3a116a91b8d6d26738c9d2b8864338b9837e536153fc482f958a208f4dd05c8ebe9d802434441a474acdb437a00d644e2509d6a00a23d4d259fb4ba220cc61506007285ec30ffb13465558ef8f1d24b62d317060ef05dc3e89efca5de506fd614dc4fe4593e5816ed4cf21e49a5892230b6b292673440c46f245066ec205b3e8528daa705939919d721537e330dbcdf5b2c347b6018c3a540258bbd781e134e10ece44e92d563faf542826b55f45d4b417254cba552b4e59d0a61ae12d8044e785268d6e9020c1095ce501e4370be80d2f92a274bbdd3d5459396a0c6815896cfc93bd3a55610882424c5632a722b6f4b26a2dde918ca20e385f4a27c2d97e75a6d752944a3598bba362f88b213e95cd08b412fd8c505956a8b1a37a0b99147534ffbe2a63a52d6234103af39081e72f1a113c8b4bdb36a0717600284b189237abe7b5145315329262fe596019be860182da0516575ae68a845d85a698ae584a5c846cf826c8a90fb20e74174592861c3a22a9c0873e3c6e4da84720fe0d537edc72cad841286fc21a43005c943fe6bec35484813bdc88455f7102869adb43195c9ee995d267a8ed58081d0a50f8746f6e0c3349427a1be61ab060c3d47a9a6d192036c10d0c538fe0268474f18550e41fad727a9b4b0016ed4f3ee04d02f4cd1d3f934c7b590566e7e849f37d329b7f5dd3abbd1a9dec5c90b415545ee1123693694438c46564a02082533c22c594191d04469b21c7316a9913893a861f2d4ff009fae3c2968ff8c82214d2ba4f
+InNoiseEPP = 024000700000c00300ff7b00f8bf003001b0ff0a00feefff2b0004000100000000ffbf04c0ffebff16000300010000fbbffcefff5b00fcbf01400000000400038000c0fff6bffeefff1b000c00fdaf00000008000000ff2b00f8bffd2fff2b0000000200000c00f0bf00c0ff4b0000c004400020000400feaffe1b00fcbfff2f001c00f8bfffaf00c0fffabf0040ff0b00ffbfff6fff0b0003000140ff6b000c0000b000c0ff0600fe2f01f0ffeebfff6ffffbff0a000600ff3b00fcbfffaffe0b000000feafff2b000800fd6f00f0fff6bf0340003000140000c0fefbfff6bf007000100010000040ff4b00f0bffe2f013000f0bf03c00000000c00ffaf002000fcbfff2f00bcff0a00ffef004000fcbf0000004000f8bffeefffdbff0200ffaf00300000c00300002c002000004001a0fffebf000000000008000240ff2b00fcbf02c000d0ff0200fd2fff0b00f4bf028000100004000000000000ebbffeefff0b000800ffaf00b0ff0a00fdeffe2b00f4bf01c0ffcbfff6bf00b0feebff16000140ffbbff1200004000000000c0fe6fffbbff0a00003000ecff02c0048000600000c0050000b0fffabf02400100000c0000f0ff3b0004000340014000f4bf0080005000f4bf0180004000f4bf030000ccff1200007000f0fffebffb2f00b0ff0a00fcef00e0fffebf000000e0ff0a00018000b0ff02c00030ff0b0004000080ffebff0600fdefff0b0000c0fe2f010000f0bf0440001000f4bffc6f001000180001000010000000fc2f00000008000040ffebff0a00ff6fff4b00f8bf00800010000c00003000f0fffebf000001000004000030001000f0bffdefff1b00fcbffaafff2b00fcbf00b000a0fff6bf0040ffebff0600028000100000c0fdeffe1b00e8bf000000ecff02c007c00000000400fe2f00fcfffebf00b0001000f4bf00f0ff0b000b0005c000000017000740003000fcbf00f0ff0b00f0bf04c0ff1b000c00010002f0ff020003400000000400ffaf0010001400ff2f01d0ff0e0004400010000000fe2f01500000000200000000f8bfff2f001c00100002c0ff0b001b00008000e0ff0e00ff2f02f0ff02c00030001c0000c00400000000fcbf0480000000f8bfffef0020001000024000e0ff020003c0ff3b00fcbf0030004000080000b0ffebfff6bf010000000007000400002000fcbf04c00010000800030000b0ff06000480ff2b000c00fdaf00d0ff0600fdef003000040001c000f0ff0e00fd2f00b0fffebf078000300000000180ff2b0008000580ff0b001300ffaf00e0ff02c0000000e0ff0a00fd2f0010001800fcef004000f0bf00c0fe1b000c000180006000fcbf0200000c00fbbffe6f010000fcbf0200002000fcbfffefff2b0000c002000000000700feef002000fcbf010000200008000100003000000003c000000017000380ff0b000800faefff0b000b000140ff0b0013000380ff0b00fbbf078000200004000180003000000005c0ff0b00ffbf030000ccff0200024000d0ff02c000b0fffbff0a000040003000fcbfffafff0b0003000280ff1b00f8bfffefff4b00040004400000001f00ffaf00f0ff02c00100000000f7bf018000f0ff0e00ff2f00fcff06000200005c000000fd6fff5b00f8bffc2f00e0fff6bffcaffe4b0000c00030001c000c00fdaf001000fcbf0180fe0b000000ffaf001000f8bf0200000c000400feefffebff0600fbefff4b000400ff6f0020000000010000ecfffebf0080ff0b00f3bf01000000001400fd2f00e0ffeebffdefff1b00000001400030001000fe2f00100000c002800020000c0000f000700004000240004000f4bf01c000100000000030000c00070001c0ff0b00ffbf010000fcff0600ffefff5b000000ff6f00000007000100002000f8bffeefffdbff1a00034000100000c000c0001000fcbf0030000c00fcbffe6f00f0ff02c00030001c00fcbf0000010000170000c0ff0b00ffbf0180ff3b000000ff2f000000ffbf0000000c00f0bffcef00e0fff6bf0380ffdbfffabffe2f006c001400014000000000c00040ff0b000c0000c0ff0b0000c0018000000000c0fcef004000fcbf030000f0ff0a0001800040000000ffaf0030001000fe6f00400000c000c000400000c00180000000070000800000001300fe2f010000e8bf024001300008000240ff3b00f8bf0040000000fbbffb2f010000f8bf0030001000f8bfff6f002000f0bf03000010000000fdaf00000000c0feafff5b0000c005c0ff0b0003c001400060000800ffef00000008000100004c0000000000003c000800fdaf001000fcbfff6fff1b000c00010000100000c0030000bcff0e00030000d0ff0600003000fcff1a00003000100000c000800000000000fd2f00e0ff0200ff6f001000f8bf0400011000f0bf0030010000f0bf03c000f0ff02c00080ff1b000c00ff2f003c00fcbffe2f00e0ff0a00007000f0ff0e00feaf002000000000b00030000000ff2f00300000c0
+InRand = ef9e8c91a774589ed24f16603ee706cf863ae430553ca47912e090bcc2dad2ad
+OutPK = 0868b7095909139920f60b50f0b56c14e0287116363521de40ce41b87cef52e34f4d15f1a4a7c4fe1681d3ea5094cd440f3c4749e928b212d8285b6545c60cb7ab1bcb591a8ad10f97c5f2c58d5ea8b5cb51fc4dbe14b6d12021b73581c697bac19d68129d09d10d310f4b09d4627544a06690161e7cb15da077898fe207225d4830c8657150a76bc1e9168b1fe0e929b77a7a91de7129b965a92f2d80c15f0074b4eaa8283bb5a7eda3c8a74a1aa396e629c02a8d98fe9fdd05f4a623d74e8211013241ae5f55a633aa65b6ed68c1fd41482262a856e75c75c81b7a271b191d47894d5987f86b23426b1368ae9c789cd298a6acb7cd4749f2a1fa3fa448db83e819976e6a9d99db028538a2234884d905099de876c108945c25780586319e1060d5f3986e00951017433599bd26cca7db8ec030bc1a565a59c61fc8a8c5f7ae087bab08c2e1222eac08d81ee84111153553abc5ae389bc9226e47854857395ed7920e8e01622ddf9393580a20877de6385c8d730ca612fe9889eae42067f97182dd2cd059b3f26c9d6384ea97603e01df8f172a5e2017956a81aae0272acbaed1efda1472a621f86c4e4133628293bdd603b20d64f251b649ff12766550a64377dc90c40d7c062d636550da144730060d4b185a1a75057cf6f2b159739306a20b6a5e4714ebb86248037216eeb3d1ac0440667330a0690bf8eb84f0f5fc5f8c2fa71427a42a225ae873cf3142c19b0350677e7106e4e8f7b8da96eb533a2afb565a33161aa66725a12f44d62bf5e17545a330596a357b65e06c51dd7150dbe9d85503b29a10e367911dd139bb65b62221893255cb6ea73f7067e3965207313d91f7a582b8fd9c84fdcdadb4b9111ce100b604ed3d88b1a86ec23b9c197d07ec69e2dc30756c2d95ef3d2e508d2991739cb5dca7759a4b8605c46a83464d86310c5ef6a6a240086c82ee1a8b1da31dc455d81ab8456e0916e9bc2a2668c10795e7206f2fcfda97387944f3a7c0a0c9c174d5892e7876943753c56cf951c8b8d11d223ae1ba55e3816d04795a95d81d1e92d0b8761f1443a6f25c2444987ed832fe4278e0fb81de4e03106e0b806dcd93190d00b92c2ca924ed230a6b7d23ca1f8dd8590c49ef050486da624dd42b49214a3a60098f934894d54eee870f820ad11d78834813d6fa2b69928b85a83e625e8a20a166cd40d85d8866980987d7002919d5111b5904837013c5795e1b3520cfc82940dd3f00e6d4538323760376a85fe44bfd5022d15646aeda06ae162743ae5a083d6403a917d783ccf9295890940599bc2faac9a4d468f9a0c6db7973d09525639cf0c1ae048a3a869be9316248728f7fb1c630424ccd7668daac8be6977f04069c034fa3c96a40c424648a4da0b808bb499435c4b3215c98d18ecbe09e201b9d1f473882343407b56605da6a1ec1745b45f1829f49eb80be284e589ab8b3df8d26528d8095895497bfdd0eb01a2ea4c59fd7fb2fa426f08ce8c252fc4875c38f8744a4385fc96cb1d8fcaa8ad26e217a92903865f259b5cc3840a95ff889656d031793528b9a2a46d7c58654d13a29c8fd99e38e7e81c1a0e926f8695d806eb6ad3866efa02046f2b00bade0d913ab1a8916da87d03d8a0dbd17f7b9d7692c6c5aecca2f05ac90a62b15497147181e1b1018d222ed4347d03bbd6f39d4b0caacf938632499d7c759b7eb6882467c4ea23e67624652ac414f92ea63295590b34930bb2b36744b0f54f434b863ceea67c171fd539616fee3471059c3d39f96c2ca04c5111c1870628a296fe66222ce84a2e69950961ca42ea8731230091db6492aa244f27729dc11c188753581cc8b25577e908d450df494febabf66c3885a7a159198c1010d569d0a952d494b4c729209b52a7020b1b6e06a81d8c43e9b216cc6c4291a7ced1c77313c423321bc20192c632a5f84e8819abc37848638f58a132122420ab2885d8742bbe2ece1795b1e5cb9cfd627e89256231cf185504619759a3e9ed5047d5bdc1208aa617af35c84a1272f986b9afa2331825ae107fa394a9a243039162e44014ca8d3c65b660cd51a73b4b217e97569b87836ba41d3da04b09f6e45ffa211122f266d43e8a0a66e41e1dd0082458261891d538094640080f9c60612a251d46cba88b8438ccc4228b6622ff81de322a3a20fb3d7179629a023d69c3a96cd5174818e037ab55e71bb1616e4412e5579d0dc941429a50c0fc37be6712a53e6010b5c8a94cc961604d05a847e8083703be17c0d133850c1f62ee765bd3ba64a0097223240a0dc7555d3db7274f65bc6a54b23477903f8a89d4a6ee534fb5af5783c381bb0a72ad76f25849b021d8871348d7d4fc9b61c68bc50c94e08562e165d4572482938656417d371568c6a3dca7007c26a5ef190e957df8e93f56c6be4da00b7a2e675a8a0094855188ae3ddee2bfb821673b389b8b32cfd83d88c986ae7e6f5f5b23e2dd62fc743e2063e8d3051862a54ef89ed823fdd14fbe3fce7182c27d90f981035d15f
+OutRec = 01c00020000c0002c00000000c0001800010000c0001800010000400010000000008000180000000080002800030000c0003000020000400024000200008000140002000000000c0001000040001c000000000000380001000040000800000000c0002800000000c00014000100000000380002000000003400020000000024000200008000200000000000001000030000c0000c00010000400018000000008000000000000040001c0002000040003000020000000000000100008000280001000040000800010000c000180000000040003400020000400024000200008000340000000000003c00030000800010000000004000200001000080003000000000c00008000000004000140003000080001400030000c000100001000000002000030000c0002000000000400014000300000000180003000040001c000300008000380003000080000c0001000000002c00030000c000040002000080001800000000c00028000000008000000000000000000400000000c000100000000000001400010000c0003c00000000400010000100000000240000000040000c00020000c0000c00000000c0000c0002000080003000010000800034000300008000040002000000000000010000c0001c000200000000380000000080003800030000c0003c000000008000380002000080002800010000800018000300000000080001000000002c000000000000200000000080002c0001000080000000000000c00020000100004000200002000040002800030000c0000000000000c0000c00000000c0001c0000000080002c000200000000300003000040002c0002000000000c00030000c0000400010000000000000100004000100000000080003800000000400010000300008000080002000080000800020000c0001800010000c0001000010000c0003000000000c0002c000200008000380002000080000c000300008000280002000040002400030000400030000100004000180003000000002800000000c000300001000000001800030000c0003c000300008000240003000000002800010000c0002800030000c00024000100004000080000000040002c0000000000002800030000c0001800030000000000000200008000040002000080003c00000000c0000c0001000080002c00020000c0001000000000800034000300008000200000000000000c000300004000080001000000001c00020000c000340002000040003c00030000800038000100000000140001000040003800030000c00010000300000000300000000080003000030000c0003000030000c0000c00010000c000200000000080003800010000c000180002000000001000030000000020000000000000180002000000002800000000800028000200004000180001000000000c0003000000002c0001000000000000020000000010000300000000140001000040002400000000c000300001000080003c000100004000140003000080000000030000400024000300008000040001000000001c00030000400024000100008000140003000040003800030000c000200002000040001c0002000080001000030000c000000003000040002400010000800018000100000000380002000080001000020000c00008000000000000380002000000001c0000000080003c0001000000003c0003000000000000010000400038000000000000280002000080001c0000000080003800000000c00030000100000000080003000000000c00030000400014000300004000200001000040000800000000c0001000000000400000000000004000100000000040000000020000c0000400030000c0003800030000c0002c0000000080001c000300000000240002000080001c0000000000000000030000c00028000200000000200003000040003800020000c0003800030000800038000300004000140000000040000c00010000c0002400010000000020000300004000080002000000003c0003000000002000010000c0003000000000000018000000004000240000000000001000010000c000080000000000000c00010000c00014000100004000200000000040000c0000000080003c000200000000200001000000001400000000400028000000008000340001000080000000010000c000040003000040001800000000c0001c00020000c0000400000000c0001c00030000c000140001000040002400020000c00000000000004000180001000000002800000000c000080002000040003000030000c000280000000080000800030000c0003c0001000080002c0002000080000c0002000040000800000000400008000000000000300000000080000400030000c0001400010000000014000200004000340002000040000c0002000000000c0003000000002000000000800008000300004000100001000080000c0002000000003000000000c00
+Key = 3c763fff910725780ae666ae0d91de15edb5faca0b8c2e22c318014401f91cff
+
+InNoiseS = 8159e4d8f3901f0cec2355ebc6511fa4993a1576af5257b606f5b5317703e6b78b4053961048db1d4661b68e7bd70c8a00f758c257fbb81ed7cc2aba5fb098a4a0e8d5b5466ad209a639d99c0408eaef04895cae0cc75a18838a2d4517b927807d1e83ef9dd6f1cc1d42ca623b720581b804bee5b95ea47f8a7440db5073166fc595b314a519c178bb37b14b7b18cbe4d68027c45acb6760ed815f035b7b108c4193e470611f2e413d50e7d0596537cfa86cb93c4400c8240978a9d2325f0d30776de50e351662f2d97c8878468dfa5555618c0e25e237fe268658069153d90ee7552296b0853f2e2787853e2a72accf3dda02b203bca258b231b8b60f5fc0aa02b5680b15d6122e8d8bf5a7c474fb867d4f9840a47a198ba81e0d20b55692c528f0d296aa6ddb0a0e868fe41c00c01ba21900740a9cb3469e0948774fd769215a2b8ce940f37ed2b3e989c1883c548a220b88020dad389e55175989f916e62edf3bfdb9569ba33f8242a19e1c58141966be01e50c9514179644bfe6e2b0352d6d17eb637a498a5fb0d57181eb5400260ca0737e59038053a543cec243ee1da72263a0bd3669d4198b62855aaa315a7254603326e4a209116ba66bf9e7abfd34619adbf4086528fb24ab9780e54690695646eacdbb7e2f111782e11001464c22e74e52ddcba7a653bc822f6aec2ac0b694c9809d21de4e404e086cb67e7164b5018d29c3f64da96c1e7291949028ee6d279fa4314b26dc4515f95cd8436dc61a1c0dd429fe3652c8048c09392999b93b96de1be819e833d40b9f20440132d94b2cd13789473b5b87b41c75a3a5da6d8880013d8246ead4983d33c21e1ca7a6ac45e60c0e536ccd348821ce5bf59829bbc8a6357b5839cbe6d9a47bae4bec2963a023766b7d835f21d25c0bcf43b064400969a5ec08a50d245954e8c433bfc06347df623aaf988b17680fe0709012dbe9f3a071f92919de80f6825284a35929619732367a166b065ec83f9fe53510c0b84714db410b391ea1851d1313af396d8112b1c608300123d8d1c47df0bae78f97ca03f988d3ef3697aa76a11ba72e013d316a83edce235e680d8da0e6009dd019f6652ee8111419ed60586a116a637c9d2fb8ddea48384945337cc9720b63f6f7af590e4410d7a6be0c4bdce16776e0385ae3536a81104920c449298a8a0269c2d731a1b561a4e302358445cd1647abb5e54f96b07982e60a5d6200b9070949e6f974771cb9e3080d4bec507e3b462e8fe72228656201828f98d31b736e6dd0de704501dd3e069e7a070ae89c2e66ffbaae926426ae8d507f469b348f0996fa70274a90aeeb22ae51f11365123d7aa93ba0f309ea161f66cad5ca3795563fdcd0717d8650cfcf49821f5a600444b067f7d9a9619f2da086d1877dea143a77097e6999612155e9544a4c88a682e5014a8086c18a6e88942bc38254ca4c3021641b434623a046138b9166039e46e52bc2654f52cc367917fcaa77c7ddf798e6930f6cff97d8305c5f1323047f826279a115abf31470bb6868a4cc9a1f099246758a9801b769ccf145809e4b0d77abd4997d1bc88d90cd1a26ae6383fbd7d2aa3026ef860f9624ad092839b7d5753f1e266ac02614e1dc23052bf8171268aa8ae6c67105a38a08cfd93d7a0a35f5071104f7820632c760756ec263784676aaf708d6699fe09534dc1865cd11b1a58c190a20d93e33204475daa45f7c11e61900754ba3e93827fe2a2212a0f9839c22924ae69102f1ca4c1e1b8125df684cbd1839541b856d75825dd24a1a615810541348020f56952d89435c006d4aeb365ee11ac9a14709c8a894642265d03022243bcef2826f94227d02a1e6851c98c124162681a5113eddd24b3d889b58c0fe2a396a67b8a952b627c20ce5c0d8d66985261ad13b7658ad0b36ce4e24435809b928dc229dadbefccced1746a616d8d202037160442edde9e0f730542355d9cbe81433ef1e8714276dafb05671149c9a77e69195856e9e315820ab07cf35492a0b8009bb7c913ccf34ab5589ad0d6d7b6840b9673945ba16667a03cfcd70a70d14718c5b228566b54fa15fd1100a7e7406d72c6494e14643030d35a44d93325a07083cad85ac1f51d05542402eed5bf08e4e1046c3b4607ff864e4681581376db62ba977815e28203e066702c911593ead01d6ac4c4a69505e56ce6d59ae149631dcf19c2b0d8f05846a9a33901cf078fa35aa5d3f67d52649769daa605282581dd8f4c0f6156b2208841bd3c1573b42fab7c74db0aa0f4f5927e24765d83a307b644700704bc0bca665e1a8c240a9e4296d0873a6041d18f9633738402682fc23752931c611b3e526f2d43d95a346da7835e0662a68daf4de5e2c7561b1b9e2a836144be8841e157f62e22aa0293cb07183e0b9e4b6bfcf6b7baa91353264ad91795e2458125d441a4fb04ec0245282a18abbb39f6bd6c695b392d7ea22499eb22c5a795223191848d46f5691615b274ef72bf28d4226928947cbdcb02a0bd8e28ed45a
+InPK = 0868b7095909139920f60b50f0b56c14e0287116363521de40ce41b87cef52e34f4d15f1a4a7c4fe1681d3ea5094cd440f3c4749e928b212d8285b6545c60cb7ab1bcb591a8ad10f97c5f2c58d5ea8b5cb51fc4dbe14b6d12021b73581c697bac19d68129d09d10d310f4b09d4627544a06690161e7cb15da077898fe207225d4830c8657150a76bc1e9168b1fe0e929b77a7a91de7129b965a92f2d80c15f0074b4eaa8283bb5a7eda3c8a74a1aa396e629c02a8d98fe9fdd05f4a623d74e8211013241ae5f55a633aa65b6ed68c1fd41482262a856e75c75c81b7a271b191d47894d5987f86b23426b1368ae9c789cd298a6acb7cd4749f2a1fa3fa448db83e819976e6a9d99db028538a2234884d905099de876c108945c25780586319e1060d5f3986e00951017433599bd26cca7db8ec030bc1a565a59c61fc8a8c5f7ae087bab08c2e1222eac08d81ee84111153553abc5ae389bc9226e47854857395ed7920e8e01622ddf9393580a20877de6385c8d730ca612fe9889eae42067f97182dd2cd059b3f26c9d6384ea97603e01df8f172a5e2017956a81aae0272acbaed1efda1472a621f86c4e4133628293bdd603b20d64f251b649ff12766550a64377dc90c40d7c062d636550da144730060d4b185a1a75057cf6f2b159739306a20b6a5e4714ebb86248037216eeb3d1ac0440667330a0690bf8eb84f0f5fc5f8c2fa71427a42a225ae873cf3142c19b0350677e7106e4e8f7b8da96eb533a2afb565a33161aa66725a12f44d62bf5e17545a330596a357b65e06c51dd7150dbe9d85503b29a10e367911dd139bb65b62221893255cb6ea73f7067e3965207313d91f7a582b8fd9c84fdcdadb4b9111ce100b604ed3d88b1a86ec23b9c197d07ec69e2dc30756c2d95ef3d2e508d2991739cb5dca7759a4b8605c46a83464d86310c5ef6a6a240086c82ee1a8b1da31dc455d81ab8456e0916e9bc2a2668c10795e7206f2fcfda97387944f3a7c0a0c9c174d5892e7876943753c56cf951c8b8d11d223ae1ba55e3816d04795a95d81d1e92d0b8761f1443a6f25c2444987ed832fe4278e0fb81de4e03106e0b806dcd93190d00b92c2ca924ed230a6b7d23ca1f8dd8590c49ef050486da624dd42b49214a3a60098f934894d54eee870f820ad11d78834813d6fa2b69928b85a83e625e8a20a166cd40d85d8866980987d7002919d5111b5904837013c5795e1b3520cfc82940dd3f00e6d4538323760376a85fe44bfd5022d15646aeda06ae162743ae5a083d6403a917d783ccf9295890940599bc2faac9a4d468f9a0c6db7973d09525639cf0c1ae048a3a869be9316248728f7fb1c630424ccd7668daac8be6977f04069c034fa3c96a40c424648a4da0b808bb499435c4b3215c98d18ecbe09e201b9d1f473882343407b56605da6a1ec1745b45f1829f49eb80be284e589ab8b3df8d26528d8095895497bfdd0eb01a2ea4c59fd7fb2fa426f08ce8c252fc4875c38f8744a4385fc96cb1d8fcaa8ad26e217a92903865f259b5cc3840a95ff889656d031793528b9a2a46d7c58654d13a29c8fd99e38e7e81c1a0e926f8695d806eb6ad3866efa02046f2b00bade0d913ab1a8916da87d03d8a0dbd17f7b9d7692c6c5aecca2f05ac90a62b15497147181e1b1018d222ed4347d03bbd6f39d4b0caacf938632499d7c759b7eb6882467c4ea23e67624652ac414f92ea63295590b34930bb2b36744b0f54f434b863ceea67c171fd539616fee3471059c3d39f96c2ca04c5111c1870628a296fe66222ce84a2e69950961ca42ea8731230091db6492aa244f27729dc11c188753581cc8b25577e908d450df494febabf66c3885a7a159198c1010d569d0a952d494b4c729209b52a7020b1b6e06a81d8c43e9b216cc6c4291a7ced1c77313c423321bc20192c632a5f84e8819abc37848638f58a132122420ab2885d8742bbe2ece1795b1e5cb9cfd627e89256231cf185504619759a3e9ed5047d5bdc1208aa617af35c84a1272f986b9afa2331825ae107fa394a9a243039162e44014ca8d3c65b660cd51a73b4b217e97569b87836ba41d3da04b09f6e45ffa211122f266d43e8a0a66e41e1dd0082458261891d538094640080f9c60612a251d46cba88b8438ccc4228b6622ff81de322a3a20fb3d7179629a023d69c3a96cd5174818e037ab55e71bb1616e4412e5579d0dc941429a50c0fc37be6712a53e6010b5c8a94cc961604d05a847e8083703be17c0d133850c1f62ee765bd3ba64a0097223240a0dc7555d3db7274f65bc6a54b23477903f8a89d4a6ee534fb5af5783c381bb0a72ad76f25849b021d8871348d7d4fc9b61c68bc50c94e08562e165d4572482938656417d371568c6a3dca7007c26a5ef190e957df8e93f56c6be4da00b7a2e675a8a0094855188ae3ddee2bfb821673b389b8b32cfd83d88c986ae7e6f5f5b23e2dd62fc743e2063e8d3051862a54ef89ed823fdd14fbe3fce7182c27d90f981035d15f
+InRec = 01c00020000c0002c00000000c0001800010000c0001800010000400010000000008000180000000080002800030000c0003000020000400024000200008000140002000000000c0001000040001c000000000000380001000040000800000000c0002800000000c00014000100000000380002000000003400020000000024000200008000200000000000001000030000c0000c00010000400018000000008000000000000040001c0002000040003000020000000000000100008000280001000040000800010000c000180000000040003400020000400024000200008000340000000000003c00030000800010000000004000200001000080003000000000c00008000000004000140003000080001400030000c000100001000000002000030000c0002000000000400014000300000000180003000040001c000300008000380003000080000c0001000000002c00030000c000040002000080001800000000c00028000000008000000000000000000400000000c000100000000000001400010000c0003c00000000400010000100000000240000000040000c00020000c0000c00000000c0000c0002000080003000010000800034000300008000040002000000000000010000c0001c000200000000380000000080003800030000c0003c000000008000380002000080002800010000800018000300000000080001000000002c000000000000200000000080002c0001000080000000000000c00020000100004000200002000040002800030000c0000000000000c0000c00000000c0001c0000000080002c000200000000300003000040002c0002000000000c00030000c0000400010000000000000100004000100000000080003800000000400010000300008000080002000080000800020000c0001800010000c0001000010000c0003000000000c0002c000200008000380002000080000c000300008000280002000040002400030000400030000100004000180003000000002800000000c000300001000000001800030000c0003c000300008000240003000000002800010000c0002800030000c00024000100004000080000000040002c0000000000002800030000c0001800030000000000000200008000040002000080003c00000000c0000c0001000080002c00020000c0001000000000800034000300008000200000000000000c000300004000080001000000001c00020000c000340002000040003c00030000800038000100000000140001000040003800030000c00010000300000000300000000080003000030000c0003000030000c0000c00010000c000200000000080003800010000c000180002000000001000030000000020000000000000180002000000002800000000800028000200004000180001000000000c0003000000002c0001000000000000020000000010000300000000140001000040002400000000c000300001000080003c000100004000140003000080000000030000400024000300008000040001000000001c00030000400024000100008000140003000040003800030000c000200002000040001c0002000080001000030000c000000003000040002400010000800018000100000000380002000080001000020000c00008000000000000380002000000001c0000000080003c0001000000003c0003000000000000010000400038000000000000280002000080001c0000000080003800000000c00030000100000000080003000000000c00030000400014000300004000200001000040000800000000c0001000000000400000000000004000100000000040000000020000c0000400030000c0003800030000c0002c0000000080001c000300000000240002000080001c0000000000000000030000c00028000200000000200003000040003800020000c0003800030000800038000300004000140000000040000c00010000c0002400010000000020000300004000080002000000003c0003000000002000010000c0003000000000000018000000004000240000000000001000010000c000080000000000000c00010000c00014000100004000200000000040000c0000000080003c000200000000200001000000001400000000400028000000008000340001000080000000010000c000040003000040001800000000c0001c00020000c0000400000000c0001c00030000c000140001000040002400020000c00000000000004000180001000000002800000000c000080002000040003000030000c000280000000080000800030000c0003c0001000080002c0002000080000c0002000040000800000000400008000000000000300000000080000400030000c0001400010000000014000200004000340002000040000c0002000000000c0003000000002000000000800008000300004000100001000080000c0002000000003000000000c00
+Key = 3c763fff910725780ae666ae0d91de15edb5faca0b8c2e22c318014401f91cff
+
+InRandA = 8f0774d3d5350bd8a9f1567b6408f044018892f845055d532885b240f813fb98007cb69e66716bc3e67f69d0331b21c613b367dc3263689b62a8b38b02846af41cfd8633f41b89aa2a7353c587b0d6b38a4ae8ad3ae2b279f340239296bea34b2d6a7048e1e38f98a6f3087ec2e24d9ff11a21e1f7b0a01e00e6b1a85c8e9c9fd986177153f76cc8b317ad0df744cf8498f01b7284038a91106217e511a0cf20ae7c5203e0ef196a552877585ad94c3b277e8b5edda7e2cef1455a066e09ef92365f19bc4c86044486498f6f4783667f72431283644708d03b534dda98dcae6692404fd49cad29b10115790de190f7eba815d93265deaf17f7d14651f8962e28394cae148d86181f7a81a941d1161198ab9d0fafa01525a043d6def1321ead41007fcafbd1243a1629d31e06776b1ba67a1bce2cd4cab1062b59877fda306afa8103adc95780c7f44b1b25ad03ff3d669d2ed2c42b46bb739ec5920d3e1f046469bb5c8d178c6caa73b82857ea5934fb87fa994c08a88291c2937129ade1e8f1a40899df5952ccbb2506b9e57796a26e999e2bdc966ec2aa89c4b8a85c15493a198472a857602f16cca5189ba0a303c6163a63d0ab94634512172c8d56a7917644937ab8a3a889f113a9738beea09f8fb2581e410689a626d38b2a3747d6873748b0a21040c8942e0e289f42dd812c298a23a5e7724f3d33cd619b82830e411d10fb9474dd95162587ab0d81a28d698e1a79e50b624f236b713a703bc46ff245387dab0a6bb77b0e0e885e7851aeac70e84b6d4a2e24bb6f9900d803d513b3ece9da5d495a18d09f61c3b50876967213f2cd4784044e5bdb3544fbacb01242e86ab0e4407bedd1ba31de696414b8a03ed07e227282602f9175a73e3698d696b54616b46b7caa419b870487f2e0869bb311398fd548897aba4a8a04f8d9b0152fb414c9a8333a48e1d7a19a7c864df42dde180148441b274beaeab25cd7cdaa5b3e369e0c16d1c8f20e2b8e5b1e70298e98651dd965a7a858a31f87c4da9a6c1dc20e025ad45f1f6b6372d99866b700d047d845b4b40563d039463bdd4e3e3150ec4aee0646b635aebf064ca1e9e7ee2483e46028a316989adf7483c160a08dafbec43aec6da81950a057fa20eb8046b9cccdb42c5e1938e7766c6f653948d1102cb399c5856fd91e1f667b27d205378f1aac0b83356cef589e5282300d8becfb547c7c297eef0c97335e1bc08869b78d46b6771f060b99b837dbee82b874a871cfe16937a4f07ed01815d7aec5664e13e755bd2c3df61f43f7c2b26e6610f5a9cc44a84c21015a06b0a72c22c68aa4493ea6d62f6258ad8e5ae1effa32c87f49431fd34c76995f85bccaa0e091231bafe3b614a0a881b1cb959427dbd3afcb9e4294c6e35d67902a908c1c42936aa258ca60953a9f4928f0820ac9f00d3c72c07bc11fc0954c0a72abbc3962a287da87ac994c1acd4aba4eda401c232c3a125814af2e2e031699bc0d600fa651f2484b1d7db75e22089492c574536e774a15c8fbb8d59164cda93b4066448da3fabbb7f52b8d6536cbea0474d6987f05c9e0296420c50a33ea26be27dc309b9201d5aa518586f58139136d7084585a3b2dc3c6b9895a0f5e468a4b00b0b52d98c147c641a2a334e45abc4289cc7f572324ba5be314e3e655b7a6ce63eb6ae217fb6f67cbb308350e91c48a88eaac9b24e8b35c05566d0e4cb2c1965b6a14593a1d245295aef119a57549fc4e86086badb512ac46d93ad0984fab1e8112a44a60a16e7051e00c630bf79042ad61a45147b1d7a531aa1c9c9bcd708ca12273daae848d990ecc46c228ad162e69302db52a008aea235a10af962b6b052c683b0d814fc74d4807076b8a0050789fa7569604a34d20b4e67aa5e6956e018b6e8696fe28f9649aa210a54d9c8c7c92b2be83a514a1a6f4e03bc721b180099cb14ccd66e812f97205a7310867f5348e6841309e8a7c2bc8fda8e336589d900813046aa96513a35086bd04745b4390ec2c7d981cf752df3578954751dab2265820ece73745903bb681cbe68f52a9f4cc7c30fab8380094df1296a1af88296b55b2a9b90dcf6a0aa8525f005706908b119727004570fb446a5a634ee44cd28e39cb53f707c9992baa7437f74d938e280a0bf29a40080da8d4798141d6a79c33d83e9b6fa01286d3920a1f5450b1c46241370533b1c5701e4f6a4ad720b208d7e567badc725c1e1364b597f03c4ddc1cc33d251d99a69ed744e04e5a2b8471c0a892fb67e0f75368b35f59c6aa6e9557f15b2cf78120a8575ffde653c968949254113406b4e5220833200c81c3013cea24983bffdeecb0f294041de340975c329b3dc9bda0a9562e436efc1b6c707c522a23c99e602bf103a01b5ea4029319f696a2919ab5c2c29a5caa59750c8ff424288e160cc02286f2ab68ac098ae8e59225c8b3579880486cab2da4e87d10348f5d97bdf20b791b60fb43d06bd88c3153c17819feef2c19df7d2cfbd4b74adcc61c370a16fa1521a2
+InNoiseS = ad9613f7d3f429e39015b40b84b0b0913ec1c4208c24d4573b1e0e5cafc5c2e3304c02271d1271721028f125e6974c6682ea15cea2cbe61cd1c03c601a708e42401ffa6cdd6bdfc925b9e520914a5902162f2db0a42b389894122e95cb5b12393642bee7c43bcd394449a938e73625985fdd9897355e13a453e073ad38438fe88738627c7ca3d39137a8e996630b1644a01c0cc5ad8c7ba79da067693c0080bdbdfdae94a5622587c4635fe319f439c7805e194b785fb65e1ce58d446e131206b025d98e60d10a1afd716e79103863382943964362c19c48a3aed93dc2aedaa4945a3d47a07ab585c3b7e377edaaaf8e4552ec3cb049c66ce1a7d9157dd552a63008a3ea6ff2026505788d18bc0152181b7b52489864aa4306eece17e366a9a822ad131059258665298515f1b8b691e490c9190ae668b2e6aaae8633a9f4b1d1a1015009c041b50e55d0d3d19066108e58c3ba80a67213c851687b6494a5235c7810718aafd10b7295810284592327f2b37ab9cd89eb80b3a81130e3a604796d95b3eede92df111d7264d21483851394002743f9fe13555f35250499421f189a1b35a92a2d2eec18e03183042e9ee7eaa15b9c11f17b4009a33960f9d628a225ab1c2557f8dca1dec00f82f80437c10a09f04fc52d3b8f95c19d86603bd6be368d427f274d3946d0221240cf76f4c4bc86b963f1e72fdeaa7eda6a382b41ba210eec4bd0a48b509dae0455a4381e6ec80226920a7fc67649fe4017b26407624bfa60da5c47559f248793eb4dd1216665201762d3b64c4782cf1175ff2eab9c6868b764d27a8f29e882beee78db130563114a1c8d91f125748ea0cfe56361aaa55b8d45a507754d332b8e9c252728b103aa48c1d5243c8e9e9a9879564f61cc2bb8cb3cbec982167859524f78cb374bb95056505acd22f0cd2890162931d4a200ba1e8490bbae0b521ff93bbaad8ed3ae62d7246205f92f8a7180492c398f76674a1a77d4278ee4117c11f001b016dc057c4d8665e7b4608e7726c727356e550a6974a4a0fa77b6677a40ff5683712a24d066d00ec14b2f926ea6b0b01b16f21a28b1ac2bdd05f4c162cfc844fb3ee4a4125e84e0876a77ee05457931550cc6c96673cf9d4526959719170815bbacdc97bd629924ea99731238be3f1c27a6594182f1944af3235ca8ab8ca067a1c6628401b4cbd665457e01c5fb6fed88191b24aa65e08c4bad30e5f9a00857aaaa0092302090ce66cbe192089896a524074c4a4e007e8a466a741417d7fb4f6d85e5c656c9540075258e3e1a0b1483ab482ffab6be449be33d0369c637cc526ee663395e092051e278e6aafc2e70f707017e85ab8dfb292a0d20eab39a773a429cce65a7f236612f633d79032c88b58af02651a1a05166032a446457fc2c8a548a60af745b8d762a1118feed7308af00023ea521d4a78a1e4d44cd266aac096985cea3f490989413b3e9cc047cd2c1e7599a5e3e1f081c647185bd819a9d7764a991e0a04db7a375102c5201527c9d23b242ac5ba5022ce8afcc78fd3a722bdc69119158898e405e68724889d6ee56831c1a2f39e507949a998e9fc3f2640c861841ac7e5ab261b563922109416ea2c4e071b4a1e46bc6c87e03b4e58bce9d7cf40a78407e1f44076f8166dc809a933e219e084126c1acf8a8e14e570383a454d0043c46b5e940540ff1f9de329321dcf7b179ca7adbc33693dab233d5d809332a5047839e50b1f20540d3d4a1908dfc64869937ab9b1a4bb21334826b449db24bc0a85a26183e870c39ce0e38372ca844aad89cec673713461468958b7e24fe3873670eea199eac685e9e64732e6070efe23ab892ce3e8b2053f0c1edbe5a46b1d6d839818047b0f2ae2150b909a3e6cc818c9819e3a156980fc2aebb172ac57a8ced24854550532249d827e798a83916bb4271aa841c5e76b49be014651b59f151092193cce682e1ad237818746724819862494633a96217581bba6a8e1652829ff0c128111d5d5d6b5bdc707ccf09e479e561aede184ac631cc7f19de60babf183cd6e6e3d3a80cbb398c58a147767da3d5e500c956083ced0699a850aada1f7b558c86778d9bc21b02ed4f6beee8a6267244a0e87687713161195d94f6dbf55adb0eb95967880a94c358579d945c521f19f361d68818a8cdf01f0a0f4a125e96f3a984d68c8a8a43cc8bd9c64a1231de791e2754928c088a519921888d460d7c5548e7c9f88e360c8da46e7616865897aa4ef14eaceb7753103103c343358398a4530d8fc86a851999f4e49b30e365044eea61a4e47524198d0f9600d8b10155ee33da006469ab55782c46416195f2a153c264ff1d7dbbb72ca01c26d11aeaa642fedadaf88a7478acca65515ab881719c8200d8559e3a63b96155016b625cb61a09209ab89cb08b444da5e6990f466e286047a72b1073c67d9e5cef88ea2e2c3713f6b1c1bababb9a1f2698e814c6ef0f4bd8aa72a7daeb41364c77831f06720b34574dc550b6b44a3550613c51db1823
+InNoiseE = 9869ddb12180ad1e6aa807a9709803867f57b8a8b7c9d6b2e6d3218f739e565a4064af20a14ea9914a36065df3804c15440d150c66588d6f3ed35828220d005ad2d8e630645a79142b3209fcb6431ffaa1ae85b26d4567abb2b44a096fae483f10173203f31ac4ce5faf521674f1065690a40af86e351e15c2f1f3640c3755cc8bf520548b0ad6b345ea8e0103a46b44c6ae053a82f998ff7c05bd09221793f90ed50d2f7328146755ab9e5943ad8b8f5d59723bb9911cd0734b5bb472bd84b43941cc04715aad31caf56c6e984c13783406fde0d5e00f7c4f1613f882a8bc4c4a145997798994920d20a350fc121051811888e25cca1a1439126008c967985956f59a7f039e68a0363b60113a559de89bfb1e68962a3887de89489b7b6d528b057e707a3da71a5aac31c372afecc9ee8bfc927648147d204b2c824fa36861029e41c9646ee30fe93a1357063045f997d09fa28bec090783def063cead9366d44ed6861537c2da5e28cf0a34024e4201738cb751c8595708a918f0aa79d6276e98c1608e89cf4e9b9a829b49c2341cd0cc81686bc551cb17133ae5185baf1abc2b37fc7cd4ab8cf04d562e29a18355521e1f126c75b625123f180791b65d94bc5f4696e5c06d1e7a49be544dd95e16c978c1ccd63f8aad341ba5b940bde106f49efea1a3e9ee481d0a163bc8b844eeb55eb7ceaf3162686aaa68d1c76b5a461adcb26af2ec714302bde25f203a20068dc3efc8158bab930559e56d4b0ed4d2a5fa6d1d677e262b9164ba9859a97e157ddc190a504f123d56907218a641840b6f55c1fa998693c1412671520a22c02690f9790d2d6c6b67f5e984da48b6e1e91e7affe38a765bd079b4d67a10da7a08ada86166a9aea80e43687a96003de5da1d1bb0018b9712f7b8a2c4af88617f449b4e3ae01f9006ded20f1142afe80f5d4c184d5989c6e24efe182c3258717e0204cd2893e043ffd1d34b59a2445fe56334e7fcb7709de3a41180be7026ab7a08b10179841aba0d34abc35ba1c0edd03e4e857c3a33956d77536718f5124c74814d0bb625a45e52b72336118a0fa382b608a6afcf8c12a8f0ea51a49ba947abbe7b0bef4a729d85364341dc20b46c7a4463cf3a22a928316f5137becc5f33ca2adae99664da189817093d3f58e55f18ddea199ece4fe21c0d8fba94ed76773d2ce5816c60b2e6b5815be238f54d838aecb992ece036de9dc5e74d892fad970a04cf5452fcd9a0c879a8254da8eac188e52dd48e2f983aec7284223139a30a7673d43cb9df86632f1b49bb2d462c20170d0957d52ae1d1a9f1261293492cfca0b671251e1f7977c72c8304090c70a61d7b01e493caa8e112ee4132a26cfa64c8aafe82061916640a69024c8d0da42b5627f8219dc74c537545e9747a9dac3ba160067aec5e45338a2a3e2e8b70d34d9fc596b3183dca4f0ca786d1483e9e17c59ff7f6d42ce8a94c45178d120ba8f5aa458e875b4434f0755985931d5835084478a8a8ed0184b14c5416ee76edb8a6b1822972092118f8c4c371c7ae318023dc536246315ce18d5abf3eb09eed7187bef9396683baf8238a22d1173dc7f2dc7fcd8cab87749c0dbcd1996415ce4fb055b9422c7c75d91aec088865935d235b2b679965839c24d85930499d274175e7954ccb6a69056714088798a2fbe6968ac3676433f50daef6d3ad46f3395d5d89ae455f0d36445b9577f40a9f26417812fdb80d10e1868b4d82225eaefb00081e3bd7d93019af46741b48c6ea1fa056fea89f43339580bc231db095a690e6c3823822d902df97603bcbec34da2e26b2426141ce1db0b9b8b4144a9244151d154683e9f222750e8049537c5262806ba0c41ac836bc13ed6b9c5350da5645994683a81a2fa4a18058d8a60a088cc8134b2809350650945d6478ad641a74db4e7f35ee0b0babd4247dd2b54a24d14a192cadcb898aa9d15672f9815609d2edb5f569b6295e6f17c0dd78bfe54538b7914a5f97ea71da80629311093499c4598d086d4c3471ae0f7d25bbd124653aea4c9be210a025db8d3753691502b0ea01e438b6aa041fc58a0c3c9d5c9819724e61b90cc74804be187555a59ae633e297ff507e96f96ca4c0421cc6b27454ad22859729dc7f4dc47fd132aa75b0d614a0defa674952c0308ad6b3479807f5afbc39ed451ee2b611441d4565a2b25cadd64e950552464775891e57db8842f9cc4a83b8bd526363bbb040fc61291886dbe8892fa71b20c6a29a1b159d8e695836ac8c97eed70448210e253b5a30651929108c1670f4afa10eb8d6252692566ea48a6e01b298c322d824cc59591d4813328da15447e90af6706a5ac42aead65931041c88b984697f11810d0365d0a6e42b2a617a0485b68da600811abe1d806fd975d13e5fe53a28f51250ba0606e3ab3dbdf49894c9c0310957d2819b08864a566866503a8db04f597be9cd721256c74ab736f0868548ad967eee6b0c4c19e03f66bf02d561071b399c54ec5e454664a5d12b2032121aab
+OutPK = a92b2c41ce706bed456c92ba9c5532a9e3d4105a9c5053f9db372c429e2a4f37f86976be5123d98b2803e72f8e68e0cc468ceb4ed04c500a900a8017417ea51ac97cf2bc1d4b11dad2836c7c0f2f12f0c2b3ee6b78e12a313c406f90420b32ffb4ac56cf9c4b83ec5848a3d289dc783983a0165585d20141cf3ab2ca4193c4c903c033ce7feac95ad34ec9815a4b0662087c97b78305e551ea630195d74b2bcd824908b843de40415c9d580445f009c98b6cb56f091343a7a18b2fccafb362730bf1f139a94012c7216c825899655b4002654e53444be1426d5f85e4410ee16861cc9787a34d3667c19af379aa657683af1691d22dd42e2bfb377e88992c68f1ed90bcbae6a0fbb8c13b9ce2e9830d414b67537ed737b6af1844a7d93d71000402935082f00d168dbd9966be19e128d01b61fe3e86c5d05b7b09a3de0afd7017942df88da1d551213eb36ec1fb97447789691d904786321300049bac6867d6db9dca622aaf1722f706b822a0470b1769efe5bb7ca755b1c29678bf5492d7556029ff5814e8bb10b56ace0fb075c47f1a600a40b8b1bb4d6c822048e50faa67fa152df251039e2f72da3180546ed88420889d63a58e498a18a79f9ae325f4da9f4a195c61e67c671c54b4121eaa3e75428c32c19980e329b978e32981c9a36413612cb50e0c95b31ba10826108db55c1d975f4269d41eb534e80af196630146192150a3af2d627ed05310a4b110bbc230c26735bb14e7328423ce25158813fbe84d82510a5ab536182e1b4d46d361613920e96397b5425a7de3342b80b0b34ece5aa63f79370d29f54203559ecacf3aa27f40a33a1b26462bfc3e621b7e903b3e04b1648fd6ae5881061e02c0ab610930e7b2a89ef22e3042b6168a647d17c49ef4eada957c136886fe4d1319611a7131eaadbfe6b420b999128f8998464e5627a0a288c3f3e5457ceedf656904984c2f043104b9822ee939884fa043da0e4aa8d81596151143993208a47318cae39eba6bffe5a5940536052e497695258820a2dd836a680d4ad550e49bea5c229a2736080a0ca2ad69bc94e66c016c51b1b906bea269c8b9523c94154992d6698894a06143dbb5adfc9c881010b7490178a3854e09aec566d35a71d4f920740149fc36564a028dc4d2985f2648a2990b699f0505ebd0a13a7c696960e542842db439cbe1ca2409dc605def6d7064f563f8e51f4270911ff8806273d9b2ac3549b0c638f99e60c5c9d8a20d294796bb147e6695af4be69331597ad656c0f4474e7a73cac1808e3c0552148474eb250e4cd87a463716173366ede98e0e6ff7514cd6cad20ad72b7cf9507d16f828d505da4103f3c8a94555e8bf18df0a3423ea1cd945f29373144b062f489877d84c0d9f0335bb1c8bdfc5f008c4366d8a2cc1a860715c4113fe48ca9e368d952a4496ada4096cf7b621793bfc2ea4a728b256ad0f2386cb5a0598250c510b8551ae5fe4cb9ed868a7eb3d4bd4cd686e64072a5852743816bd12eba1b7bca8fdd90b0633f302fc534cba923b469e854179a852835cf771cd3d23a5a0d5b4904e46ccbc1b39f6728da4f702a21638d46d566532395366211c3a88bc226acb54e1b8a936fd67cd94e6e620f5ec0e2abd2803a25f72106b7d84dfec6077a012371f0d66a2ec6e92e08f8407b41c95e3a7736887ee32e3ca43e4c9ee1f1c59b433768c01e58f22242ed5455ac8fb6522d262c9d26817f10a59b3cf32d2e57a539181d41778e41cd445a811876249448059536965b39c953dc737d632fe18a1cb2d2641e3dd0b67c6e40ec002f005dcfc0634698a818cb2bcfca6f2058b0a1c37e5083231fa9d3ce886306bfd9e2fe01a919c69ad0fa134b399ca86b4a93772d30e305d426819d7f984e10b05aa3fa49612c65e89f0310d4d60c5f67b8672ffea26c76f8a31639bf56360396e11c17cd192a01d7e579ef0b9b2797780efe1487e7bb66bd1f60bce073b212bb1429a246761366900eab92662ddc2fd99786a45a688db084118deca7586663dc50c45d8f6e88560a01cb5e55c289d5e3095d71a75b74975a3757d680092e29abcbc3d19454ff07bd5b92221b087c4154f21c39280acb0a5268345b541fda116ad9f87ecee717089802aa2ae6f0ae4371a08ae7bc2cf30309ece8659ee2c59fea41411c34c19340d05a89711d2776648a695e8e63ae20bb7e3eb4bf2047a3d8528f9baa9050b818ca2fdca1b5c035a87f7be3e34d5aec5d8363f0554fbe8aaad471c441a5346a5879bd968b6fbcd7cec07a133a00cbe5be0de2a213cb785a5f728ceeaa4b85d6fa8421c7539a0ec430a9982bc9554808162282543d2b6a5c9374c41b086eff61a5a05843a5cc884888b6475b0729193d5be8679f60ac14468381f5e41a7917d2628b0740f9934815b58195f6ff3c0bfd0013324b18a98796ada66d2457af69c51669fd9fa5e3d2180b0c915b4bedbd18de7fe04aac453d1e875ad83d325ed74a578857bd60758885193814092abf83088ea5ccc83753532
+
+InPK = a92b2c41ce706bed456c92ba9c5532a9e3d4105a9c5053f9db372c429e2a4f37f86976be5123d98b2803e72f8e68e0cc468ceb4ed04c500a900a8017417ea51ac97cf2bc1d4b11dad2836c7c0f2f12f0c2b3ee6b78e12a313c406f90420b32ffb4ac56cf9c4b83ec5848a3d289dc783983a0165585d20141cf3ab2ca4193c4c903c033ce7feac95ad34ec9815a4b0662087c97b78305e551ea630195d74b2bcd824908b843de40415c9d580445f009c98b6cb56f091343a7a18b2fccafb362730bf1f139a94012c7216c825899655b4002654e53444be1426d5f85e4410ee16861cc9787a34d3667c19af379aa657683af1691d22dd42e2bfb377e88992c68f1ed90bcbae6a0fbb8c13b9ce2e9830d414b67537ed737b6af1844a7d93d71000402935082f00d168dbd9966be19e128d01b61fe3e86c5d05b7b09a3de0afd7017942df88da1d551213eb36ec1fb97447789691d904786321300049bac6867d6db9dca622aaf1722f706b822a0470b1769efe5bb7ca755b1c29678bf5492d7556029ff5814e8bb10b56ace0fb075c47f1a600a40b8b1bb4d6c822048e50faa67fa152df251039e2f72da3180546ed88420889d63a58e498a18a79f9ae325f4da9f4a195c61e67c671c54b4121eaa3e75428c32c19980e329b978e32981c9a36413612cb50e0c95b31ba10826108db55c1d975f4269d41eb534e80af196630146192150a3af2d627ed05310a4b110bbc230c26735bb14e7328423ce25158813fbe84d82510a5ab536182e1b4d46d361613920e96397b5425a7de3342b80b0b34ece5aa63f79370d29f54203559ecacf3aa27f40a33a1b26462bfc3e621b7e903b3e04b1648fd6ae5881061e02c0ab610930e7b2a89ef22e3042b6168a647d17c49ef4eada957c136886fe4d1319611a7131eaadbfe6b420b999128f8998464e5627a0a288c3f3e5457ceedf656904984c2f043104b9822ee939884fa043da0e4aa8d81596151143993208a47318cae39eba6bffe5a5940536052e497695258820a2dd836a680d4ad550e49bea5c229a2736080a0ca2ad69bc94e66c016c51b1b906bea269c8b9523c94154992d6698894a06143dbb5adfc9c881010b7490178a3854e09aec566d35a71d4f920740149fc36564a028dc4d2985f2648a2990b699f0505ebd0a13a7c696960e542842db439cbe1ca2409dc605def6d7064f563f8e51f4270911ff8806273d9b2ac3549b0c638f99e60c5c9d8a20d294796bb147e6695af4be69331597ad656c0f4474e7a73cac1808e3c0552148474eb250e4cd87a463716173366ede98e0e6ff7514cd6cad20ad72b7cf9507d16f828d505da4103f3c8a94555e8bf18df0a3423ea1cd945f29373144b062f489877d84c0d9f0335bb1c8bdfc5f008c4366d8a2cc1a860715c4113fe48ca9e368d952a4496ada4096cf7b621793bfc2ea4a728b256ad0f2386cb5a0598250c510b8551ae5fe4cb9ed868a7eb3d4bd4cd686e64072a5852743816bd12eba1b7bca8fdd90b0633f302fc534cba923b469e854179a852835cf771cd3d23a5a0d5b4904e46ccbc1b39f6728da4f702a21638d46d566532395366211c3a88bc226acb54e1b8a936fd67cd94e6e620f5ec0e2abd2803a25f72106b7d84dfec6077a012371f0d66a2ec6e92e08f8407b41c95e3a7736887ee32e3ca43e4c9ee1f1c59b433768c01e58f22242ed5455ac8fb6522d262c9d26817f10a59b3cf32d2e57a539181d41778e41cd445a811876249448059536965b39c953dc737d632fe18a1cb2d2641e3dd0b67c6e40ec002f005dcfc0634698a818cb2bcfca6f2058b0a1c37e5083231fa9d3ce886306bfd9e2fe01a919c69ad0fa134b399ca86b4a93772d30e305d426819d7f984e10b05aa3fa49612c65e89f0310d4d60c5f67b8672ffea26c76f8a31639bf56360396e11c17cd192a01d7e579ef0b9b2797780efe1487e7bb66bd1f60bce073b212bb1429a246761366900eab92662ddc2fd99786a45a688db084118deca7586663dc50c45d8f6e88560a01cb5e55c289d5e3095d71a75b74975a3757d680092e29abcbc3d19454ff07bd5b92221b087c4154f21c39280acb0a5268345b541fda116ad9f87ecee717089802aa2ae6f0ae4371a08ae7bc2cf30309ece8659ee2c59fea41411c34c19340d05a89711d2776648a695e8e63ae20bb7e3eb4bf2047a3d8528f9baa9050b818ca2fdca1b5c035a87f7be3e34d5aec5d8363f0554fbe8aaad471c441a5346a5879bd968b6fbcd7cec07a133a00cbe5be0de2a213cb785a5f728ceeaa4b85d6fa8421c7539a0ec430a9982bc9554808162282543d2b6a5c9374c41b086eff61a5a05843a5cc884888b6475b0729193d5be8679f60ac14468381f5e41a7917d2628b0740f9934815b58195f6ff3c0bfd0013324b18a98796ada66d2457af69c51669fd9fa5e3d2180b0c915b4bedbd18de7fe04aac453d1e875ad83d325ed74a578857bd60758885193814092abf83088ea5ccc83753532
+InA = 8f0774d3d5350bd8a9f1567b6408f044018892f845055d532885b240f813fb98007cb69e66716bc3e67f69d0331b21c613b367dc3263689b62a8b38b02846af41cfd8633f41b89aa2a7353c587b0d6b38a4ae8ad3ae2b279f340239296bea34b2d6a7048e1e38f98a6f3087ec2e24d9ff11a21e1f7b0a01e00e6b1a85c8e9c9fd986177153f76cc8b317ad0df744cf8498f01b7284038a91106217e511a0cf20ae7c5203e0ef196a552877585ad94c3b277e8b5edda7e2cef1455a066e09ef92365f19bc4c86044486498f6f4783667f72431283644708d03b534dda98dcae6692404fd49cad29b10115790de190f7eba815d93265deaf17f7d14651f8962e28394cae148d86181f7a81a941d1161198ab9d0fafa01525a043d6def1321ead41007fcafbd1243a1629d31e06776b1ba67a1bce2cd4cab1062b59877fda306afa8103adc95780c7f44b1b25ad03ff3d669d2ed2c42b46bb739ec5920d3e1f046469bb5c8d178c6caa73b82857ea5934fb87fa994c08a88291c2937129ade1e8f1a40899df5952ccbb2506b9e57796a26e999e2bdc966ec2aa89c4b8a85c15493a198472a857602f16cca5189ba0a303c6163a63d0ab94634512172c8d56a7917644937ab8a3a889f113a9738beea09f8fb2581e410689a626d38b2a3747d6873748b0a21040c8942e0e289f42dd812c298a23a5e7724f3d33cd619b82830e411d10fb9474dd95162587ab0d81a28d698e1a79e50b624f236b713a703bc46ff245387dab0a6bb77b0e0e885e7851aeac70e84b6d4a2e24bb6f9900d803d513b3ece9da5d495a18d09f61c3b50876967213f2cd4784044e5bdb3544fbacb01242e86ab0e4407bedd1ba31de696414b8a03ed07e227282602f9175a73e3698d696b54616b46b7caa419b870487f2e0869bb311398fd548897aba4a8a04f8d9b0152fb414c9a8333a48e1d7a19a7c864df42dde180148441b274beaeab25cd7cdaa5b3e369e0c16d1c8f20e2b8e5b1e70298e98651dd965a7a858a31f87c4da9a6c1dc20e025ad45f1f6b6372d99866b700d047d845b4b40563d039463bdd4e3e3150ec4aee0646b635aebf064ca1e9e7ee2483e46028a316989adf7483c160a08dafbec43aec6da81950a057fa20eb8046b9cccdb42c5e1938e7766c6f653948d1102cb399c5856fd91e1f667b27d205378f1aac0b83356cef589e5282300d8becfb547c7c297eef0c97335e1bc08869b78d46b6771f060b99b837dbee82b874a871cfe16937a4f07ed01815d7aec5664e13e755bd2c3df61f43f7c2b26e6610f5a9cc44a84c21015a06b0a72c22c68aa4493ea6d62f6258ad8e5ae1effa32c87f49431fd34c76995f85bccaa0e091231bafe3b614a0a881b1cb959427dbd3afcb9e4294c6e35d67902a908c1c42936aa258ca60953a9f4928f0820ac9f00d3c72c07bc11fc0954c0a72abbc3962a287da87ac994c1acd4aba4eda401c232c3a125814af2e2e031699bc0d600fa651f2484b1d7db75e22089492c574536e774a15c8fbb8d59164cda93b4066448da3fabbb7f52b8d6536cbea0474d6987f05c9e0296420c50a33ea26be27dc309b9201d5aa518586f58139136d7084585a3b2dc3c6b9895a0f5e468a4b00b0b52d98c147c641a2a334e45abc4289cc7f572324ba5be314e3e655b7a6ce63eb6ae217fb6f67cbb308350e91c48a88eaac9b24e8b35c05566d0e4cb2c1965b6a14593a1d245295aef119a57549fc4e86086badb512ac46d93ad0984fab1e8112a44a60a16e7051e00c630bf79042ad61a45147b1d7a531aa1c9c9bcd708ca12273daae848d990ecc46c228ad162e69302db52a008aea235a10af962b6b052c683b0d814fc74d4807076b8a0050789fa7569604a34d20b4e67aa5e6956e018b6e8696fe28f9649aa210a54d9c8c7c92b2be83a514a1a6f4e03bc721b180099cb14ccd66e812f97205a7310867f5348e6841309e8a7c2bc8fda8e336589d900813046aa96513a35086bd04745b4390ec2c7d981cf752df3578954751dab2265820ece73745903bb681cbe68f52a9f4cc7c30fab8380094df1296a1af88296b55b2a9b90dcf6a0aa8525f005706908b119727004570fb446a5a634ee44cd28e39cb53f707c9992baa7437f74d938e280a0bf29a40080da8d4798141d6a79c33d83e9b6fa01286d3920a1f5450b1c46241370533b1c5701e4f6a4ad720b208d7e567badc725c1e1364b597f03c4ddc1cc33d251d99a69ed744e04e5a2b8471c0a892fb67e0f75368b35f59c6aa6e9557f15b2cf78120a8575ffde653c968949254113406b4e5220833200c81c3013cea24983bffdeecb0f294041de340975c329b3dc9bda0a9562e436efc1b6c707c522a23c99e602bf103a01b5ea4029319f696a2919ab5c2c29a5caa59750c8ff424288e160cc02286f2ab68ac098ae8e59225c8b3579880486cab2da4e87d10348f5d97bdf20b791b60fb43d06bd88c3153c17819feef2c19df7d2cfbd4b74adcc61c370a16fa1521a2
+InNoiseSP = 564eafbabe3db55e87c419bd7551d0e63228ed9c3ae2a107b7c02614350eec332d19a20f061f879a646868168999eaa9124a058f1565f8710c9669248a15abbe8b7631eb697ceb9b28a4d4359de12975c82ce417e389bde1f08a7960539e066d0288f8989d420a72040e44774bd64a3f0d0ed777e265520c1f75931eee184991718af619b1b62935f43e149068133458595e87e0a273a171714a1b9e8672fa8245fe8b430aa068ac93ef4da0ee1d88b65b3823f7721fca56771082dd0be86f4e811b7c4a838af224aae56534cacc3446d94450002f48ad0e7c4c543810677a937962ab26a2280f14548f7aff393e1a42ae25b56c941a4e7cb600d14dffe440a1d2de6a9027ed965521abd5dc26e25d729dc598e3c14924a29a2335e9fb3533de04e738edbd67096e0198635d3ca644a828753551c622a56acbe272ba06f4b409d922b68782d681d0501cca4f11351674cd6f2a2b06b116c994a123acc65e92e8c96406d8255f538768cb4e74af43a6e8db3da540da3c865a8d2c14e86852c3c97c26af554a609e184b1fe391861c73e4eda477288c1ca94043058236a668989d28a37629f18ce3754c5100a2ce34048e989e950ca7ab50c18e648a45d0e17a9ab49bd087fc46a8b597d32567a5013c58f4d826589c81c5464b29011e508e8b3ab65658105a5c8931deb5dea38e0190b62b6325523a59f287786fc6560421af46098cd686285103499b050729079154fc3a3250a6e859a1b3da1e291d86fc21db496df445d601c3b44a3346a1413280857ca1ff37d75aac5ddb99030a0998de562b4b580905b691f6f481d004be0bd233d28d36f253d1f65b05ab0e631fb661cd5fcc080e76a65160c02ddab089b6400dad4b2a8dc8763c15b9da59c640aaa31f168c657892e2e4816c5c51e80efef47f020991836306c40666e456c441548923ea44097171a19e199f8d2274887c4b54e4808ec5059ed786668245045e2baa1323927b5e5f8749fc668459a4daca0d8e81245b1eea482161dd8f488a6c8d71b88c2d23c0583fee4b3be04cfa344ced844afb41551013c73434fa739d4f0a82249080ed522f51663509585b6174905d5f0042635bfdc912a2e8f5a6efe99d67ea4d965c245507a560b3f2669817d4ee17019aa3d8171bd6304998531b0d706c1537cc2c1e0800e2b3558a12c7d019997a551009d3b12ac9dfb4b61aa2453609d787fb1a7f499db013b44089bbca19885602ae5c5d534aa1013e776b3bd76e9091fdcdc68bf15c65aaa284090dcd7ae9a634c8638a4d64688e7b144c2570858c17039d3b2d82c21714349bed5f1a5701511e79cae191e195a7b09a32999d2cb4291c4eda7c1da06d0985dad801a779613458756ebeaaa695f143d1a50da35e6b69b48f466cb479eed6154ca6ab5a5288932a8f8f62ab46238b97e0a14af0232144a0fa09444ac98b9700ebc819e86fc8b0092cbe5f2b0f60d6a1288f431d606c698d65c465850375634e01b6ab7b369d122874528136bdf8825ce63a621f056c12f00904a108400281da06824b8c5c1468f4931a2988db371620c7ebec23790c997beff4c90fa128459c8da6ddc802b10529b6305c6c41ca245abc65266e44bc4952e2adc7caa35607b20a8f1d0ee26c607e48224f22e36d68af19054115fc23741a28257a5d1ca88450867d7e752aea190357697beb4bcbc3f736924659d680681dac4d08cb8478ba76bdceb99a4864ad8b488b87d238bfd02c529834be431642371199d479b0c5f83b4f8196cc109d3a7292315fdb896992b52287cb61b8d28cadf1a44e58d0d25d5b0f084a3052408b4adf15acf6aacd47021431d9450c1dde8b98820fdd2c78aac94d0e36ef16328c3470552fa558c02693fe1c3135c4457e252f412a18ba0aec007a772de963762ce3a01b04bcf52e85b9cf121931c945ea126910001909f5e5e6b5c61aa7f456c5338a5999a33f216b1dafe3f0b74a74936274d9318906b56d609b295d0a73a10b05642272d954bc3370bd5a85a63962b551039bcbb4866b8e77e1dbb7fa336937eb9e18f6d5c0a5a927aea4b0bc7e736425e79772a0b90292f7495e48986f0543f5b97bca41b405a3fa47c8de3f2791adad8bdb4958da55351e91e6c4703d8d4f843435a9ce2d3dcb47278cc8826e567a314f94ab0a836570e7697d822857aa584818c822b858955e8aa0a51ae64a56865dce4e65032e76e0c0f610836d7d1752169bd59eba0fd206850ead8cb71afb671ad4304991b0f3e0640432e6b1251bfa9f5a9f71672d21790093d902c39d33081405d2156e1fd78ca1b3765c67d0c0e4aad4ad6731e7b6c79ea0456e6e7c1b8709405a21f0c9b5f83c405bf3d1631e8c6093b7591e71244b9212d980c4084ba73a4451f43089c8de175f344fb6691a06f54a5d2cc0b4d43321b0728b8e98bc5d0470104f06ad4819e1492fc922c42575a99ae6588e89c1ef6825e4582f4b6e548b1532236e10345b63e4743c078ec1c5ce0aca1125cb42841968654d9277c521
+InNoiseEP = 1a6aea83846d6c49937f55ec5c228e41f5b31ca182ebc7bc872b9a54c55b088a774624ffe5c5e8b635272509daa7d4a43d628154aa1d9c9c62e7b2d5762d1436ac97db5cbe8afc18bc34c77d0713e553420c5c9811cdfe131c66b9e0867b39ea85a45b420b533342a13d4b94d11aaa02c9596067e1b25ae6193224e5be04538787423996bc6b55c1232da1724ad9b8d6056070e64bf1fac64db54e0ba7532fcd62cd82260afba990b6a7b40b03949fc7ea51082b8143c9e1800893b24544419ca26b228c64690b3550a825e196d2b348fe6ed39c814a9bd67c51519b7905b28f69915d292ff8ae3aca98e85c466cac501e3b9be5478a6c29e3d7bcbb7626cce6e7b29296c727255d90389a9f8e86995142cf54104a60d1a7f46cddb342366e06ac308afbb9ab76a8ff2624725a9bac3f7808217547093a73f8e698834338330bbe06b3cc60621795573167e6eb0f7d38e85b34c73d96900c85b414598463051397b506c8afa6ac54126906265bedaf23654dbca883935b0ae2093b2a4579e01917ca8ddac676622a04a3a605ceadb8f8dad6c7c33e6c9ec5fa89f1ae7279056c4504a039cba1b1e1efc5506951be573131054a688fd80ab0186bdd53c98d2116d61a9eb85b6a03c34ca4265196762f0f82cb7504896aedfd4191b96ac2a8f372a14d820d644773c204799417f67b34f522a6228f562ab84262564e12c2f875d464d05757ba3058416d21bf06627e59b3e5339e45fb436ee8131e82314ef3e2ec7920dbca8ba0a8d249ea5ad75443792ea550f63068c551db89d007306155ea80b016e8342b23660e950671107fd2faa8fc91631eea713a79a017895a70161be146d2d0517091bc3c208a06eb4131b44eabfcb3cd2a1df482d2a81c896551815b11f38d420edbebf5335c25aadd4e552fed05135b2fb24c4655b76006d097dca7e545385a9f9096b64802b1ccb9ae515c7f7bc6385327d5fdd8a29595c1855387c60d1a920888656551b52e91a335ecfc5c3d4dda55270a0ead48aaf03092514f8ba4f6eae5a4c1d38287d235a9cb50cb24518a972eda50d29fb085b98c25f950741bdc6a3853792d27a5a389a1bdc65772832a43eddd12524db26136eaaf5c9aceb1a25993cd42e249e7644979c0afab6a08047766b365bc3e5af585d7241b125ca81aefd9c1ec9ead98b9f0634825590eb132fd10af74d386e227000006efc1b8951862d242205005f5513cca5e17acb614e282bde9ee4c0fd66c76a8cb0d68a9cb49276c9459696c1c230fc2b5d7dafa9789298981df45b1712675d46967f6f4c01fdec92702d3886ff58027fa6d32a99bdf1c86dbdc17945fac98e3c19beac43c959c3967295c0a7a0df1b2362be267623434749ba64abea437529876b7a27073fa1478a037d46b4c0f0b082bd4b1650099550d494d88658199bfe969acd45122731d9f2d4500372ae9183fa547ab22ba4cfdd70634d729a868d78642826e04551936c092c4194ad59ca070ca195c662dd7bef43141e09659dc7db71e1d15f07176b3a258efd331199ee0693645e4348785c55908df197aed0fa0a2d8b0aab351505afada2fc456fa7aa4c23ba6805e7439707ac0167bf61c017fc88866d334bc4259c014daddd423a6004291a9883d889187da474dad31552d1a82412fc2dac9246932b5cd4f2724db50aabbe5146388985156248e92ab9e9807d796d590b40ac3543035191c4597001fa8c1fa1d66a8be47126998b611bcf8298a9fa686c9e42b4407ff20002a97306ebf90f14bd294867425d5dae0c15cc1af3b86cc3057c4a2665634525a1b1753b2ebeda0f9d95052d02d05818d44f3fcf98508e9c40afa08ab4e453cb34991431219f6c2e8b5161acae5fa88497f414701b9f8f06ab8cb49db7a628c47af05215ef6b349cede61083ab3ec22184987547a085cc620cf086dc2dd3f2bf2484fd09af93ae304b06c274e839dbc5e23cb6fc23cdc4a021e9ba355006202e890e0d4d03b15e501969168a0e04fc87526bda835ac44f04875434fe8bf9b63c52fc15406d0a6fe466cc6fd640b5241bd91f8eba1c401745ff085393e09e4ae80b4e95d33f2ea5832bac91f135757b28e0267f283b71430216ca52c2793d776bfa89e5ad10cd808fb898bd90f6e21d36680e74b7a747653301a5f14a24b17abb120b28a9f5331c96c1e89bc1192e9786c336a2fe654be988080d4a1e5800053066bf260fa391a1def437243ce6be582bf022724152f41f5fa2eb53352a07aea4f8c4cb7a0d9f3d3215d6aa3b971ce846228d757f3933a30cae35f88c125a80bedea69b44940a59d1080c78285b1d73954a3b63403d4ad7649bcbbed067622eeaaac36937570fe15021cd893d7d6929adcc5f378bca09daf2b2de09d4a1f9f83d556f9122895628bc41d25bef96e7835ad21bbdae1bfc775821dc66e0494f6f86c5b6bd2317ec53533c238a4fcb81d33875530128192eb8fd63755d92b74d03da66ded0dd5c617050e2554fce83f3a492954ad2125837dba00
+InNoiseEPP = 000000ecff0600fd6fffcbff02c00300ff5b00f8bf058000000000c00180000000f8bf04c000e0fff6bf018000400000c0fcefff4b00040005c0ff0b000300010001400004000180001000080004800020000000fe6f00400000000100005c00f8bf0300fffbff0200fe6f0020000000feaf003000f4bf0000006000f8bf00000030000000ff6fff0b00ffbffe2f00500014000070ff1b00080001000010000000fe2f001c00f0bffdefff0b000000fc2f00e0ff0e00010001f0ff0e000070003000f8bffbefff0b000f00fe6f003000140003c0fe2b00f0bf0080fe1b00100002c0ff1b001400010000fcff0200ff6fff4b00fcbf00b0000000f4bf02400010000800feaf00100000c000f000300000000040000000f7bf014000f0fffebf0600010000f8bf007000e0ff02c0fdafff3b00f8bffe2f000000f8bf0100000c00f4bf05400170ff0a00010000f0ff0200003000000000c0ff2f003c00f4bf028001100000c00300001c000800064000f0ff0a0000f0ff2b00f8bfffef006000000001c0ff0b00f3bf034000f0fff6bf0000ff0b000f0002000000000b000200002c0000c000c0fe0b00000000b0000000fcbf0240ffebff0e0003c0ff3b0004000000000c000000fd6f003000fcbf03400020001000ffeffffbff0a00ff6f00f0ffeebf048000000000c003c0ff2b0000c00440004000fcbf0000002c0000000400002000040000300110000000ff6f000000ffbf0340001000fcbffb2f002c000000fe2f002c000400010000e0fff6bf03c0003000fcbf010000e0ffeebf030001000000000070ffebff0e0001000000000300007000e0ffeebf04c0ff1b000c0004400030000400ffefff0b000c00fd6f0000000c00038000200010000040ff0b00f0bffe6f00400010000100001c00f8bf0680ff0b000c0000400000000c00fe6f001000080003c0fe0b00ecbf01c0001000f8bffc2f00fcff02c000c0ffebff02c00240ff3b001000ff2f0020000400fb2f01d0ffeebf024000300000c001c0ff0b0003c00480fffbff020005c001400000c00600000c0003c0ffef0030000000fc6f00d0ff06000200000c0008000000001c00f8bf050000000003c0ff2f01e0fffabf0140ff1b0000c003c000000003c0f8afff3b000c0003c0002000000002c00030001000fe2f00500000c007c0001000040001c0ff1b000400ff2f000000f8bf0440fffbfffabf030001b0fffebffeef005000f0bf00f0ff1b00ecbf010000d0fff6bf000000ecff0a0000f0ff1b00f8bf0030000c00080005c000200000c0060001d0fffebf05c0ff0b000700fd2fff0b000b000440ff5b001800008000e0fffabf0280004000fcbf000000200000c00380fe2b0004000040fffbff0e00003001500004000340003000140002c0ff0b00ffbf01c0ff2b000400030000fcff020000c0fffbff02c0fd2f00ccff0200044000e0ff0a000180ff1b00000000400030001400fe2f01e0ff0e00fd2fff5b0004000180002000f4bf0380000000f4bf028000c0ff0a00008001f0ff0600fd2f002000000000c0ff0b0000c0003000fcff0600ff2f000c00080003400000000c000030fe0b001700ffafff0b0010000680003000040000b00000000300004001e0ff0a00fd6fff0b00ffbf00300020001800ffafff2b00f8bf0440011000080000b0003000f8bf00f000200008000300ff0b0003c001800010000c00004000400000c0f92f000c00fcbf0200000c00f8bf05c0ffcbff0a00fdef0010001000024000000003c0010000dcfffabf00c0ff0b0008000280004000f8bf068000e0ff0600fa2fff3b00fcbffe6f01f0ffeebf0070ff2b0000c00100001000fcbf014000f0fffebf0180ff5b000800018000f0fffabffc2f00200000c001c0001000fcbf0340ff3b00fcbfffaf00000003c0fe2f0050000400feafff1b00f8bf01800140000c00ffefff2b0000c000f0ffdbfffabf0280ff0b00140002c0fffbfff6bf05c0feebff0a000340ff1b0000c0ffefffbbff0200ff2f000c00fbbf008000100000c002c0ff0b0000c00200001000f8bffc2f000c000b00ff2f011000f0bf03c000300000c0fe6f00e0fffabf02400160000c00010000dcff12000240ff1b0000c0ffeffe9b00f0bff7ef00000000000500003000f8bf0040ff3b000400fc6f01e0ff020002c00000000000fdeffffbfff6bf02000100000b00024000100024000070001000fcbf003000400000c000b0000000f8bfff2f0000001000fe2f000000fbbff9efff0b0000c0ff2f00d0fff2bf007000f0ff12000040001000f8bf003000e0ff0600feefff4b00f0bf000001f0ff02c0ff6fffebff0e00fe2f000000080000b00000000000fe2f01c0ff0600038000f0ff0a00014000f0ff06000140ff0b0003c00200008000f4bf030000c0ff060002c0ff2b00f4bf0070ffbbfff6bf0100013000080002c000200004000300003c0000c0fe6f011000080000c000e0fffabfff2f003c00fcbf
+InRand = 3bec20e879d06c7784727a350e65ef4a75df10bcda185de1bb4e4a6cf8d8e450
+OutPK = e2637b35a9e43a2dd25333c125bb90407b7b1c0c62da269efb13008434d8a8f00d212f6198d693bff0062482ba182ce12bc16520d6928e1d6ea54a870adc94396e2f633e6a9b024f8878c64c8af86164fb6561717369db940d96a1844a7511105271785a8600fd062ec6e3f853a584ae238e7fc948ec1e3b2d1e24a679696eeb4a6a8e3d00f3d4428043b81ca050d3fbd03c036b400cfac70ab179eff09232c40f374991bb53d53f8c930e241105b31391fa9a65142d0c95b88b06c12c7c195296f91246e7687034eca81ad9ad1d47fb6c006e2245ebe8a179531c446976fe39028a06a1cb6451590f9c883095b9d543e36b26bd1506dff3f7eb9d79cad5fc62b106820f544e3688f09a386c07f0a7428892a80620f3da33bf19e595ac79af5d58cbb8b404862fd7b020e564a2551df746dc880b67098df5732eaf139adf20f41c8323c71e378f2e35544c12f446dd8536445a993f25a028cc3e106c9410dd5ed2f5f1acb1a02683e21c357153c056d2e755731f1aaab7dddd9a75cc159377ceb26404efd25e6676d946ec388a4268a1ee7317f209861adf78126f025363c9254839f465fa5e9e37098ebd8f633a16ee310a9d512fa922dd25dce24b364ba24388a72d40eaf13e4f535b61d8007690483f6aef6d4d07819744091a0e4d4a3ac85ae52f04d530a937aa0c81a858d7b38e7a4281ab20f186890d00bf89590650a5de283a37fcb2a4cf85c658f4148e24b478d8225f7e0ee0135c9e39568a6f8292261d856b9c3878741a11ac9d39aba68cb714292943e44aaf5d9d00385425d9407f99ba6a7743e9abd162c80895ea9585b611a205c90b9ad2188e6a903f5554c4a35996ce266a49371a4fecc68660be35055fe1f8797a5f6dce81e22414764c44d3ad981b2eaf415169855ebf5a4de3904227789c58d2a34a0c75e50668dfce4e4f2083a693a607370d5e9a79f943609f94663cf47c94e14d5708346b33ab51c2ba91729206356491cd57afd8ceaa0d3634d3257de0367110f05ab7253c2130989b9575887e0cdc6459f9e3b61d72416242e6c2b02a8ffdb98e5c5f6da8e7a13a7c7276ce47e4bfba1cdb000ce070a4bbed57413ac7e5110682fe86b0c5791644be6a7ce6169bca6bfab174b734918da1ce4a399a903be6e2621ca4a86f90e0bc4750819be2cc4603c4aef178c3865c9d858ce8a1f0519927fff327b906cc6e39a4238da0c7061fc4c8240388acd039ae8e7d68990fc78f5061362361c1e1869762ce6a066d24aa9ea4f8468112072fd16f8b314c5fb4c032725fb6729812fe9bdae138b81aba3abdee0ff740fd9a5ffa18205b3307e53607e90e7894767249ae95a436ab71798e1b5b48f4117cd56e3cf3a4912dae43bc63598a78f2ece536cbbd4320248df43cb845169a01981ffeaa2e9dfc17a8aea8675cecd86e7e9a544bddf12af07652cc4b2610a81871e66eb18e643fcd267f99b731ac72258ac4aa66a41a1cead40450876115119133449e2e5535b008957b7b6682e8271a9b0a4c0b4849fc1fc023ec529d2d6614d7e860587925b1eadb3311c90aa1597af55af1beb62dc01867dc0b932deac47adc91d7c1d93968041a1edeb5808a8883f65f7d11be85b8435d23482c081a9d6d3c5693a05aa66186620ed46a23118552673c96820a6f3bb3aa9e51c3a07b26d497c458ad219c5588f461311bc8bd702309f9b44aba430d81559989140f95982e871d502e02c3f161399a367910d526a2063b4892b507c0611d2d8d6d901e318e92eda13ac2c14ab3a9b13129552c00d529b975c1a8bfa0b55bc77488424af77b97d63fd78d9998158e51a297d286156a99fb6a5112ade63a1085228ba7de53c7c3f2d2131e510002ef92cf4c5a45570e07abc094ba294661e4cd96fcc3a7a1bfba84d1a2c8d0b2d550e20fd963d3100fa9d890540cacbc2babd97b6fc4052dc4d4abf77e6c5b8860219ed1276c9d5c566704a9d19e6f54d8ea63315079839a042ff0520797ce78b1489982c26aaa463b20a2e9ac710cb08473e79bd134416357e5216e3e644b71d7182a121dc0f1463e22aa44cc4f6246016cd1af2d119e82abbeae7b6b1ec05e38acee10fe422051c448a14a71a23a98594258d9525544fe697d752477c5e01922706d2ad10351262a32cf86859a180d7f2185bfe370663c9fe81b419ce52560d9552b95f013b31068eb447c528a48c53bff387575d61dda46a9499a0b0d59602591c31a7a20add950142d82719b08b460270b207e9a03ed91eee0e5d8203e5fa061f8e624195f05a4e4e9376e9dfba02d14325ec2beea8fc0b21e67e8b671d8a194e1f9367ada2c9a096c9a6d5c83ba9344d2d2026138ac89940a946090171fd868310fc29f2996b1046910a754243db02fbec676109fa25de969f3e626646209d38b9b3bf909c4d249e5ae2dbc119d779270aa3e332fa2124506a80f41c323a7e1a9486a0cf5002d1ae09f798670d981dfa07a313a254222a131163d596443ca8697e4990e0fd3c301e45874
+OutRec = 00c00020000400038000100004000300000000080000c000000008000080002000000001800020000800008000000000000040002000040003c00010000c000280002000000000c000000008000200003000080003000010000000020000000004000240002000040002c00020000c00018000100008000340001000040002400030000000034000000000000200002000080000c000000004000000000000080002000000000400034000300004000240003000000001400000000800030000100000000080003000080003c0003000040000c0002000040001c0001000040003400020000c000140003000040001000010000c000000002000040003c0001000000002c000000004000300001000040000c0003000080000c0000000080001800020000000030000100008000340001000040003c00000000c0003c0002000040000c0000000080003c0000000080002800020000400008000000000000300002000000001c0002000040002c00010000400024000300000000380000000040000c00010000c0002c000000000000300003000000000400020000c000040000000040002000000000c0001800010000c000040002000080003400010000c0002800020000c000080002000000002c00010000400018000300004000280000000080003c0003000040002800010000800030000100004000140003000080001000020000c0003c00020000c00020000000004000280000000040000c0000000000002400020000c0001c00020000c0001c0000000080001400010000c00008000000004000280000000040000000020000c0000c0001000040000000020000c0001c00010000000004000300004000280001000040002c00030000800038000000000000280000000080000000030000c000380002000000003400000000c0000c0002000040003800020000c000080002000080000c0002000040001c00010000c0000c00010000400014000300004000000001000080000400000000c0000c000000008000180001000000002000010000c0001c00020000000018000100004000080003000080003c0001000040001c0003000080003c00010000c000140002000040002c00000000800030000300000000000000000040003c000100004000040001000040003c00020000400028000200004000300002000000002c000100004000100003000080001000010000000024000300004000040001000000000c000100000000300001000080001400020000c0002800030000c0002c000000008000180000000080002c00010000c000380003000080003800020000c000040002000000000400030000c000240001000000003800000000c000180001000040000c0002000000000000020000800024000000008000140002000000002400010000400024000100008000180003000080003800000000400014000000000000100000000000001c0002000040003c00030000c000140001000040001800010000c00000000000000000300002000000000400030000c000080002000080003c00020000c000300000000080003c000000000000300003000040000000030000000004000100008000380002000000000c0002000040003800010000c00000000200004000080001000080000800020000c000040001000080003000030000c0002c00020000c0000800010000c000280000000000002c000000000000000001000000002c00020000c000140003000040003c000200008000200000000040000400020000c0001c0002000000003000010000400018000100008000080003000000000c00010000c0002000030000c000000001000080002400010000800000000300000000180002000080002800030000400008000100000000280001000080003000000000c0003000030000c00030000200004000380000000000001800000000c00004000300004000040002000080003c00020000c000040003000000000800000000800014000300000000180001000040002000020000c0002c0000000080000800000000800010000000000000100000000000003c00020000c00030000200000000140003000040001800000000c0002c000200000000040002000040001800030000c000340001000000000800030000400008000300004000340001000080000000030000c0000000030000c0000000030000c0000c000100008000040002000080003c000200004000140001000040002c0001000000000c0000000000003c000200008000280000000080002c0002000040001c00020000c000000003000040002400020000c000240002000000003c000300000000300003000040000000020000400018000100000000380001000000002c000000008000300003000040002c000300000000340001000080001c0001000000003800000000c0001c0002000040000c000100000000040002000080003000030000c00
+Key = 489c79a48135995c4c8cdeec1777a79cc68bfa7b167f21a25e92945b4004634f
+
+InNoiseS = ad9613f7d3f429e39015b40b84b0b0913ec1c4208c24d4573b1e0e5cafc5c2e3304c02271d1271721028f125e6974c6682ea15cea2cbe61cd1c03c601a708e42401ffa6cdd6bdfc925b9e520914a5902162f2db0a42b389894122e95cb5b12393642bee7c43bcd394449a938e73625985fdd9897355e13a453e073ad38438fe88738627c7ca3d39137a8e996630b1644a01c0cc5ad8c7ba79da067693c0080bdbdfdae94a5622587c4635fe319f439c7805e194b785fb65e1ce58d446e131206b025d98e60d10a1afd716e79103863382943964362c19c48a3aed93dc2aedaa4945a3d47a07ab585c3b7e377edaaaf8e4552ec3cb049c66ce1a7d9157dd552a63008a3ea6ff2026505788d18bc0152181b7b52489864aa4306eece17e366a9a822ad131059258665298515f1b8b691e490c9190ae668b2e6aaae8633a9f4b1d1a1015009c041b50e55d0d3d19066108e58c3ba80a67213c851687b6494a5235c7810718aafd10b7295810284592327f2b37ab9cd89eb80b3a81130e3a604796d95b3eede92df111d7264d21483851394002743f9fe13555f35250499421f189a1b35a92a2d2eec18e03183042e9ee7eaa15b9c11f17b4009a33960f9d628a225ab1c2557f8dca1dec00f82f80437c10a09f04fc52d3b8f95c19d86603bd6be368d427f274d3946d0221240cf76f4c4bc86b963f1e72fdeaa7eda6a382b41ba210eec4bd0a48b509dae0455a4381e6ec80226920a7fc67649fe4017b26407624bfa60da5c47559f248793eb4dd1216665201762d3b64c4782cf1175ff2eab9c6868b764d27a8f29e882beee78db130563114a1c8d91f125748ea0cfe56361aaa55b8d45a507754d332b8e9c252728b103aa48c1d5243c8e9e9a9879564f61cc2bb8cb3cbec982167859524f78cb374bb95056505acd22f0cd2890162931d4a200ba1e8490bbae0b521ff93bbaad8ed3ae62d7246205f92f8a7180492c398f76674a1a77d4278ee4117c11f001b016dc057c4d8665e7b4608e7726c727356e550a6974a4a0fa77b6677a40ff5683712a24d066d00ec14b2f926ea6b0b01b16f21a28b1ac2bdd05f4c162cfc844fb3ee4a4125e84e0876a77ee05457931550cc6c96673cf9d4526959719170815bbacdc97bd629924ea99731238be3f1c27a6594182f1944af3235ca8ab8ca067a1c6628401b4cbd665457e01c5fb6fed88191b24aa65e08c4bad30e5f9a00857aaaa0092302090ce66cbe192089896a524074c4a4e007e8a466a741417d7fb4f6d85e5c656c9540075258e3e1a0b1483ab482ffab6be449be33d0369c637cc526ee663395e092051e278e6aafc2e70f707017e85ab8dfb292a0d20eab39a773a429cce65a7f236612f633d79032c88b58af02651a1a05166032a446457fc2c8a548a60af745b8d762a1118feed7308af00023ea521d4a78a1e4d44cd266aac096985cea3f490989413b3e9cc047cd2c1e7599a5e3e1f081c647185bd819a9d7764a991e0a04db7a375102c5201527c9d23b242ac5ba5022ce8afcc78fd3a722bdc69119158898e405e68724889d6ee56831c1a2f39e507949a998e9fc3f2640c861841ac7e5ab261b563922109416ea2c4e071b4a1e46bc6c87e03b4e58bce9d7cf40a78407e1f44076f8166dc809a933e219e084126c1acf8a8e14e570383a454d0043c46b5e940540ff1f9de329321dcf7b179ca7adbc33693dab233d5d809332a5047839e50b1f20540d3d4a1908dfc64869937ab9b1a4bb21334826b449db24bc0a85a26183e870c39ce0e38372ca844aad89cec673713461468958b7e24fe3873670eea199eac685e9e64732e6070efe23ab892ce3e8b2053f0c1edbe5a46b1d6d839818047b0f2ae2150b909a3e6cc818c9819e3a156980fc2aebb172ac57a8ced24854550532249d827e798a83916bb4271aa841c5e76b49be014651b59f151092193cce682e1ad237818746724819862494633a96217581bba6a8e1652829ff0c128111d5d5d6b5bdc707ccf09e479e561aede184ac631cc7f19de60babf183cd6e6e3d3a80cbb398c58a147767da3d5e500c956083ced0699a850aada1f7b558c86778d9bc21b02ed4f6beee8a6267244a0e87687713161195d94f6dbf55adb0eb95967880a94c358579d945c521f19f361d68818a8cdf01f0a0f4a125e96f3a984d68c8a8a43cc8bd9c64a1231de791e2754928c088a519921888d460d7c5548e7c9f88e360c8da46e7616865897aa4ef14eaceb7753103103c343358398a4530d8fc86a851999f4e49b30e365044eea61a4e47524198d0f9600d8b10155ee33da006469ab55782c46416195f2a153c264ff1d7dbbb72ca01c26d11aeaa642fedadaf88a7478acca65515ab881719c8200d8559e3a63b96155016b625cb61a09209ab89cb08b444da5e6990f466e286047a72b1073c67d9e5cef88ea2e2c3713f6b1c1bababb9a1f2698e814c6ef0f4bd8aa72a7daeb41364c77831f06720b34574dc550b6b44a3550613c51db1823
+InPK = e2637b35a9e43a2dd25333c125bb90407b7b1c0c62da269efb13008434d8a8f00d212f6198d693bff0062482ba182ce12bc16520d6928e1d6ea54a870adc94396e2f633e6a9b024f8878c64c8af86164fb6561717369db940d96a1844a7511105271785a8600fd062ec6e3f853a584ae238e7fc948ec1e3b2d1e24a679696eeb4a6a8e3d00f3d4428043b81ca050d3fbd03c036b400cfac70ab179eff09232c40f374991bb53d53f8c930e241105b31391fa9a65142d0c95b88b06c12c7c195296f91246e7687034eca81ad9ad1d47fb6c006e2245ebe8a179531c446976fe39028a06a1cb6451590f9c883095b9d543e36b26bd1506dff3f7eb9d79cad5fc62b106820f544e3688f09a386c07f0a7428892a80620f3da33bf19e595ac79af5d58cbb8b404862fd7b020e564a2551df746dc880b67098df5732eaf139adf20f41c8323c71e378f2e35544c12f446dd8536445a993f25a028cc3e106c9410dd5ed2f5f1acb1a02683e21c357153c056d2e755731f1aaab7dddd9a75cc159377ceb26404efd25e6676d946ec388a4268a1ee7317f209861adf78126f025363c9254839f465fa5e9e37098ebd8f633a16ee310a9d512fa922dd25dce24b364ba24388a72d40eaf13e4f535b61d8007690483f6aef6d4d07819744091a0e4d4a3ac85ae52f04d530a937aa0c81a858d7b38e7a4281ab20f186890d00bf89590650a5de283a37fcb2a4cf85c658f4148e24b478d8225f7e0ee0135c9e39568a6f8292261d856b9c3878741a11ac9d39aba68cb714292943e44aaf5d9d00385425d9407f99ba6a7743e9abd162c80895ea9585b611a205c90b9ad2188e6a903f5554c4a35996ce266a49371a4fecc68660be35055fe1f8797a5f6dce81e22414764c44d3ad981b2eaf415169855ebf5a4de3904227789c58d2a34a0c75e50668dfce4e4f2083a693a607370d5e9a79f943609f94663cf47c94e14d5708346b33ab51c2ba91729206356491cd57afd8ceaa0d3634d3257de0367110f05ab7253c2130989b9575887e0cdc6459f9e3b61d72416242e6c2b02a8ffdb98e5c5f6da8e7a13a7c7276ce47e4bfba1cdb000ce070a4bbed57413ac7e5110682fe86b0c5791644be6a7ce6169bca6bfab174b734918da1ce4a399a903be6e2621ca4a86f90e0bc4750819be2cc4603c4aef178c3865c9d858ce8a1f0519927fff327b906cc6e39a4238da0c7061fc4c8240388acd039ae8e7d68990fc78f5061362361c1e1869762ce6a066d24aa9ea4f8468112072fd16f8b314c5fb4c032725fb6729812fe9bdae138b81aba3abdee0ff740fd9a5ffa18205b3307e53607e90e7894767249ae95a436ab71798e1b5b48f4117cd56e3cf3a4912dae43bc63598a78f2ece536cbbd4320248df43cb845169a01981ffeaa2e9dfc17a8aea8675cecd86e7e9a544bddf12af07652cc4b2610a81871e66eb18e643fcd267f99b731ac72258ac4aa66a41a1cead40450876115119133449e2e5535b008957b7b6682e8271a9b0a4c0b4849fc1fc023ec529d2d6614d7e860587925b1eadb3311c90aa1597af55af1beb62dc01867dc0b932deac47adc91d7c1d93968041a1edeb5808a8883f65f7d11be85b8435d23482c081a9d6d3c5693a05aa66186620ed46a23118552673c96820a6f3bb3aa9e51c3a07b26d497c458ad219c5588f461311bc8bd702309f9b44aba430d81559989140f95982e871d502e02c3f161399a367910d526a2063b4892b507c0611d2d8d6d901e318e92eda13ac2c14ab3a9b13129552c00d529b975c1a8bfa0b55bc77488424af77b97d63fd78d9998158e51a297d286156a99fb6a5112ade63a1085228ba7de53c7c3f2d2131e510002ef92cf4c5a45570e07abc094ba294661e4cd96fcc3a7a1bfba84d1a2c8d0b2d550e20fd963d3100fa9d890540cacbc2babd97b6fc4052dc4d4abf77e6c5b8860219ed1276c9d5c566704a9d19e6f54d8ea63315079839a042ff0520797ce78b1489982c26aaa463b20a2e9ac710cb08473e79bd134416357e5216e3e644b71d7182a121dc0f1463e22aa44cc4f6246016cd1af2d119e82abbeae7b6b1ec05e38acee10fe422051c448a14a71a23a98594258d9525544fe697d752477c5e01922706d2ad10351262a32cf86859a180d7f2185bfe370663c9fe81b419ce52560d9552b95f013b31068eb447c528a48c53bff387575d61dda46a9499a0b0d59602591c31a7a20add950142d82719b08b460270b207e9a03ed91eee0e5d8203e5fa061f8e624195f05a4e4e9376e9dfba02d14325ec2beea8fc0b21e67e8b671d8a194e1f9367ada2c9a096c9a6d5c83ba9344d2d2026138ac89940a946090171fd868310fc29f2996b1046910a754243db02fbec676109fa25de969f3e626646209d38b9b3bf909c4d249e5ae2dbc119d779270aa3e332fa2124506a80f41c323a7e1a9486a0cf5002d1ae09f798670d981dfa07a313a254222a131163d596443ca8697e4990e0fd3c301e45874
+InRec = 00c00020000400038000100004000300000000080000c000000008000080002000000001800020000800008000000000000040002000040003c00010000c000280002000000000c000000008000200003000080003000010000000020000000004000240002000040002c00020000c00018000100008000340001000040002400030000000034000000000000200002000080000c000000004000000000000080002000000000400034000300004000240003000000001400000000800030000100000000080003000080003c0003000040000c0002000040001c0001000040003400020000c000140003000040001000010000c000000002000040003c0001000000002c000000004000300001000040000c0003000080000c0000000080001800020000000030000100008000340001000040003c00000000c0003c0002000040000c0000000080003c0000000080002800020000400008000000000000300002000000001c0002000040002c00010000400024000300000000380000000040000c00010000c0002c000000000000300003000000000400020000c000040000000040002000000000c0001800010000c000040002000080003400010000c0002800020000c000080002000000002c00010000400018000300004000280000000080003c0003000040002800010000800030000100004000140003000080001000020000c0003c00020000c00020000000004000280000000040000c0000000000002400020000c0001c00020000c0001c0000000080001400010000c00008000000004000280000000040000000020000c0000c0001000040000000020000c0001c00010000000004000300004000280001000040002c00030000800038000000000000280000000080000000030000c000380002000000003400000000c0000c0002000040003800020000c000080002000080000c0002000040001c00010000c0000c00010000400014000300004000000001000080000400000000c0000c000000008000180001000000002000010000c0001c00020000000018000100004000080003000080003c0001000040001c0003000080003c00010000c000140002000040002c00000000800030000300000000000000000040003c000100004000040001000040003c00020000400028000200004000300002000000002c000100004000100003000080001000010000000024000300004000040001000000000c000100000000300001000080001400020000c0002800030000c0002c000000008000180000000080002c00010000c000380003000080003800020000c000040002000000000400030000c000240001000000003800000000c000180001000040000c0002000000000000020000800024000000008000140002000000002400010000400024000100008000180003000080003800000000400014000000000000100000000000001c0002000040003c00030000c000140001000040001800010000c00000000000000000300002000000000400030000c000080002000080003c00020000c000300000000080003c000000000000300003000040000000030000000004000100008000380002000000000c0002000040003800010000c00000000200004000080001000080000800020000c000040001000080003000030000c0002c00020000c0000800010000c000280000000000002c000000000000000001000000002c00020000c000140003000040003c000200008000200000000040000400020000c0001c0002000000003000010000400018000100008000080003000000000c00010000c0002000030000c000000001000080002400010000800000000300000000180002000080002800030000400008000100000000280001000080003000000000c0003000030000c00030000200004000380000000000001800000000c00004000300004000040002000080003c00020000c000040003000000000800000000800014000300000000180001000040002000020000c0002c0000000080000800000000800010000000000000100000000000003c00020000c00030000200000000140003000040001800000000c0002c000200000000040002000040001800030000c000340001000000000800030000400008000300004000340001000080000000030000c0000000030000c0000000030000c0000c000100008000040002000080003c000200004000140001000040002c0001000000000c0000000000003c000200008000280000000080002c0002000040001c00020000c000000003000040002400020000c000240002000000003c000300000000300003000040000000020000400018000100000000380001000000002c000000008000300003000040002c000300000000340001000080001c0001000000003800000000c0001c0002000040000c000100000000040002000080003000030000c00
+Key = 489c79a48135995c4c8cdeec1777a79cc68bfa7b167f21a25e92945b4004634f
+
+InRandA = ad8ebc02b5c27c85c559292964696c2e3fd406142102d74d8ae9168131abea968da1715a08c67bed550789ccc9254e404045d18a89d4a4696996a5c5cd3c87cfc3d6e92985973d6cce02ac765bec09fdda16a4776c9d92c75431121d1bd453b8f296dac1a5538555823b20f2999cc416e62eaa90a3a2788d877d03b69e399dd089c7778e4d70d831e48a9c371218478612a2ac8eae6c8278956b1aecb7874da681a14d5e5a95325400ec0341f5d58767d0a7798b56bd0882d35b1fee076529fa8a13d523a965093178959a169de1643611870f869069de2c1fd5cdc514dcf626d5da45e7a34c9ee648295890e01f222fd56089a99c6c1b9ca947da5ea7ca32c7a0faa26bcf6ec390ea439defe6a19daa689cc1a1467cfe75d9285931bbc42f2f21d802cea83fc1aa27500762242c6e624b396c499dda561aff040d6f265760ab4d38256352b682682f90c1f9aa1046838ceb916061a550370d3830c0317be41a8f8853406a8f86bda08f79b3e31f8c7746da1c62553ba706020ede82e632a9061de666a8b00bb10e5f44762a99e47ce09c68d080b931e5c34d4be3dd8a7b56cfd762f610c2a183293268258082873779f418d30c7f3517e192236ac6e208c994ec9acd82c52e85f4642c0626763484afe6160eec7f8e2fa317a1ad89ee65c7dbc18481fcc42a757f3d7b48a90cb211703f1ce112e4822057f385b497b0325d94594b66997e5dbf972b9a70b010da0363b79fad6841d4ba8513bcb728ae50e3bc7550630272a5e189715fc198b331de8931af19a0bbfc9e24947b97c0e2a751aca732389252ee53d1093bc175ec0035013ff2431e4fe3da60cc769c0bb515aed63601e824097e750c3587b0569b2897754676917c7e154aefb5f829b60e71c8beb534be1f39a0cf36520a727204339796bd24885dcae7c5e18ba40ea3c553e193a10f6255734a6bc6e171f9898969d8cac08721bea50ad906b4f8803c695e76c21a46b285a728d3f054bede0b1b72630a5eae82838714b26cf35fc0027fe685b1c7d4d422d606cd23bb68e3fa052b5504b243313892e4d1123dc6661a4bd899cf44584e975b14a8dd6bc4c6e1a7b0ba1ee7c6cef815e561abee2052462e6ce46c92b0bc1c717e0aabb1f09c21272df5f6ad650d0e0528f04c652a6a4b6ae784fabd51a3395622dc274d486c36b47d4be3dd454324e12fabed0f6761c9712d1ea6e9224653348202e4000013d4ea0300b6c9bf6a40ef32c1429c28a24a7b8d14b36a15c17896ea0ca047e7c6609177c2ead50053224a5ea12dfb23095b905fd88b422646e991d1049b9a358f88ba76ba3a24a4018594546c1bd5d4f5ab19daa88cc33f46c6194e3217b00b500290ca88c2200a3493ba935949a9cdab90c477b6717ea0df127097e73d4fb30e659b6722853d468261be609e085735fb15e075414cded0e0825ffaa99b0bcef49fded751d6ddd63d37a4f787b74094b356ffa3b5d920749990700a8c24ac573ac9e87d71d02fdf7362d830ac8080f7212a206754fa3bbd1ea21b5195d53ca67769ce53c4451020190b58c821aa5ab9909d69303419501ed9098fe11c048fa1c48d816334468370e5fc21a02b0bc94d158dbde43f9694f441da613252853c7f8010ca98720eaef82599dbf5a84b3a125eb42ee22af05a495077499d43ac084283d2813b6c0fc268e0b432d7ed59fa06187320ef49a7501aa648d1faa1b1a5e0ee2eca253629ba167a670d86587652fcca51482f704cfe71455a192bce7af801994885a34a3a5a063c79860cb0a846b75caf889ac9221e41d8828a783d9510d830a4a5ca7074ed5804e4d60f24eb90a609f07bbdda2df9f7fa5daddb1547582a6b5a41ed2350d0a4875dcc09c8f929e951f231626c3bb245f498c8899bfa9ea610522190b92ac091260e1489089bc244cd57c75b3813d35d84d48d120531ba07c9aefa76733a93c140a737223e7d58e57705425554b52be20ae22c4e69496e5364c906f78f3687c7f0840eaf70b233557bdea0f896b5ac60b9494fb370aeb69d2698f3aff06ebd85ca19fba82873a364b6671d887faf673586f551890b116bfb0541bb55da875cbcaa0751e05b73f20940a26036c1c2710283fe44bfa8b295528212a5b20b750e787465325adcc469189ec8200e866b6961ce8c8c985d18f6bca78540457bd3c12a4de82fca18dda3e6a1ea38336a0d9d5f52eb52e831afd7d7f23a2c06295cabd38bd558c30763669b89289c97d8dba5ac005fdc87534b32488eefeb5148262202db92989c543b2e82105159cda8f1948513b2a28b7fda1c78ae6c1269021a991b91a20ad698e3105cb58e2ecfab1a8d61a904e63244596acfc89f8b146d966915237bd0ad0e79e2cf029d8087d25056b94a699f6684cc83646257f4d033c7d3a6b565aae8626706a80fde6e595b7215dee1e689d7865f5b6b6fb5a3ac90d84584d15e862d2c0ea9ab60e642c76592e7dae26972dfe414e8e5873c6c6f504ec27f4a91b7b5c4aeb900e1b5e927ac57
+InNoiseS = a80b21a95b81047b96b9897ff01246dd9b46644d94e9eebb652d84bdd21a45815d7441a863e381121a78479f8a8b8ca9b3ecc170c8ac0630b1dfddba2f28a373471cd809001b36ea92e6291e26da1bbd469d526e734f45d78f2c6a840533b955fc36330f3dc865d5b7f9d6110b2b3d0eb92f34b9ae344ba06f04888b3202c111ad4749a2b923aa08528eb6a18a08719b06f4793b0dd2c958da1072628fb9a410bb7c5c2165806a718ba1ca0850c191230083928062776069b14562d513e843be94ad3e476b4c4239c1d52fbf900d2b00cd3725dd5111c238ba16a61314c59e706885aca57fc505fb9dfbe6ce6829bed6cc76e9e1b9af52805a737e4baf2f37ebde562ea01172fa29c27e4ed7244308aa253fe11481c90c9e762b11a880a6590d58ed1139f62ba60313f4afed1af24c4764d79c89fda62d06fcfc6258e88979f2559ca0612f845a5c3d6f6c5df309ac8701cdc21a648996f8d8ee97c8d894382b3994b3357afc5d06682e1095f25c1b59be76a316159cb623f04b494deb258f043f216eba710e6e9b0ee772432a45456602942a39f1912ad530b1d3d0b740e3f581cf368acd463a23d3960066d92de33b0a4a398ff673a719b52e15ac91b6a51aa8144826fd657bb517cb65e6e9782dd30a324022bbd7cd8995a5346b32970e0ae9be9aa79c91826b2c0e3c87c0030f72149ca9a77a53e946402e291097158db12aad04dd0c839aad8c220f207214cc87a07d057a81e37ba81956ab24554f657c124e10683af65fea15531d03f1190ebd0b0278089cbe01b019b194ae6ab8c9ef2c8b82e16ff1a4aad24060a62c5e89a3676d12fc1f1be3ee0e552c15808104919e64000a92d55800486af24632c4b02e631a5572d5751385aa95d4b5bbb71ebd56548a6f4a2cbcc33485803c90187b227ab2829e732b8ad15dddc3450317a966201f4ec3d70a3d04ec9a79a2c98ef2a3a693672ead1f0d20e42008726320f1ebfe162ba0c611b03a32a0c96260443ddeab0b04ff9381f14363a6a4e90b45a356907196cfb845c9e68c91d79d2e74510f5a2556605b0505142b0549416e3f8125c65afdad22a88620a05fe34a998a46ba57043488c2102e23da22f18e680be20702d326f8a86ae4bd36d4ed4e0f53fcd9d59c0cdf6a5cc80325730a513631991e420daa12b9f191af12c9b429298157754cb7ead1be85f8e826371954bb15946fa6620c8d63c235e37e7cad391829c258446522e30a60f0fa7a41c05eb0b2fc8faadad38ba6f66ec70fc62b2e9976a1d56bb2b4b26df54621f26b75af4f5030a668e211d58d36688e10a692c541648214a9e8037b86ec2009f2e6c5c0bb4c7e91db3123818441c8675d672c6e7cfde43d359d39280a974bc3e128407ca6e2883f21bc612777508f32202f2558b5b6224b6d4da3e83c9d3c582f7ab1bba82c904a1a75d6668ab0ef8893f4c24e305063e6d85471ced2d74a383451ab027613cdd094476538f9d03a55be9e4d0788099a3a4acebac42865ae436e55df2123a9425270cb113818640b614f8c487966904043d531b58c44b50571b1d45e04b56c4a0332a180f0006e3da108a08978159282670ea10b4e4e89155285bcd0a4d90827f845683b5fd708f0aa9541af9e304b2eb87c4b06f5d483789a621b5431384d7615cff8579ca2a44f157c6882ca6d15e213a9c8fd85015bf8d55cd21d274c442b66146d8dc456718599a68e8d57869e5a4ca4d00b17996c2bc483e476421205e6095594f5a8908ec8c6a28c118b9f2e7794c9920b928f4a5729ec983f2c5ae4846c91d50ddf2b90f6513949187900aa8ef828d4640012006dccfc7a225168165fb32b3a9d535de29310fa669aba94faf0c37d3a32463ec711a474e1cb20c15b36845ee4f6785d6d1a0eebc771d68d282ae2326933211fb91ea08b045113feef903bcaca3ffb6898f61815890b5a09cbe2413e5394f3d65a42250fae3930ddcd1d3d63bd26714640b8ae4cfaa3e57f0fc446ebc6e0822e6aeca4625252591568e1f80aa29a0679e65d9c6d19ea2f388c1a1a526db1f674f22ceba41412fa247b192eae509ff831be8fe55433a69570a7b3b24f1c8d5b443dcadd25a11f0cc432136c79bea5fb5a83de240c64d0717a7299ce499496e71e675c20428834445aa99db4124df4615865b68555c8ae0b021a824324a81ce0be995352b84490ad84413608c12dc2a00e4a53bfdbbb403a2847dde4616a38ed47cc8b04334cde0269ef0120fdfdaf795eec3b98924cce1a3924198e36dd6bc638faa01d76559942508e400c5f10573fb98187a562ca966dbe1b900043fcec5d826d17eb4a1e3790875d05baba956e6cb9d88b211bba112217d01ca67e83e3f6ae187e82e7c3398c127f894bedc489f15f6faad152f2364ebc8d63009e241d01c2db7bb9d6487de303a3915c4699c3e9857d8403671d2a774fe618d34b75560e78285f11938a343d8f5663a396c642b8dbe44aea56325af044979be3cd37b0e3b69436f45d5e95883a47e09d
+InNoiseE = e845be9491fc0c92163b96787e80bf0ed9e369841d76e3ba6a87548fb7999f66d78d96a7d296e777fe3db2c3033a11064940d950d84f01b3d0aa612119d18c200225f7d554a8f2c6c921c28e67efd92587a0f084578f5c36473500110ca8a7415c55750a75f004823d1be0cb09c6488918ea38c3778c212e2cd80081d95950c3fdc1cc61b24b5c8991069867d196189ae04c893be3fb51aa794abfe72b33e48ea2af932238e8747b37459854e30c84d223faf5cbf0707ae958483b3553b3a64aea4afc97eb296078007e2bb480c911795eb3b9954a83fad85d3e254f434c3d1075e9180b32fe7b2e083c0bf3469cb2e8ac6aa7c59645c9d0b3e2fc78ad19014546a545d7ad64d0ef2804eb9a8495c4805de8049c278ef24260019b0a1dd159055ac289067820e2c8cfa1cb7dae90e57072d0d14921ec2ed8ac2080011f004a95405c5167023b0e6e9ed2d0b15b9a0008a6aebd9677feb4cf0d6f904dc0bbea8ed11601c8bea66581c006e5a37ead62954e7ab810537f06e7d1210c80ff844fac9127c1b2005d6541dbe821e490e008524671a653709c249db99940567c4292166bb508984120ea44ae4180f62365d97b3c0153defc41099a5715a4f564d1454c172e3b8366a9a8b5415c99a9d60f6f1fe5a06dc58b7782dfe727f2a8932d45f5289e00ec07f6932d4a44f1e32bc446e9a69e611bc43b3015059f9093172583a0e2e18a2a557fe8690eb852cd1adbd1eee0e8ddbf9de930658830262e97ac30ec3893945485040d5caea90c3510b924a9ca842f281260217e2aa49a7155849c13b4963c708b71ddca47f9849f3347088519a8437462f348e7745aeb40d2eb36a2224617d85220f18f2c99d4c54ccc94a1dc1e47988d95470c925204014b201065b67c785d2a6f23289ad89df746ed90b1fc5a23c8be594a3943726d3c47efe0b087255413ceed195fc6bfb32fd8640b995f382e2d945645a05682ad74cf9ac2e3e9f13b958f89a541edb34558363bcea95315d9e7184dea7f45c081e1ed74869685685148164e4aac81747fe43be7d550a06885552416dabae41c23c89c4791e2110b07a3b4007e2a2d2d6dab709c384d09a92f91316225ccc46980c5ccbfc19bbc91f2d818f557f2f133780367a4954bd1fc8121e86ef57f1a59419d20162baa6b465d61231f5806dfcc373b8510b8d5cee65a09f932c54c71212c3570306baef65a6e8fc0e533b10e0abaea9105b3e5daabcfc82c92550c535c646e84aa4ea50ba7d8c78f419f61d4f6d39f1daf4deb0a48136c6a5d65f2f8db6612ec654795241c0543a1bcc69f8a65dfae5c76fbfd8c105a056b5a5d7e586087719301ab6804f2d5c1988a420b45f58a3e717725ec36e9c1877bd515c814da53822022763808907f4c56384131babc125b1562884a538cdff5e0c137e61b45a40de995c75929a8b1beaed8817ad64b15a823c1f6345d0924958310f0690c576a459d572b32496cdc53fa424cbed92b97a4214974ee10daa7c19d065299ac11151a4eeae4dc6771f642b0661c999ecc96ca58a0c7e80a621c6b32d1046c38ab9368269cc61a48e532171606213c5d5bf4ff6a19b4d36bf85b12b830903ca70576b276195356c03caba1cac6d67e923e2b498371985664cd0a15b46f1253822c3870927202f08dfee8d315255d09548ab2b698c8d19d9b2166a496c4431b5e99644620ac7663ba3cefad032bcafd77559d4fabdc71451c17f074ee12ad13443698a06c758c44afb28190245b221874073a7cef2d8ae46d5d2c2ce6b7fbd0c92978c1dd6a2bba3da1655bdb9cc09c0a24d1c4822c3ece61708414f996500ccbf0790e2f7f9fdd739c7aa7ae1d0be4ba4181910f9d339b6a1667c115b6b6884dc48642f551fc7822ae8ad55d6cbc32141762f1da6ff967720622daaea75455e6a999535763a17248426532511e33d21e00e784258a5079bdef43068acd352e7a43b269ceed99ec518db908ce55dad54c46277da381efd1a147854b492aa31b45f86f06476d6b2cb078cb8d137ab94c3d419dc5b67b6051286c9feb1a9a24d92d8ac781dc7c7b458e30bbce43a18ff2c4343560af9109cbdf69b49ed0ce24304015fb0adb88c2e18f0e50cb662f5635f6240ea0ed7598f4ef07da6d21ba975e9411e39968d5461977104c283ac14bba833cb5c112c699c25064bb22f0fb80e11cebcc0e70a90556e61399049e5880f2946e3425a4330d8ca8aae68d2a4160f1436d0a37aa91c3651bb4bef354f82404061884e6dd55ec591bea4a52b0e4096dd04514d4cbd891495da4d113381a756171d00e8d74d42d2a06001812fc63a10731918076ac892573fd17eb263dc0490615a0412bb38e793eaa146758b4c08af825936732f0bb8616151574c2294b51bb9a1bca28fbc7e29b30e5852c910f40c3d920feadca804e7569e827747ae976b6e5852a76bddea504cdc5bbdbaa06de2aa78686f0973845bb7563fc3c03eb6fa93162b40f56d50bab801068dfc3934c4e7a2c6708c9057e72
+OutPK = e092dbf9d91122e3c8c9b32888abf88fd30616761cccd9e4668c8224c749b688e8f27683d5ca9bac627d876c0ce8f16a872b190b69e839729d51b3a44742af8690498480044eea562de9fc9223254b1ee4c0047763914a21c93876e8e4a8650834774d4eef5b18207f114cbd124c158bae99d658a3718ad0dfd85504815a88808662264a90282e6fb9ca32863d5c789172ca65201704d2e94042aeef4e461ad19d9561abbbc09ca279aab71548b219dbe15199131c7eb9427ef9874297dcc51d83dc1d57d0a9260350a250f9d9db527e4e903605d1bbec04329288f081099218f715a8e808c9a222ea9582b6268a9909a357f4dc1d6d5504253adca14110e416f5aca00dc6ad747dda9ea34085854589062f557434adc9656b1357c550e972c86005e41bf08ac8817c4910813bb44ec3ea63a9b7acd1882695640fdcdcfb943baaa0d36a874b329c43d0dc82e7e6b1ae662abe23cd8eb1382c3241f2614894842a43e969805159846a38715cd98244260c604618eaefc89548648fc6d5f23f28246c033d5b3110267e0b25f6adf9432156bd6b9dc42bfec7d32b5b1abd80d19ebbf2388ad3af0a55e92da8a311434ba38a8b3d6252a7165596c7825e027ea95f619df33413619dfaabbc4b7119a9a8227044cd7827046b2e846ccc12bbe58af4d17d7957a50b6830c55898d220a3cf6500fb1d901380452209401837aa9c6c3403d71be9fdb43f5f64a5b866aeeb559833e604a463623dc9b5ad397ac8e3e7b0520ac610743a6e39a4a0a01006bcfd59e38bed07c7360f772c45d1dedcaf18e2593566d646292911bbdd7d632f57565712765fe90b0109ea3db99da61bb5422ea15767082184e221bbdb09e4094e58ecefff20560866c6eba6d1d7443180417ac8690223e9dd8c99a18e442e80cb4ba0e0746f644f34996200d8db57e6d7927485ae487166665880263cb1bcf28e1c4977864ec9a0b4089e5871be09e6a89879ee48aa415bc0a1d914a1faac0c91ae3889554e594842b696b293700651c0836e081dd250b00e5229a2ea113907b1a0a39b5a4555f66b4baa5dcd1bb02ff997c75d40c98a13474a1892ec463cd2eea565ea9c26bb987613c5aafed27dd42eaa212a09a01a322b80ff568f9d16c3ac70c5b958b7cf16fb9a17313858257133290a5873d34b6957da55b8a5bee2ff2a4ed363b12076c033746bc5b06a9e9c41dcb5780d0d29c0e73ad4fede7582256c1b3bfebc96245af8f97d6655c0606b1bf1bb8a27c719c41117402f9f93fea5bc0be6bdb14b96657de399a1c1206da328342b2d78aff767d7116690b16e0a9385b131a08e6230d0306c0bcb8e1685c1f857ab98d6f865080719058915beec43539640245cc6bd478719c39a691099c225b966ad7a838c4c08beb4033649288bae74978eeb06a6e36486ef1766955e3c31a525f377fc6abd050a52ea3e383ab792606827f276a8a736887a9cafb80314107e9c53d45be5ca85ba0c582683328839a2dfeb044abf56a32d22a4146b7aa7c7c926404b12645b10dc4013058dde023068f60501d9ecb8234a08992220d923110187f26b7b946c683b0d9c64f6ca397f019199ea72e9a13e5552b9b16c95e66eed44149e980c10a46b76c9451f8665f69a716d7bd5fe1858e677509a1c6ba3a8662aab81e42d7e39652d5c09141e8d3899c3c15a4c41bc1489d407ac1e949d37b1d359b58b6870c87e5c885880d8bbf2889b634ef21379f8b9f9a68344d74c4b9c5ea4cb7be919ae0354a189064c0a013c2b655264140c3dc43a812c762d00db994a5cb9a98a35cc582bfaca1c134636a76393ace07e46167aaf6ea22d783a6c8d0d891b5669b711ea92a701a660a2e7e1a368a1f65bd63a8cc2041fa30a09108c002d198d10cf5d821628a8cbf6ca45ebdd5a0018f8a832684fcb91b66f03c0bf56b9413c405457f563347f2928ef63bd3c6531e6ec412ba914ce9f2e576c913af8eabac93492ac2aae23233481afa0594a02cd6a3d7451eb67ebaa17972b6c749e765ebf9b1fc8953eb8b912ba2a6aed334726fe3b37741a26499f62928e0b460da43586923487e2648beb2c2ca59e64a987100590284ab2d25ca215c8ea765d31372d63547627221dfe697fd2db5e6226ac8ce52d0155604ad8c07c799a56e828bad21400421a92da4d455172c2ee099aa13f32a0fb02eac95487624c888eba13210434f52505bbd3672e83b2157cd2890a80e42475bd6e4c590ca9af555dad24e2694dd86d923a62fe313adc2757e195a2f7a8a268d1014a0bdc5bd4b6fd2c0a6a77468ea8bab7d0abb339ad9d186e172a2dc40d2b12cc631c0ab30017ac54f61ab239efdf257ac26ac6e3205ad84e5bc9876c284326430baab511444460dd08fbc5cd7c5ca2e14185c8148552aa1bbaa319b2cc937f17aef4711862e944f2a9360c5d5a96c6baa7f40bee36ee65119c243e78a08eba11e48c109f652844af9837056635649169f2bb3d9dc209543907a6ae6d837f68d670bc7b0626b86b0ab7
+
+InPK = e092dbf9d91122e3c8c9b32888abf88fd30616761cccd9e4668c8224c749b688e8f27683d5ca9bac627d876c0ce8f16a872b190b69e839729d51b3a44742af8690498480044eea562de9fc9223254b1ee4c0047763914a21c93876e8e4a8650834774d4eef5b18207f114cbd124c158bae99d658a3718ad0dfd85504815a88808662264a90282e6fb9ca32863d5c789172ca65201704d2e94042aeef4e461ad19d9561abbbc09ca279aab71548b219dbe15199131c7eb9427ef9874297dcc51d83dc1d57d0a9260350a250f9d9db527e4e903605d1bbec04329288f081099218f715a8e808c9a222ea9582b6268a9909a357f4dc1d6d5504253adca14110e416f5aca00dc6ad747dda9ea34085854589062f557434adc9656b1357c550e972c86005e41bf08ac8817c4910813bb44ec3ea63a9b7acd1882695640fdcdcfb943baaa0d36a874b329c43d0dc82e7e6b1ae662abe23cd8eb1382c3241f2614894842a43e969805159846a38715cd98244260c604618eaefc89548648fc6d5f23f28246c033d5b3110267e0b25f6adf9432156bd6b9dc42bfec7d32b5b1abd80d19ebbf2388ad3af0a55e92da8a311434ba38a8b3d6252a7165596c7825e027ea95f619df33413619dfaabbc4b7119a9a8227044cd7827046b2e846ccc12bbe58af4d17d7957a50b6830c55898d220a3cf6500fb1d901380452209401837aa9c6c3403d71be9fdb43f5f64a5b866aeeb559833e604a463623dc9b5ad397ac8e3e7b0520ac610743a6e39a4a0a01006bcfd59e38bed07c7360f772c45d1dedcaf18e2593566d646292911bbdd7d632f57565712765fe90b0109ea3db99da61bb5422ea15767082184e221bbdb09e4094e58ecefff20560866c6eba6d1d7443180417ac8690223e9dd8c99a18e442e80cb4ba0e0746f644f34996200d8db57e6d7927485ae487166665880263cb1bcf28e1c4977864ec9a0b4089e5871be09e6a89879ee48aa415bc0a1d914a1faac0c91ae3889554e594842b696b293700651c0836e081dd250b00e5229a2ea113907b1a0a39b5a4555f66b4baa5dcd1bb02ff997c75d40c98a13474a1892ec463cd2eea565ea9c26bb987613c5aafed27dd42eaa212a09a01a322b80ff568f9d16c3ac70c5b958b7cf16fb9a17313858257133290a5873d34b6957da55b8a5bee2ff2a4ed363b12076c033746bc5b06a9e9c41dcb5780d0d29c0e73ad4fede7582256c1b3bfebc96245af8f97d6655c0606b1bf1bb8a27c719c41117402f9f93fea5bc0be6bdb14b96657de399a1c1206da328342b2d78aff767d7116690b16e0a9385b131a08e6230d0306c0bcb8e1685c1f857ab98d6f865080719058915beec43539640245cc6bd478719c39a691099c225b966ad7a838c4c08beb4033649288bae74978eeb06a6e36486ef1766955e3c31a525f377fc6abd050a52ea3e383ab792606827f276a8a736887a9cafb80314107e9c53d45be5ca85ba0c582683328839a2dfeb044abf56a32d22a4146b7aa7c7c926404b12645b10dc4013058dde023068f60501d9ecb8234a08992220d923110187f26b7b946c683b0d9c64f6ca397f019199ea72e9a13e5552b9b16c95e66eed44149e980c10a46b76c9451f8665f69a716d7bd5fe1858e677509a1c6ba3a8662aab81e42d7e39652d5c09141e8d3899c3c15a4c41bc1489d407ac1e949d37b1d359b58b6870c87e5c885880d8bbf2889b634ef21379f8b9f9a68344d74c4b9c5ea4cb7be919ae0354a189064c0a013c2b655264140c3dc43a812c762d00db994a5cb9a98a35cc582bfaca1c134636a76393ace07e46167aaf6ea22d783a6c8d0d891b5669b711ea92a701a660a2e7e1a368a1f65bd63a8cc2041fa30a09108c002d198d10cf5d821628a8cbf6ca45ebdd5a0018f8a832684fcb91b66f03c0bf56b9413c405457f563347f2928ef63bd3c6531e6ec412ba914ce9f2e576c913af8eabac93492ac2aae23233481afa0594a02cd6a3d7451eb67ebaa17972b6c749e765ebf9b1fc8953eb8b912ba2a6aed334726fe3b37741a26499f62928e0b460da43586923487e2648beb2c2ca59e64a987100590284ab2d25ca215c8ea765d31372d63547627221dfe697fd2db5e6226ac8ce52d0155604ad8c07c799a56e828bad21400421a92da4d455172c2ee099aa13f32a0fb02eac95487624c888eba13210434f52505bbd3672e83b2157cd2890a80e42475bd6e4c590ca9af555dad24e2694dd86d923a62fe313adc2757e195a2f7a8a268d1014a0bdc5bd4b6fd2c0a6a77468ea8bab7d0abb339ad9d186e172a2dc40d2b12cc631c0ab30017ac54f61ab239efdf257ac26ac6e3205ad84e5bc9876c284326430baab511444460dd08fbc5cd7c5ca2e14185c8148552aa1bbaa319b2cc937f17aef4711862e944f2a9360c5d5a96c6baa7f40bee36ee65119c243e78a08eba11e48c109f652844af9837056635649169f2bb3d9dc209543907a6ae6d837f68d670bc7b0626b86b0ab7
+InA = ad8ebc02b5c27c85c559292964696c2e3fd406142102d74d8ae9168131abea968da1715a08c67bed550789ccc9254e404045d18a89d4a4696996a5c5cd3c87cfc3d6e92985973d6cce02ac765bec09fdda16a4776c9d92c75431121d1bd453b8f296dac1a5538555823b20f2999cc416e62eaa90a3a2788d877d03b69e399dd089c7778e4d70d831e48a9c371218478612a2ac8eae6c8278956b1aecb7874da681a14d5e5a95325400ec0341f5d58767d0a7798b56bd0882d35b1fee076529fa8a13d523a965093178959a169de1643611870f869069de2c1fd5cdc514dcf626d5da45e7a34c9ee648295890e01f222fd56089a99c6c1b9ca947da5ea7ca32c7a0faa26bcf6ec390ea439defe6a19daa689cc1a1467cfe75d9285931bbc42f2f21d802cea83fc1aa27500762242c6e624b396c499dda561aff040d6f265760ab4d38256352b682682f90c1f9aa1046838ceb916061a550370d3830c0317be41a8f8853406a8f86bda08f79b3e31f8c7746da1c62553ba706020ede82e632a9061de666a8b00bb10e5f44762a99e47ce09c68d080b931e5c34d4be3dd8a7b56cfd762f610c2a183293268258082873779f418d30c7f3517e192236ac6e208c994ec9acd82c52e85f4642c0626763484afe6160eec7f8e2fa317a1ad89ee65c7dbc18481fcc42a757f3d7b48a90cb211703f1ce112e4822057f385b497b0325d94594b66997e5dbf972b9a70b010da0363b79fad6841d4ba8513bcb728ae50e3bc7550630272a5e189715fc198b331de8931af19a0bbfc9e24947b97c0e2a751aca732389252ee53d1093bc175ec0035013ff2431e4fe3da60cc769c0bb515aed63601e824097e750c3587b0569b2897754676917c7e154aefb5f829b60e71c8beb534be1f39a0cf36520a727204339796bd24885dcae7c5e18ba40ea3c553e193a10f6255734a6bc6e171f9898969d8cac08721bea50ad906b4f8803c695e76c21a46b285a728d3f054bede0b1b72630a5eae82838714b26cf35fc0027fe685b1c7d4d422d606cd23bb68e3fa052b5504b243313892e4d1123dc6661a4bd899cf44584e975b14a8dd6bc4c6e1a7b0ba1ee7c6cef815e561abee2052462e6ce46c92b0bc1c717e0aabb1f09c21272df5f6ad650d0e0528f04c652a6a4b6ae784fabd51a3395622dc274d486c36b47d4be3dd454324e12fabed0f6761c9712d1ea6e9224653348202e4000013d4ea0300b6c9bf6a40ef32c1429c28a24a7b8d14b36a15c17896ea0ca047e7c6609177c2ead50053224a5ea12dfb23095b905fd88b422646e991d1049b9a358f88ba76ba3a24a4018594546c1bd5d4f5ab19daa88cc33f46c6194e3217b00b500290ca88c2200a3493ba935949a9cdab90c477b6717ea0df127097e73d4fb30e659b6722853d468261be609e085735fb15e075414cded0e0825ffaa99b0bcef49fded751d6ddd63d37a4f787b74094b356ffa3b5d920749990700a8c24ac573ac9e87d71d02fdf7362d830ac8080f7212a206754fa3bbd1ea21b5195d53ca67769ce53c4451020190b58c821aa5ab9909d69303419501ed9098fe11c048fa1c48d816334468370e5fc21a02b0bc94d158dbde43f9694f441da613252853c7f8010ca98720eaef82599dbf5a84b3a125eb42ee22af05a495077499d43ac084283d2813b6c0fc268e0b432d7ed59fa06187320ef49a7501aa648d1faa1b1a5e0ee2eca253629ba167a670d86587652fcca51482f704cfe71455a192bce7af801994885a34a3a5a063c79860cb0a846b75caf889ac9221e41d8828a783d9510d830a4a5ca7074ed5804e4d60f24eb90a609f07bbdda2df9f7fa5daddb1547582a6b5a41ed2350d0a4875dcc09c8f929e951f231626c3bb245f498c8899bfa9ea610522190b92ac091260e1489089bc244cd57c75b3813d35d84d48d120531ba07c9aefa76733a93c140a737223e7d58e57705425554b52be20ae22c4e69496e5364c906f78f3687c7f0840eaf70b233557bdea0f896b5ac60b9494fb370aeb69d2698f3aff06ebd85ca19fba82873a364b6671d887faf673586f551890b116bfb0541bb55da875cbcaa0751e05b73f20940a26036c1c2710283fe44bfa8b295528212a5b20b750e787465325adcc469189ec8200e866b6961ce8c8c985d18f6bca78540457bd3c12a4de82fca18dda3e6a1ea38336a0d9d5f52eb52e831afd7d7f23a2c06295cabd38bd558c30763669b89289c97d8dba5ac005fdc87534b32488eefeb5148262202db92989c543b2e82105159cda8f1948513b2a28b7fda1c78ae6c1269021a991b91a20ad698e3105cb58e2ecfab1a8d61a904e63244596acfc89f8b146d966915237bd0ad0e79e2cf029d8087d25056b94a699f6684cc83646257f4d033c7d3a6b565aae8626706a80fde6e595b7215dee1e689d7865f5b6b6fb5a3ac90d84584d15e862d2c0ea9ab60e642c76592e7dae26972dfe414e8e5873c6c6f504ec27f4a91b7b5c4aeb900e1b5e927ac57
+InNoiseSP = c64beb7608609174039c0966eabff18173e661d90f131e87d7ae8150e5c34773303d482a1d83f58ef58037e0ccf1aee263b3a8e0a6f4716019c3b735a4e5b4cc111c0b34623a65929394a9357224214776813e93fc1a03586de232a7a8327ad2be35a6542eb9adf031dd2a829662c2923fc25588de898075e4bd2b30921ccbd0f13280263a689fd4fb107aa35883f8212c858ff08aaabb6b0259154a0c479f40aca2a06d6319dd7ee75d6fc048f5ad6425c966cf1c6afd97108164c8828dcaf86a96264e85123180d4d97e4a43d620d9325b359a1788db6c5ce4cd08252d4c0f9d491132cd217da62ddea308ac8e992cbecb7a66bbe0909abbaff2a96f925b79f6516ec5c78ed3da0154030cbdc7ebe50286540ba84c54bdeb2b98f2693d69d9de9434a18529071a0ff96784288fd43550233ebeef51fef54e115ff5994b87072e2583806773d33969c8eb3bdba29a9012464278236159b542bd30aa8c6718ca3320ab6534455dbba143b937b24cd702c8d4963854bd819f9dabcc000005fdada7bed44a94263843ad6c08f7c05c09829c72510bc432411eff258c7d783e1676fbc7757321c6d845fbcd7ae609516427588cb4935438b76a64ea41f5f92ba167a25737748af281bb2b3646659e10db4896a4865013126cf70ac85098a305627a102cb4fb4d9d044498019604ef082f21393b588d81dd1a97a5640e171dad9dac6ded9874e52ad1eaaff519be29a35dc6cb60b044f5caca27eb9c96842758f2500592fe1f408be9381afbd95b557b3022b9ab00e2060498a00f5332802522ce41c6918a3a177b088d321b082b09eee19acd1986b9cd4f0802f6ba146e6c3859d0af7fd3a51a1d6c680717e3b1cf6e9b42e2a3c9094140f90289594e40a196112793e53a7a749fba7539061aef4518db2c9c981ee249d12f205e9f241949e18171e81c26700694bb3bcc474949f504ed98fcc827cc8e9b628b56ede94c3cca63e75c32aa9b41a5526c0160818c9c18ab484d49e015facce589c340ebe41d6c4f9ad66353f5ba6182d838cbf554a8ad4bb41b7396362d9dda2530a1411c15ba4a61cd473d0269e0d76e9c5aa8b3902c169269220c0076d215b61424237bbe46cad136d6c0dd220d42ab265402698b1d821a52512dc7c6ab0162b402ff8ab1b33da922abc61840ac76aa3505136789e07d461a08715acd713eaf3f42f40c46f848da48d15cbc2adeb705b29c33ebd330f8384501845eada58c80654a2cea07a3d558e4e80d81b8f943840b73a3272479132a2557efa6566b0688996f0e44ea171a52582a5abbd49fc12d35536bcc137283457de9d53a87295568cd5e6338a7b5b3664c26d18c99024b6143a5bd657f96e2320869305498864e34e9c046e6968705bbf530ddc73bb954817a0161b3ca898046b7eb97270ee48fb348a34b39d14933e18a47df80362ed4fc0227848fa448d061a11d97b62123f2985133d15a59f3d4dc83cb19cca11000320324c4a4bb008c965a2344237418ad00a5f2dfb609d89f89998e7e9470031bf0b06197198bdfdac9498f528ca7f817318e569816caab2944414113e3f89a08200e4921dd3ab85b5782b569d610b41f7a61d6ee2406e3e8e06429bc3329765592f04fe1403fc0fff88eb28f6587b2b6b1e5cc8cf1d44983c70e4de001500cb71807a8ea9a00f9cae380c8087fe8ef6ab157d90ccf234b206cee3823c3f775365c972422d0597bd01ae9e1596bdfde7c53617bb3964904c4897fb8f07515b525f3558715498168f12081b698a91e7b9ab7b80bcd2f1998a92255a4af3d4a169e73d3d255f2ec392c1a671aabd8be28c21207c636b12e49da9bf1978aa74723be73ca9872222e0ad439f681946e484867565f8ca48656e8f618bfda386209d9046a1c886b9414bd11e93178d0cc1944d84b987882884ce8271b5532332980c0d5ca8c629b8b81f65f62aa5545dba61e215249a7f2457c06965004db62e31e1344a7fe3557105580e6c181a184079090b535a7e15b04c434277b896cc98c7e56d2a8492b4f25a91c211d4a0bb219fb087453ede72402a17386c1c96770821f6fd4dfb97ce84ffe1d15133b765c7f6fc4b83d85b54704cb3bbd4a3221e990d3cd521874894993487a6fa25463645b89b8aa5aea272c9e2e0e2e14f010080f2e4f6fc6b771a7e7c377e91ce8896105e1e990714dba41a925479aa37bef79a963969bc16ce49888b8513e209820e3116dc786c39b8f5a4861ed4482f45e3c481fae6b6ce4a0fb9dffc76dd0b3b5046bcbaea678821655c434055106cdb3d2a88830d91345837bad1ac5cb230af6995aea644cd87e38a60393d024122d1a8ded1de4cff1050e98040866dda4c89278d02aa6bf5c4e31f442505e07a2889189c45994c5ced0de41b58baf44f2a7fc34259909fbc2f8b93356bf362086ac2493ff40ab3652fd9a890aad5c6c77a20052d5398649056cfbac185018cdb0c7779ab5898ce65b5af261921668d3b6b9186f6692db8c4658f29dc3050d7115
+InNoiseEP = 56580d3581e9b313853d989e7aa880543520dd4d79ba81873613024324416364673aa8eba9f6428ae800496d492547f1205d67af20d2c6bfa4029bcb560d421ac9ede485fc9ce525aa141fec013ad09b7b5ef14b24ce5761f2065850a6d9c7df2843d610a00b98e52ba54cffbaf24c0596609c3314d1823891ada417b425612df3ba99e287f65cb7e1727cb510c92932bd35511dcf81f9b4bc81bde3a2b98d7e3d7a847c64172c7f1fd6a5d214ceaeb955581613b6a9d28743569bbd711920a768a0bc31be652460497cbc8dea2eb7e54d09045b0f89f36c0d111c83c7b46406fd9e15f3aec966bf6fe6836d4e1c0f41ea729358621c2ed3078b26936096f73a67964af5e77ba41be07238d6a062c6582d01ca41ca6e8a75079d1497119466550d25d06e84a979adcf30ccfebb158482baa111026ad314fbed709f4f21d0700a2e82ca94837a314891dd573e64d53a8bc49a0d796fa1b4c7c640b9739c7d53518d74adba7f6c1428353bb628f79d1ca195f4aacf97a242ecc6336e0bcc89a29d133c55d9778be105e4cbef773495342a425858ac2a6094dcf4eb78f139bd0cf0918246b8e89281b9bf5949c452dbb45a199dfda959c369b2bdfb2221aa0f5d7f4fef8087c6d04bd56f34b8f98297c31feb281cd0b0bed525f32552079e274395f3a16fec6dfb16fb7558be4169bbfda64131e8e93318f69d974f841964d4278f53e910e7f29287073eb7d939217dae13b10be11f4ad27dbb505198a9c2402bf3649b95c06e78bda95e504a6a91b6ee77d7ef3a51d07552d692a920df1a5450a67839c39a8a636b89b14b6d7d8b6685343ad2539856bbd50a24b0134f56d5b6c28069efe7089d2085a799e7232a4c4e1785d58aed5d489b6ec2c49ecc2b5069ea29acb82d3bd61b77dedc67cfa2b1964d8080e850f47bd4a9052d043eca734487d526c2453c6d3722a01810a9a20c73903d9a4e51663683b17a44952dbe00185584a19f8a85ba56a0dc6f6c2eb21407de982ea6c24bb4ba99941cdf846c2822e51d88d7b88a6005c642d607c67eed65b63466b050e2810a2777de0cc055f100c69c7219cafe07936618f54f981414394387ad95b1adeda3d94edf6a2e4db35cd0b463b17aa7a1973f5a225226a4ec2fe6ba4c504aed32cb4abd79374ae045fe6a4c7bdbc0aac0b8bda624dc6099de66aa007c4938e0b4995466f8c3fe7cfc051c64a33d8c8f15eb7520dc0c35dafab4fc8c595859f000bf44717c9be42448eca6da25e0b702eebf6b272f41dab06106093fb0bb8e27b584e6c86df28616df637820f905b623503bd14523948545290c616fb30213e7da511965a2c81576f4a0786474a3c508a68fa92168b8847c6e6755c8fa8c5c9368381104545667d1221ab59a13dd9dbef2b0ed36736e90515c2175e408956a9085a3950b7da321668b97525580013970f415bde3225534b82f2549e0dc339e117bb1d9815683593bb18d2c70d387be2a723097ca6e30ebd3322d18d85c1241aa1e361828b7cf8c229ca177103d8c1c028bcc84b80a1013af478198dea250cd20f86d46b6e95f52b8e2b40eade14c7974a563d6a85e86dc69396629d58aa7b6110d6da33a7b80555ba543e25c987754522dc96db560e24b72e9dbb260522cf1e6da744c5faf989bf14e128647457ad26622d3aae638dfd49fe69938421e8a9d9f1ea0c8720d7e6a9da7893c7440fd920edabe4d06419598e2cb2e59606dedc006bcaa2acbac9a2ecd3065697b92059c299aace3f02cd51675049f820b4a4e7480026bc71e19e388df193a0ab98be36a353198a7ae0ccbf928e67eb427137bf6ce25fbec0be741fc4912a22c68875d37f2ac823008393461a684b643c0b39ac0f6eb35b9a2ae0953cbe1163a93e7a104acb035cbc00ab86ba09b8bc1738766602579e15ac21f94686095d0c82b945330834f633b655e54984948f7dc6e79a67e52c195726e2fe6d518e2615c9a43a3aa2e69ac2e8c67f1615db3070f671a08a0d2250c755cdc9b97901e6b36f68d9ce34526330a17f98bb2a12c9d09aa4846c0affea228a6705b5115667c231acb86e62541876d51e2622840181d18d99d8a7dea535aba4e62a8d432280db67ecdc4c5b997c079c2214718d0dd7e5fabfdb4ab9815340c66c0fada45c6041e4bea112db4627ce4a08a5b3e42e9ea8c390ee84636807b4d4b4759958951fe3cf64608d7b7799a42600a934c75b85843e436cb4a70440025a5ab594128190ff96c1c82d555bdf543b82d3bd88fd078b4b2c51b6171c3e90587169938535c48c5dbea13b6b187341f2f61d835b99e4fe3799e5a3af787cfa68f2a100c6f38c120ad73f36d95da3de1184103b0f192d80cce06b3d36b20acd5dd116a1ac2b383aa4f37876e107a4dc01842e12d2d6b819a8139bd7b9214b3e7dc44039652bb8acdb12f0fff23f7ac445804281959ac1529d63cab2ab6170c220c6983da677348ef13c3840835d6b14361798f598cc2ca4b16ac76affe8017a63e6225ed4a5cd05b
+InNoiseEPP = ffafff1b000c00008000f0fffebf00b0000000fcbf028000c0fffabffd2f011000fcbf0000002000f0bf00f001100000c0ffaf00e0ff0a00ff2f0100001000ff6fff1b00f8bf00b000d0fff2bf01c00130000400ff2f00f0fffebfff6f01000000c000000040000c000500ff1b0010000070011000ecbf0240ff2b000c00000000fcff0e0000000010000c00038000500000c00040001000e8bf00b0ff3b0004000040ff0b000b0001800010000400000001000000c0003001100000c00200001000000000f0ffdbff1600fdafff0b00040000c000f0ff02c000b000200000000080ff1b0008000340fffbff02c0ff6fffdbff0600ffefffdbff06000030ff2b00f8bf00c0ff0b00ecbf02c0006000f4bf01c0000000030001c000000004000480ffdbff020000f0002000f4bf014000f0ff020000f0ff3b000000fe6f0030000c000280ff0b000700fe6f0000000b000040ff1b00fcbf0180ff0b000700fd6f002000fcbf00c000a0fffebf0040fffbff0a00ff2f004c00f4bf01c0ff1b00e8bffc2fffdbff0600fe6f01f0ff0600ff6fff5b0000c0ffefff0b00f8bf00c000c0ff1a000100ff6b00fcbf0300005c00f8bffe2f00dcfffabf0040000000ecbf01c0fffbfffebf018000300008000280000000ffbffe6f00f0ff0200fcefff0b0000c00300004c00fcbf0180ffebff020000b000f0ff120002c00010000800ff6f000000030004c0ff2b0000000380ff4b0000c00030000000f0bf010000fcffeebf01800000000f00ff2f000c0000000030ff0b000f0000b0ffdbff120004c0ff1b00100003400010001000fe6f001000f4bf00b0000000fcbf058000b0fffabf003000b0ff1200028000f0ff160002800000000f000300000000ffbf014001c0fffabf0080003000fcbf0100ff1b0008000440ffebff1200ffefff5b00f0bf0400ff0b001300024000f0ff02c0040000dcfffebf0480ff0b000300feefffebff0a0001800030000400fe2f001c001400024000f0ff0a00028000000003c0024000e0ff02c0feefffebff2a00fdeffe1b000400000000d0fffebfff2f00fcff02c0014000000003c00380000000f4bf03c0ff3b000c00fe6f00e0ffeebf03c0001000080000b00010000400ff2f002c000000007000d0ff02c000b000e0ff02c0feaffffbff0600fd2fff2b000400feaf0000000f0000b0007000fcbf0200000c000b00040001200004000400000c00f8bffc2f002c000c00028000300000c0fe2f0130000c00fc2f0000000b000300005c00040002c0ff0b0004000030002000100000b0ffdbff06000200002c00f4bf04c0000000030002c000d0ff020002c000100000c000b0fe2b00000000300000000c0000f0ffcbff0e0004800020001c000180ff4b0000000100000c0000c0feeffe0b001300ff6f01000003c00480feebfff2bf050001200000c0ffaf00000003c0ffeffe5b00080005c0ffebff1600010000dcff02c0020000fcff0a000440ff2b000000fc6fff0b00f4bf03000030000400010000100000c004800000001700feefffebff020000c0ff0b001800feefffdbfff6bffe6f002000100000b000d0fff6bffe2f01300000c0028000d0ff0200014000100018000070ffcbfff2bf0140ff0b000f00ffaf00e0fffebf0080ffcbff02000030001000f8bf0040000000ffbf008000000000000240002000f0bffe2fff0b000300fd6f00000000c0064000000000c0fe6f012000fcbf03c0fffbfffebf0380001000fcbf0070fffbff02c0fe2f0000000c00fe6f00c0ff0a00fd2f0010000800fe6f000000ecbf010000f0ff0a0002c00030000c00fdaf00200018000780ff1b000400010000400000c0018000f0fffabf0030001c000c0000f0ff4b00ecbf0280002000f4bf00700050000c0000000000000700f72f006000f8bf008000f0ff020000f00010000c000040ff2b0000c001c0ff1b000000014001200004000240fffbff0a00024001f0ff0e00fe2f000000f8bf003000ecff1600008000f0ff1200ff2f002000fcbffe2f00d0ff020002000000000f0000300000000400ffef01200004000030003c0004000030015000f8bf05c000c0fffebf05c000f0ff0a00014000f0ff0a000400003000140000f0ff8b000400fcef00000004000030003c00040002c0ff0b00e8bf0100013000180004c0ff0b00100000000050000000fe6f01f0ff1a000540002000080001400100000b0002800010000000fd2f0020000c000000003c00f0bffe2f003c000c00ffafff3b00000000c0ff3b00000000400040000c000000000c00ffbf000001e0ff12000300016000f4bf038000100000000080ff6b000400024000e0ff0a00fdefff1b00f8bfff2f00d0ff02000100000000e4bf00400000000400fd2f00a0fff6bf00800030000400007001e0ff02c0000000000003000070ff5b000400feeffffbff0600fb2f002c000000003001e0fffabfff2f00f0ff0a000030003000100000b0008000fcbf
+InRand = 13d4f1b473932b85d8bbbdbd30713aa4a25482ae0f02e3351794769e68e70eec
+OutPK = 8b2d5c9aec7477f2e384b6a9ca064b029f6386ca3b760412859c647f78c364b158d8659c65d692b506bb4e56dc233189bdf703ed9134a47873cc14793f05aba55fc63ac34e9d02d3ef2a706e1a916a8816d8d07deacb2777e2b4a545e7e00575fd7a664b9d626bb05acda02a55e9a96afe54ecd6f95037edd2599089167b10e46d68f25258799ac46b166d9f9313d0e8f2d0a8a2a533b68ae1ac9c2c467071712f192bc809f2dc45b76e214a5d41222ec4b9d5a062a0b600beb70270aea1254cd8f79d4b034a357ba19527ea02bdd1a1ea09d04eabf568103cc4ca8be72e697a3e8ba131de02396c0a5b033742af982872ea3ade03f8a22059fad59fb21ee9529c544ccd9f7d64172c9d2515d6379b2e0df9903ec839e1b1db192a3a1ce5b1d94a17f748698a91cbf39306ad24e34ad329d3a8500cdf8bbbde0e2cc26b3d673e8a2159d0bbc0e5fd38f08e22063178b41a0d890b95761fec6bd5f64ebc260c6909008efa02f7477c199d32265e552f057606b13d84cab4de42094a94961226f58021cb1f34a95d1206a00ce286fea7c5aa40b1b93d9345ed1723b6747b1de69823ddb4409ba4391bbd24494011a4a590d20b151237a9e7a23b4be8865207514c666fec394406b367685880baa020eb5c6a556c614312aae258018d23b46f2c120cc43a8c9b082b755ab1fddd90b8eb4526eec8c43768255cac2c2d161a605ea90e2fa100a82448cbe04104e839ea617f93730064e0a963c3d9d60f4b214b29a1aa38380a5409e29878b788cad64db263449a69616d959bc8de606b40228dd38eef97797c80374b749a818a5ef40560a14701a4f4e45d1be415591ec47950aa9d6ca84af8986c9516a55be012a02d93a6a43604f9ed58a7dee509aab6576ed9a4217cd1bbf291864630723eb0d25c3ae7f123dbd12d92061a30de10a4e5a9dca35303e1379c0976295851f67e5237cae4e4566c8481382e2f212f580adfe4e18822d0a6bfd69a355eb670324e35559f95a9fe87222708d80a2b9269b075d660c020c2ba5c29acd809eacb71e266d627b7a322a9675203c4583e61a9b6c99ed6fd299e9992f60189be642d0b4bbb0e710153db50b4931c6849a4bc81608629a2ef850218f00d944be1ebe4f1520760c09119f47d751e85425eb89e309a45233fd290ae53f052074164b0cc35705f805b611aec389a209a122cb412d1d214f11314e427a931b5a82f49dcc4ac0ca5d347f49146bd6b35c62dac7689abd60be0399f045692484289491644ba9963510ef2c352a0e43c9589c6b52215c43ffde82ad868768c2da59727ffc45623eba8e3397995382471a60f4a82985987c110eab255cdf4319c88481e87f1fa80feac75eb0b626b71064d98a4c9324a7f9a58b023053c7849ee95ea7fe2510a8648b5894298d15776a49d35580122737a97968711ac9e98011c453b27f47b383e6ea46532678101374a2e6a8778e6b3f82212c240050a22cd40554aaea30b04eaf1b7748e7d51da4a1be83070eccab4c2f621fb93983b98940c9926b7d7f51a58ffa6d4a7350c0879546c4025013f952d9c410ecd7532d30b393b9a2bebac155468f48add16b6ca79e887bd5c7e12fafc71fbdda1cbbb8196b56dd3f168ce5e15dce5f0400030582e716056f85c5b10c2c5f4bd20cc6f64e2ccf179ee5f7864164c642d6356e6a89c17c91a0312f24859324b7d01f419691e03b4c198859a6b6b355964fc839c26f101ca88719b004492eed28a9d9c956519c053e0acc0350c2c3c82d4a438ec40033390fde66f2ab7672a16f8d7ae841d641754bde0466fa84b6822dca7766c7468205c12679594812d190153e54784665052961cdfc3fb3510084f44ea8bc47d00d8c7a0683a4178ab5e8725196334488ea9927448fae93ac72a548648d481122f166c8cc902161fadbb2325c2c4d89c79196a8648c49504b7036037337d85788b156865e674f6deed11965102ffe2041a7d9a55ddd53fe368828f6540fe79a4c4a1762dee08cb39524f89c0eb0a2a9246df1f85c1318c259f6dd6ae4dbcf39e91c9e3ba23f809bfd69d81bd749ddcb2bef679bfc6c118853e9736c9b5c808b4b31d254b444cd98c5ba104e6d368007c67e541ff42489d962c5462b5aa325f73e5e34c19998be96a705c78bb47a678f1a57819a887c2f3d64a37e997790f060f91c8b2760348802b1f854731003d21ab8f907c91861cc962804cb80c5cc26dd5802572c1594ce16cc57df24063289c582510cf5ff810ec43c2e0701b2a080d891992372c1979dd8420223cf04cbc401233d1a42fe646f8b2f2c98cd49cb813ab08b729a44f314c35884582d920e564659cef80aa61387029822713c2e868765a2917d8060c0115f5b6df3147548812216fd152ef4520c64e6a89de4a88946f7592dfc9ea20c61c8c1aaff83391fa71e6ce5e06f67e47e702663b137c275f5904e0c21c3b080723b75b492dcd03fc768ea633011ab3d3c4987cc5d96a92c22250b41ccf15beb885cca27352b4d9af
+OutRec = 00c0003000000002c00030000c0002c0003000000002000030000c000100002000040001400030000800008000200008000340002000080001800030000400004000300000000240003000000000c000300000000300001000040000000010000000004000000008000280000000040002000000000400024000200000000080002000080003c00000000800024000100004000080003000080002c00030000c0003800010000c0003c0001000080001c0002000040003c00030000c00010000300004000300001000000000800010000c000140003000080001400010000c0002000020000c0001400000000c00014000100004000100001000000003800010000000020000200004000380000000080003400000000000030000100000000140001000040000000010000400028000000008000100001000000001c0003000000001c0002000000002400020000c0001c0003000000001400020000c000080000000000000800030000800020000200004000240003000040003c0001000000002c00030000800000000200008000180002000000003c0003000040002800020000c00008000100000000200003000080000400020000c000380001000000001800010000c000180001000000000000000000c00000000200008000240003000080001400020000400010000300008000280001000000003000000000c0002000000000c0003c000000008000040001000080001c000000008000080002000000001c0003000040002c0001000040003000010000c0000c000000004000300002000080002c00020000c000200002000080000800000000c000180001000000003c000300000000340000000080000c00020000c000080001000040001c00010000c0000c0003000080003000030000c00034000000008000040000000000002800000000c0000000030000c0003c00000000c00018000100004000340002000040000c00000000c000000002000040003c00030000c0002c0002000040000c0003000040000c0000000040002c000200004000100003000080002c0001000080003400020000800014000300008000240002000000003800010000000038000000004000340001000000002000000000c000380001000080003000000000c0001c0003000040003400020000800028000000008000000003000080000800000000c000340002000080002800030000800020000200004000080000000040002000030000c000240003000040000c0001000040001400000000c0002c0003000000001c000000008000000001000080003800000000c00028000000008000100001000080000c00020000c0003c0003000000002000010000800020000300004000040001000080002c000300004000100001000040000c000200004000140003000080001c000200008000180000000040002c0002000040001c00020000c0002800010000000008000200004000100000000000002c000100004000340003000040001c0002000040003800000000000034000200008000140000000080001800000000c0000800010000c0000800020000c0000800010000c000340001000000002000000000800038000300008000040003000000003800030000800034000200008000180002000000002400000000c0002c0002000000001000030000800018000200000000200002000040000c0003000040002800020000c000080000000080000800010000c0001000010000c000200000000000001800000000c0001400010000c0003800000000800018000200000000100003000040000c0001000040002c0000000000001000010000c0001800000000c000300002000040003c00030000400020000000008000000000000000002c00030000c000200002000000001c000100000000240003000080000c00010000000028000100000000280003000080002c000100004000300000000040002800020000c00000000200004000100000000080001800030000400000000100004000240002000000000c0001000040001c0003000000002c0003000080001c0000000040003c00030000400034000200008000180000000040002800030000c0002800020000c0000800010000c00004000300000000380002000080001400020000800010000300004000200001000000002400030000c00008000200000000000000000000001800000000c0002c0002000040001c000200004000100002000000003c00030000c000380000000000000c00020000c0000800020000c0000400030000400038000100000000140001000040001c00020000800008000300004000080000000000003c0000000040003800020000c000040003000040002800030000c0001000010000c000100002000080002000030000c0003800020000c000340001000080002c0002000040002800030000400018000000008000000002000000000c00000000000
+Key = d5492977f04342e5c73557bce8b5f5c5a6c2e2acba0c8addcb834e797642aba6
+
+InNoiseS = a80b21a95b81047b96b9897ff01246dd9b46644d94e9eebb652d84bdd21a45815d7441a863e381121a78479f8a8b8ca9b3ecc170c8ac0630b1dfddba2f28a373471cd809001b36ea92e6291e26da1bbd469d526e734f45d78f2c6a840533b955fc36330f3dc865d5b7f9d6110b2b3d0eb92f34b9ae344ba06f04888b3202c111ad4749a2b923aa08528eb6a18a08719b06f4793b0dd2c958da1072628fb9a410bb7c5c2165806a718ba1ca0850c191230083928062776069b14562d513e843be94ad3e476b4c4239c1d52fbf900d2b00cd3725dd5111c238ba16a61314c59e706885aca57fc505fb9dfbe6ce6829bed6cc76e9e1b9af52805a737e4baf2f37ebde562ea01172fa29c27e4ed7244308aa253fe11481c90c9e762b11a880a6590d58ed1139f62ba60313f4afed1af24c4764d79c89fda62d06fcfc6258e88979f2559ca0612f845a5c3d6f6c5df309ac8701cdc21a648996f8d8ee97c8d894382b3994b3357afc5d06682e1095f25c1b59be76a316159cb623f04b494deb258f043f216eba710e6e9b0ee772432a45456602942a39f1912ad530b1d3d0b740e3f581cf368acd463a23d3960066d92de33b0a4a398ff673a719b52e15ac91b6a51aa8144826fd657bb517cb65e6e9782dd30a324022bbd7cd8995a5346b32970e0ae9be9aa79c91826b2c0e3c87c0030f72149ca9a77a53e946402e291097158db12aad04dd0c839aad8c220f207214cc87a07d057a81e37ba81956ab24554f657c124e10683af65fea15531d03f1190ebd0b0278089cbe01b019b194ae6ab8c9ef2c8b82e16ff1a4aad24060a62c5e89a3676d12fc1f1be3ee0e552c15808104919e64000a92d55800486af24632c4b02e631a5572d5751385aa95d4b5bbb71ebd56548a6f4a2cbcc33485803c90187b227ab2829e732b8ad15dddc3450317a966201f4ec3d70a3d04ec9a79a2c98ef2a3a693672ead1f0d20e42008726320f1ebfe162ba0c611b03a32a0c96260443ddeab0b04ff9381f14363a6a4e90b45a356907196cfb845c9e68c91d79d2e74510f5a2556605b0505142b0549416e3f8125c65afdad22a88620a05fe34a998a46ba57043488c2102e23da22f18e680be20702d326f8a86ae4bd36d4ed4e0f53fcd9d59c0cdf6a5cc80325730a513631991e420daa12b9f191af12c9b429298157754cb7ead1be85f8e826371954bb15946fa6620c8d63c235e37e7cad391829c258446522e30a60f0fa7a41c05eb0b2fc8faadad38ba6f66ec70fc62b2e9976a1d56bb2b4b26df54621f26b75af4f5030a668e211d58d36688e10a692c541648214a9e8037b86ec2009f2e6c5c0bb4c7e91db3123818441c8675d672c6e7cfde43d359d39280a974bc3e128407ca6e2883f21bc612777508f32202f2558b5b6224b6d4da3e83c9d3c582f7ab1bba82c904a1a75d6668ab0ef8893f4c24e305063e6d85471ced2d74a383451ab027613cdd094476538f9d03a55be9e4d0788099a3a4acebac42865ae436e55df2123a9425270cb113818640b614f8c487966904043d531b58c44b50571b1d45e04b56c4a0332a180f0006e3da108a08978159282670ea10b4e4e89155285bcd0a4d90827f845683b5fd708f0aa9541af9e304b2eb87c4b06f5d483789a621b5431384d7615cff8579ca2a44f157c6882ca6d15e213a9c8fd85015bf8d55cd21d274c442b66146d8dc456718599a68e8d57869e5a4ca4d00b17996c2bc483e476421205e6095594f5a8908ec8c6a28c118b9f2e7794c9920b928f4a5729ec983f2c5ae4846c91d50ddf2b90f6513949187900aa8ef828d4640012006dccfc7a225168165fb32b3a9d535de29310fa669aba94faf0c37d3a32463ec711a474e1cb20c15b36845ee4f6785d6d1a0eebc771d68d282ae2326933211fb91ea08b045113feef903bcaca3ffb6898f61815890b5a09cbe2413e5394f3d65a42250fae3930ddcd1d3d63bd26714640b8ae4cfaa3e57f0fc446ebc6e0822e6aeca4625252591568e1f80aa29a0679e65d9c6d19ea2f388c1a1a526db1f674f22ceba41412fa247b192eae509ff831be8fe55433a69570a7b3b24f1c8d5b443dcadd25a11f0cc432136c79bea5fb5a83de240c64d0717a7299ce499496e71e675c20428834445aa99db4124df4615865b68555c8ae0b021a824324a81ce0be995352b84490ad84413608c12dc2a00e4a53bfdbbb403a2847dde4616a38ed47cc8b04334cde0269ef0120fdfdaf795eec3b98924cce1a3924198e36dd6bc638faa01d76559942508e400c5f10573fb98187a562ca966dbe1b900043fcec5d826d17eb4a1e3790875d05baba956e6cb9d88b211bba112217d01ca67e83e3f6ae187e82e7c3398c127f894bedc489f15f6faad152f2364ebc8d63009e241d01c2db7bb9d6487de303a3915c4699c3e9857d8403671d2a774fe618d34b75560e78285f11938a343d8f5663a396c642b8dbe44aea56325af044979be3cd37b0e3b69436f45d5e95883a47e09d
+InPK = 8b2d5c9aec7477f2e384b6a9ca064b029f6386ca3b760412859c647f78c364b158d8659c65d692b506bb4e56dc233189bdf703ed9134a47873cc14793f05aba55fc63ac34e9d02d3ef2a706e1a916a8816d8d07deacb2777e2b4a545e7e00575fd7a664b9d626bb05acda02a55e9a96afe54ecd6f95037edd2599089167b10e46d68f25258799ac46b166d9f9313d0e8f2d0a8a2a533b68ae1ac9c2c467071712f192bc809f2dc45b76e214a5d41222ec4b9d5a062a0b600beb70270aea1254cd8f79d4b034a357ba19527ea02bdd1a1ea09d04eabf568103cc4ca8be72e697a3e8ba131de02396c0a5b033742af982872ea3ade03f8a22059fad59fb21ee9529c544ccd9f7d64172c9d2515d6379b2e0df9903ec839e1b1db192a3a1ce5b1d94a17f748698a91cbf39306ad24e34ad329d3a8500cdf8bbbde0e2cc26b3d673e8a2159d0bbc0e5fd38f08e22063178b41a0d890b95761fec6bd5f64ebc260c6909008efa02f7477c199d32265e552f057606b13d84cab4de42094a94961226f58021cb1f34a95d1206a00ce286fea7c5aa40b1b93d9345ed1723b6747b1de69823ddb4409ba4391bbd24494011a4a590d20b151237a9e7a23b4be8865207514c666fec394406b367685880baa020eb5c6a556c614312aae258018d23b46f2c120cc43a8c9b082b755ab1fddd90b8eb4526eec8c43768255cac2c2d161a605ea90e2fa100a82448cbe04104e839ea617f93730064e0a963c3d9d60f4b214b29a1aa38380a5409e29878b788cad64db263449a69616d959bc8de606b40228dd38eef97797c80374b749a818a5ef40560a14701a4f4e45d1be415591ec47950aa9d6ca84af8986c9516a55be012a02d93a6a43604f9ed58a7dee509aab6576ed9a4217cd1bbf291864630723eb0d25c3ae7f123dbd12d92061a30de10a4e5a9dca35303e1379c0976295851f67e5237cae4e4566c8481382e2f212f580adfe4e18822d0a6bfd69a355eb670324e35559f95a9fe87222708d80a2b9269b075d660c020c2ba5c29acd809eacb71e266d627b7a322a9675203c4583e61a9b6c99ed6fd299e9992f60189be642d0b4bbb0e710153db50b4931c6849a4bc81608629a2ef850218f00d944be1ebe4f1520760c09119f47d751e85425eb89e309a45233fd290ae53f052074164b0cc35705f805b611aec389a209a122cb412d1d214f11314e427a931b5a82f49dcc4ac0ca5d347f49146bd6b35c62dac7689abd60be0399f045692484289491644ba9963510ef2c352a0e43c9589c6b52215c43ffde82ad868768c2da59727ffc45623eba8e3397995382471a60f4a82985987c110eab255cdf4319c88481e87f1fa80feac75eb0b626b71064d98a4c9324a7f9a58b023053c7849ee95ea7fe2510a8648b5894298d15776a49d35580122737a97968711ac9e98011c453b27f47b383e6ea46532678101374a2e6a8778e6b3f82212c240050a22cd40554aaea30b04eaf1b7748e7d51da4a1be83070eccab4c2f621fb93983b98940c9926b7d7f51a58ffa6d4a7350c0879546c4025013f952d9c410ecd7532d30b393b9a2bebac155468f48add16b6ca79e887bd5c7e12fafc71fbdda1cbbb8196b56dd3f168ce5e15dce5f0400030582e716056f85c5b10c2c5f4bd20cc6f64e2ccf179ee5f7864164c642d6356e6a89c17c91a0312f24859324b7d01f419691e03b4c198859a6b6b355964fc839c26f101ca88719b004492eed28a9d9c956519c053e0acc0350c2c3c82d4a438ec40033390fde66f2ab7672a16f8d7ae841d641754bde0466fa84b6822dca7766c7468205c12679594812d190153e54784665052961cdfc3fb3510084f44ea8bc47d00d8c7a0683a4178ab5e8725196334488ea9927448fae93ac72a548648d481122f166c8cc902161fadbb2325c2c4d89c79196a8648c49504b7036037337d85788b156865e674f6deed11965102ffe2041a7d9a55ddd53fe368828f6540fe79a4c4a1762dee08cb39524f89c0eb0a2a9246df1f85c1318c259f6dd6ae4dbcf39e91c9e3ba23f809bfd69d81bd749ddcb2bef679bfc6c118853e9736c9b5c808b4b31d254b444cd98c5ba104e6d368007c67e541ff42489d962c5462b5aa325f73e5e34c19998be96a705c78bb47a678f1a57819a887c2f3d64a37e997790f060f91c8b2760348802b1f854731003d21ab8f907c91861cc962804cb80c5cc26dd5802572c1594ce16cc57df24063289c582510cf5ff810ec43c2e0701b2a080d891992372c1979dd8420223cf04cbc401233d1a42fe646f8b2f2c98cd49cb813ab08b729a44f314c35884582d920e564659cef80aa61387029822713c2e868765a2917d8060c0115f5b6df3147548812216fd152ef4520c64e6a89de4a88946f7592dfc9ea20c61c8c1aaff83391fa71e6ce5e06f67e47e702663b137c275f5904e0c21c3b080723b75b492dcd03fc768ea633011ab3d3c4987cc5d96a92c22250b41ccf15beb885cca27352b4d9af
+InRec = 00c0003000000002c00030000c0002c0003000000002000030000c000100002000040001400030000800008000200008000340002000080001800030000400004000300000000240003000000000c000300000000300001000040000000010000000004000000008000280000000040002000000000400024000200000000080002000080003c00000000800024000100004000080003000080002c00030000c0003800010000c0003c0001000080001c0002000040003c00030000c00010000300004000300001000000000800010000c000140003000080001400010000c0002000020000c0001400000000c00014000100004000100001000000003800010000000020000200004000380000000080003400000000000030000100000000140001000040000000010000400028000000008000100001000000001c0003000000001c0002000000002400020000c0001c0003000000001400020000c000080000000000000800030000800020000200004000240003000040003c0001000000002c00030000800000000200008000180002000000003c0003000040002800020000c00008000100000000200003000080000400020000c000380001000000001800010000c000180001000000000000000000c00000000200008000240003000080001400020000400010000300008000280001000000003000000000c0002000000000c0003c000000008000040001000080001c000000008000080002000000001c0003000040002c0001000040003000010000c0000c000000004000300002000080002c00020000c000200002000080000800000000c000180001000000003c000300000000340000000080000c00020000c000080001000040001c00010000c0000c0003000080003000030000c00034000000008000040000000000002800000000c0000000030000c0003c00000000c00018000100004000340002000040000c00000000c000000002000040003c00030000c0002c0002000040000c0003000040000c0000000040002c000200004000100003000080002c0001000080003400020000800014000300008000240002000000003800010000000038000000004000340001000000002000000000c000380001000080003000000000c0001c0003000040003400020000800028000000008000000003000080000800000000c000340002000080002800030000800020000200004000080000000040002000030000c000240003000040000c0001000040001400000000c0002c0003000000001c000000008000000001000080003800000000c00028000000008000100001000080000c00020000c0003c0003000000002000010000800020000300004000040001000080002c000300004000100001000040000c000200004000140003000080001c000200008000180000000040002c0002000040001c00020000c0002800010000000008000200004000100000000000002c000100004000340003000040001c0002000040003800000000000034000200008000140000000080001800000000c0000800010000c0000800020000c0000800010000c000340001000000002000000000800038000300008000040003000000003800030000800034000200008000180002000000002400000000c0002c0002000000001000030000800018000200000000200002000040000c0003000040002800020000c000080000000080000800010000c0001000010000c000200000000000001800000000c0001400010000c0003800000000800018000200000000100003000040000c0001000040002c0000000000001000010000c0001800000000c000300002000040003c00030000400020000000008000000000000000002c00030000c000200002000000001c000100000000240003000080000c00010000000028000100000000280003000080002c000100004000300000000040002800020000c00000000200004000100000000080001800030000400000000100004000240002000000000c0001000040001c0003000000002c0003000080001c0000000040003c00030000400034000200008000180000000040002800030000c0002800020000c0000800010000c00004000300000000380002000080001400020000800010000300004000200001000000002400030000c00008000200000000000000000000001800000000c0002c0002000040001c000200004000100002000000003c00030000c000380000000000000c00020000c0000800020000c0000400030000400038000100000000140001000040001c00020000800008000300004000080000000000003c0000000040003800020000c000040003000040002800030000c0001000010000c000100002000080002000030000c0003800020000c000340001000080002c0002000040002800030000400018000000008000000002000000000c00000000000
+Key = d5492977f04342e5c73557bce8b5f5c5a6c2e2acba0c8addcb834e797642aba6
+
+InRandA = 38cbf333053e5c9addf8537386b88da15212a3a81ae15340f63f194faf1e9f38addc51fbaa72470e210d2a97f8c3b988456389d8a0c6928cbaa2a752d3e2a12d23d2297ec417b003776169d5b5b1198ce1bc10206f9ecd915d680b71ab0f14a87560400c8927492278ce10d6e3470912ce1bb275cc098356dcd9a3eee19704825332c146bf7dea0e02b3ec22802fd706da3283bb2bb7aa58d17c09264bd8dba2776fa9ab08ceed27aed39091d4ca732cdb4880ad35b201d0ad8bacd61015d07fe1ad3c9b1865237a2f28afc16b19311d61b3ba2021a8cf1d733f61e3609986aa006ba6053d1023b1e5a0b797900cfa59a1d5b40ea466830170f5187a4cde089752f4467b9ed487ea85335b4f7b2a8400133867ada22db09d79d478d0c9a88977450154bf74201e020c2458b29ec3d25b94d0992e4f89cca758806aaadee52a592913358da200d006373458cda6dc399d2ee4c765771a6d7e69057345de1047611125a9a04df955e71b3a026a5d5dcda81035470227e5188090462e64a806b9d539c0a13eeb9635710d516a10219683c459cb397b467e0fee4bb4d4d060d001093b93297889499c3698428107aa58f76c012d0e95d046c2066b94211f005e22a3b5ce5968a8c47a3fa9ead41e925356820b85b12ca6d588525184ac72ed2de5aa24e2716e944dd20d3e22e0c10b163c007aba809f95c6e4a1e6ddf0f4515e1094ecf7426a747f1eaada64b6ed1df26ff3e474a1586a090247558e050d162e1583151cd9694cf650208d6d600663ddda518fd7438036064c925bf5a5398e4f18aa90193100ae980b3c2633f43da46f1cc8a19c4bbc6b4cc0c595aef60254cb96350e105100715b084c100a5553337d107cd78444b1865814968303aaf28ed9c2edd7effcb51ad73146bf4c8900a15ff60449a19566b8ca6b4a75a76432c397d81e2eabec411ac409118cfe53b25041d146a5f8e579bcd59978a5afce582a519331a325b4beee5b4361199bfac6362bc76506138ab9fb38b11e01d6b78a2266b2f00a329a84a1873bdf85fae39d29a714c0d891d9b31647d052cee828a902b268eb593aeac0c45a55cea69c429040c5a1763c0f52e394fea300108476968529c24cff510ce92b97a6d2620946bb3c8ffbb518da2bfeeb69e7cf41b1d39859b24824b3f792f8758fcd295f21c3d6e428281a42a740f67896454ce5d50d8e984c9e0309828d303bcb2117c31a10a6cc7917c8ba803c464d06a2ca146d6e9e666045b78dd385356be976bc0963528b7a4a42524942a63921245a7a089ef92aba50afdaa629ab470fab604ccc39869ec496ec2c2a102e1871a54c5378880f05c380304067392629d5a1f121674ae09870e082ff29a1269a22ee9316e889071f21199a36e522baa3bd43e81186d217b57a022045c98f2a6b9a32b9dc9ea276256900feab7ad036c53202297667fdb681e996cbaad03269a01bfafa74d00f6525f5534fd09800155f74cca1206ae6e6d0e058a0538c5d8480aeb1ef4c755b21222ec265de576316b63829ed37cca935e154f10580c05c1d8f51fae6d6643c43a9d546b07deb89afd9780c5e7adc0baa69383f6b235b11e87a3660531039e89e00496a9be8088609318e166a5d0272aa473617359840e79c95faf9cd9f08547780cfe594d1aff6352b7d6b1468148bff2c6c37d6660aeae9b482543337b6453f531e805b60526fdd59e5c1ccb83568d65db81c1dabf5afa573a7190cd42ca1e459c145a5430b61eab011e28f965befb658b8844ff7b056777bd80dd2097245120f8e5887750d386b28302a7279d700d3772eee28f3cb68e562328a3226437b55b9b2be81d1318f5413ef15de9a48fa50a344b6c51399afca6a82301cf6417213014a5a45bbcd90771ac2397e19e117d5a92d0b94c71965a001159feb9325b961ae725b0b14722aa3a906b6b076e9bea80d7af7c6211c28ee6a44bd4c2eb6cfa93a332489572968512818799687422122a59ed981f6a3bfcd928f9f0372bf64b4db4cd315597642d80c7683f85839fd57eaf80b1542f84383e04e313b91a6a8798a729e02a530a621b5912a1ccecbfe7da8e067a543526130e06537ca89a20399e775a2e34ea739eaf8e04180043f01d74a9a954a4a5b6b87cfd43fa4e1a9e36beca135e56c23f2756791cf1814d76537074575e18c09a5f68187c34d2223358f59c220b5229f69f948156e9f658d74d59292542ed226b8cd4e074ee6d0d0d1c64a6a9c1765e90c67f35bbbe342120d40826b174a2dbc4566309368500010d289e942d421bee3e7c5b90471ff8b9be754c168ccd5ef640e56bfb2d1628146dc0a752305f41316859ecd263052a90c149cf2003fdc791a1b4e555cdd163eec93346742b8199eb17ad1c66e342b991a1cf950225532e5ddfc8cb0e36d3b390d253a193b955a124e01606f51e14e20c0435a36924a2e79c5ddf12d126c73925a38c4f8109d09737459fc6826ef12653648a52665f80664b147ed544653d3ea09259b511be4c406
+InNoiseS = e5c40729d83a968c6b2ae550c89b6623e77579f20c14a6c8cb4a623b25da3973ebcc3ee5c92a34345957fe5d10827aa05da022a399332066a2679d11e83e00ac2be799dd3eb7a6a4c787e0b59fee900013ac050b77cbda453cfd06f0de51694b12433fdc32e37b16a8e60d2bb02b82101415850212b676144ba4145ef47731af3419fc8e406be62485d7da056868435a8d1c6a52823fd4ff3db975998aba564e7274525407c318a604a4dc1360c6629f9d425963019f2c9d05901e38abfe87ee51e4ea7c8591ed84c2f991669d6454d9a1b3b88e41e9309e94ae8fa797a91e27fe08f09a2c5e826b44b1626bc88098a4280428c05ffd8129939d450bd912784ae55e13c7044bc593e9406c1ec0c262ca59f225f60a812217471d1fe6af221c98a43135f6f6696441f17b698d92702f811702ce6b292e852723d21f996675c77070427be30a70f8fc8decd69c94c19c88949ac9b528261a26a77016952a7e91a17ea81be4bc4f2175d8b44835472e1606d0059a2e4d86c236cd9c8f27dbe9fb71800b5c335862f62acd0bafa1aa6821d585f7e6b4a5718a6020d4c53244b99d80718a09621766b7c158ec90cb0dee4bd630a9264a49db854e3af0126b17359842956ccca27e498df495c220ab9968000c021a7386464f958f8691a66c671186a26e484f04e5b29112e409ca5f366091d69ab4492f52e8f6abc7e561394ae89ce050bb776b7c3cb3c334f9e5da9fd3af1de2c68a2109ec683976a24cc4255139854c4a482fb8555e926c41a96db8f62e62f4ae6783bb48622a8e2373c7b0252dc40d52b1713fc48b0058b1f65a0fcdb3b8d07c3febd7eed55021773a58e9017aa90934c55f5799d53ee4aef2a8cb2209c01fafba6151be916bfdf15862204c52adcb0da5231408ebca29c02029cfda60baaa5aa09da3f3719495fa8de6107a6d175b030d8b84fe4e5b4f17032f447a20695f349ce8124d868eb7f2dab6820e6f78115c53514ab631f6fdbf3dda71b1be890d12e5bab273a9312d2afe739b6d75c6cb6446c445aa0198eb862748b55de2054acdf0b54bcd323ac6f27f4de55e197f7517210142e179d81afc501a88661d89be6c7e6aabac160704a5b6c1a2b829d9ce7486418fb92cfa23bd1ca3872a0b67b5ce4c62caf1a495bc442c11cdc87c06563d1a73941ae907d46ab77059166dcd11d12221582bb49ae411debc6cf36a9ed3c68643f7c18af0cf107e7dcabbb221cc201023a6156bdabde7e9b12bb3c64e0f0fb92a87ba2c59dcb8a5d48d97fce343ca0e69210b1c4d01897141ec4627e3a7ce05f848c4c558e0af50c36c053b100df69532935f46293a29c5c8e24ca3ade25bb427712f80263b736a6403cdd4c47b284d22ba4575d066d202d498e86b6ec23dba8abe87f63e375b0b6f41601c68fa1717e67b654ca21bfb428a0ca7ff5d2f51447e05a56e550a6790657cc3b0c736922fbd21b491694a64a11f45108b605f06d8610686f2912f504ff07f313edae07930cf8a4e838b0606a402625c494205fdfa764a5a9416853548364b0cd84ede3d3ae49af22f4d01ab127d31264eb8ace5d2554e55290a2d8979aaf88a761582f5c92a19f49ee4f573d54a61a638703e7535eb465bb6fa3a3dc1ab5cc452d826ef6e818a65aa842f1b60c57a50354fdaf1518f4d94c088ba049a5d963105f2a8e0819da6192361240474c5cebb328cdd907a2e04b0bda41c720c23c808a0918e68fb83dfe12684a4bb471eba7a0d48e75847a44042220ab85b412048da1981306d52fc659f34876d16ae89ccba803080b9268a8597bd57f00dcf79012cbb0528f9830864a129a5495879d228ef86fbc5bb39ac450b196a97200a1829323781d64fe981fac57b5228719adff3ee5e72c29af5a18d3e9635574cb65b4086e92fbb1ba62d36a823139955d186f65d05b6bc3915e5061416f548837d532a453aa50eb26848121a3a33aa5604c678249c676c8ec973c558f2e8ef88fb105998550da3cffa09838974403e8610370b2937bae154f488bf31c816890c83b878cacc577f2a3bb256687025c17cd595614fd2e803d1fa2891634772badad84549a71a5ae83e3b9418f6f9f6ca6d4a67d9c30459554bee4ce413091e1ca092a507d9685fd259d5f0b991d0645dc6d48a1fdf8171aa8e4c210c6cef97360155acdbe19b55f000012120e221240964cdf57b09900791e02f5168ddb798e3bdb1056298ef04d00a1bde9653e073e8899530db2d30961a4a58d604ae055ab56e5a0dcb77403a41e51b5d0895c675900c9e253d1851e9d87eabf235056bade602f0952ca1c8dbd5cd4a59324d5dfbc309518b5769926a4c7863c51db8a4249c6fce71c92b9c086c217f987a38569d923b01f58c3c3682a5a796223f89c7262160226cd8ef3730ec71a43d4e3053b2f15b855e3934501a90bfc6bdd9c3d6003ce2d86076215ce2db3e31bdd2266c8693e020129d63576617d3c68127608b7566b4be9dab7576b4167fa0cf610180153207d5ff9413488a
+InNoiseE = 4dc2a8f9bbe84e148d7f5389a5a28bd7162a43aa2e3e9415d944324e10c17885d0856af0495cd531401e6a970a82d439943b6ac520527c2afc2f3cbaf4d401178b9293111d76a14bb1407ad61e05284f6398020ed2db4ab42da6abeda9b9f631646ff2eb2300566814e225332580cc4c5068eb176509703d188e39354211a6944e125510006b972fd12f218efc8f231200c1062e91e2137931a125d2cb4b4e0d129a275cc766351d7961a589d0c254a19651073a456a80e6e59b28b00a5413eeb9e9e57bee93528388749cd2c08b89e5d1674a07e7247db53ea14b804413769be256ad01de518192c0310621a26bc3809313c6c877972eb9b9dfd91e27eb33468fcc99c14012f02ee67ee6479886fe208eb41b47d03d9d3ca3138cf08f2a8d9064a1c94e69ae5d8fcc5181bca3556bebe67c09ab47c7237532c03ebace244854b25160d455ab00b93bf3ae4822118c9c49aa42e149523a2c6badf8feed721ad8d6e56b26a0ae6836ca486e00a24c522a9544140701519b5cbc4392c72cf60b6c5e85d44ae4ec2077971640f98b361fd09e16252ff02dab937308995c8a9905674761b408a38c5fa6671583844bfcc5e0041088450940f37d5880999636a1fc8fba69264bc79482d7a4b2fa33467af8048924870e6e97d660b58d01b85d501f2566d5150aa74e8b7b0009a14449714d4e34de2fd7a87541033d1da5b7aba57081edc539837600239a870669f52c45de3585b0710f2a645d1807c1b9526df45445857f78018067f65d051a5fb96413e68792647b8a94664c5a2430f4b4e280898af079c1b95a456695d21ada7540af9490b109507d48b563bea1bd214988d7241a18af9f85901f4974b45afe7520ea31bf97c958bba2022012d755ce8cbb1701e7d730fd48396165309321bb2f5c45c9c8a153d22366849304277050dc31751d21db9fe6831c8506769eaa5a6bf4a1ab0adb72b5a003d75187d906e679b06dd63118a91b37a3748544c97eafd44fe5c90abec58acf93762471ed6b51a330082e624655d7846273aa9a78f667e47d4fef8c0981dd28896ad516288c85dc476493951a4cffdf8aa3ad706a4e6425b3870a5b27ce517afb1aa8808092bbd7161dea9048c9015ab10956f4c0b9e88b6c86325b5e6571df5d3c382dd94acc55ea65caf452bd1e3188c694b66924e793ccac23625cc7033cc2a05991d8bbc71e5c7c851871e2da8af241e198c3285946ad1603dc7990ac0f436a1bf2a8ee009c53c8e51eff9b3fe69ec4a5bc661a98a82074bf41df22362a32aa5318a800563bf40b413740dc1e3c0b20f160d804bb147ec55f5e09c8c834b78a8120e80c95aa84de5c0459f702257c6ccfdbfcb7a996970a0a3ed0e72ea11e09006a47a8424a494b383602ad9daad233befaa70598d717d52cb7e44be1b3ee4e948727cf071a8cb05e54a766f54e7935aaef25138db4d4468d627f9a090a689a7329718de61efa323645850685ac742e0e7c725ad006fb4a7209d2d1b7845e344b2ad9c29bf979bdea397a8d3097474a20c2fbea8071665942536a6e1f2c3bd7b54400259b3210147610c12047d705cc700e1f2d7879fd63fe69c554b64e02c76a4a1ba4c23b7f4e6fb000ce894598f27049f9ba0c257d5160e27b214ae151da0479f1069df0f4814b4b8636d84c0c963d2887a41cc867209c9fb219bc9847c10277f80d32ae40f88060f651739c77689f3640f1eba789a254b0cd191b61c82a48afaaeca4194031e8417cc0144d63c4643616dd2215a980236a02c60f8e67d7a42104949d4a1ee8d38cb88cc7a6b5674904984a894966e673578105ab3274bc3b015ea992bc6a70994e845669858b0062c0d1fa6defeb64c3d3e0a8a49e4de6892980c85a901295a479475438fa59b103dd1bd083d79c193a89db61d18c7d2d8410d5b63d3c04a85464713e8a856abb17aa1c935e5e2c791b0d5b2899bb2088127fe8907b7390f1bda841f48632561bbc2ddda6f2d01fac069629f63e1ef0821b388bf86966e178d82b3e9776a47bc011091c5e02dc12617c681be877584129617781a1d2a8b8a905e124a63620ad74cee68bc0d1a0cb4bda493f353c93200c533bfc6c94800e88895e045e09f6d4faf662468143955858768150746aed404d3e81a1f34ef9083761b1393b008ad524a789cf5da8862cb66b70a800f7a84e7aaef13456483d4ab8e8045659615237e6183f4be799583822b84bd397e7cc9af9865b70443679f52638910e7d3ff5c7497af2054e31927032e47d9b3a5fbae4613853061fecf8cc3d46a04aae5277021b0f2a4ca2cb6027b66d8d17d8089780a39794126d75744b7294775ca0675e3a32f7b62ff0ea6b033c0e3f77e39bea7e58b86ea0b973923295a7262b71657973f69133470da2565f4c4f3b24ec9bd5c309eab95db467a355e8cd385fd79fb766cd9d97a182438a56e11b08a3a57bf1aaad1a465d3557ba552a0168d4744d6020020b312eed92496e5a4502650c1529b5d549b98f59dd7831033e41
+OutPK = 41aa3310e40a5c72e000a825b951fb43b8145b3d240dc83aa705fd81a585a0b20894b09bc641244008319d5674e3dc916955877d153c3d9c04236e5513c67d535c704922ea0af16cb02423e0a8831104f6533c98264fce6a59d055ddc55e15a986667cc8c46397e6831850ed94d3416c320ea1502570936b9ae649d3c22a6fe104c30c15a6a915c6416ed891016435c8db948cf796a99189fa8c1601d1ca03b93bf80bd47591342c6dd9d976c77ea631e2b0d15eb569f2d9cee48d4a4e7de8c17a5f8046dc83f83916fd6ced61cbb6a2058ff22e685465e5ba97cab0312f5669d458f7d596f2171582afea02549766d1aa09aa39054080b174574875ad0579da369079565ba413a360198f92f1fb0a3d3ba467c3c5f1218bb6a9cb94373e1e0d0bddd53d24bd05c101db21b2b41a8b20822829bbfbdd3a93821c6facc547152f71771492a0c2c709aa541b5fb0a43a50d9ac5fa414509d09d448f4f271620c1159026768bc46ea9364e906571fab6976105d34ae22cf895fcc087461706936ee0a0ea4a8f9b73039cf18b874a7582ac3af68855e1e9d8928256158b801ca93178a16ac0f61c6d0234549abfe1dcbb9386084295d43a4324ca3015f575235285e6a97a125fb088706dd0bb7922194631cb0b46fb11e66c5a2f753aa3812d74c62519230019f6f27759dad24ee2365d3ec13809c920abe9c587f817d265e1d1c551fb917e85d53ded3e530afd648f72076aa0f396d41d824dbd46a79ed2e276b0025bc49e4b738cd166ee9134b1366558ed3a3f838b6c55f2bceaa6b6a55ac181d591a5c3d69cd4be59a7ea68de6e00ae238ee37475c0221c2f0785fa3deaad4eda01505480a171095206794330a004c37e9c0a9af38936bab9bcaaef2496eeac863f392295eeb6fd793f681c39a3b255f4e91228ad9d6831039da8b9948da25b830102b8468be17a5a317732bae56f407a575e8448084516202435c22d42b1e08e8b127498f3f50b99e08719e4595ebde9b54a76d7b8e145ec48002623580be54e99c4696bd4c47d28f96079596311f7ee7951513040a9449f2a806a04f20e4d5f25a23c84f40262ab0f144ee2956b66c7c8e2c38ff0c0a29df461080cea94c470f90ed1635340949280ab15e9189e9f054e5a39797a291c724162f64df6a4ad93b3a4f80845411124fdfd61320a4176c04cde3011a770add6870e36c0b8594083ad7d1246a22ba1611f88290138d79f6249fde82a920fe95a0c3d1ac017ebe55205eef41a8c01f5813c05a70c11908a37546e4101af12342c70cd05d03a1ec5404ada42a2d29a9fc8811805e5490a0317e1667dacb21a9a1d2489816cf1e2deaa2c708b5b03216cf2350546c062bc6e6e81b52a851826e9aef2e4ed55d18e99f8401c5db7709f659b808007c847e90754cdd7c55d850b0fb5077fb606867e3e00b9b109552a61cb187c6416e0729a5294f4e6ebf892be54ece31c74507237edc5884987237d5c270f52a86c429781648188479268e9e7eea00d12f6e321857d7948d388de52dc5d52d46b606848ac970c8ad49610ee8785470f71a10cbe3e48bdc497e5123890e1a93586089cd917a14fea4e4de89c885db8bafd2615a6855e1ca1a303443af75ef9d1239c3465bc9e0b2880b89b0d0140e11c147e894fa1096e75c4b863e69ef2f2c45c4087d40dd64130b58739e445bdb141a7f39d7d9a2032da8bbecca12d5aa1a718040834fec212f139d8aa4f50ee5159ff5102c2dad585ce19c8972b215f761e87d71d45174c4486a2c43a4435400b986cf8727c2e2009127405e39b85e1cea1e9841912567200bc6e5b2fc52ac0b895043228292adab063ba81ed049f5e1e0749d3e025ad16459b4ca18db00ce61a164d9d352043a6f44e8e7949c393a0aa56fa0bf8d065e531cf570a09e1f21b6c7ee507d6e803999296576bd243f3410e42adbab7e19a3098ad75967c248dc0359cc68a5d6ac1c6c81fdc1c1f6a00f530aa2facc51b0ab9cf8f408afdd2967dacb586b721a54f7363d87f1af0ed354d017b567ae0b2440279f4c5e237360018194a8e38bba66316d7634f1002d5d245e5019ad08090a35b732e84aae82ef9bb329286661f9e5218da95a6deb6ab7416b551361444ed890866a8cbb70ea59b20c05a64fbc94efed92f72faca2584d779476d41c5427d9119ebd6d94af6ef9306637cc4590f705dc5f28007568c7748d49248483cca2accc1a6bf008668878c853a1d09c247e0c3854dbf55647ae9ba2194c4a111c99e032f830b69b9ef8c45a864c23876343ee870290ff33b8241a4a95808a0fd17217af5803d5f83e676d29914290ad98addc43f77a85fa6623b0a254af2a87ae677c18029049a225681da84ccd9d37ddd50b8a205c7b9f2e140256d278c4c858ffc9fcb5d7c2aa302abeb15c6c227f5a4508dd0579164264fb953487f5a077d9a4ed2fac17dfe22012a327ae89a1e6b99133ef6415ef953056117f9b476d58d6865f577d65576559a03660a912789870fbd42520
+
+InPK = 41aa3310e40a5c72e000a825b951fb43b8145b3d240dc83aa705fd81a585a0b20894b09bc641244008319d5674e3dc916955877d153c3d9c04236e5513c67d535c704922ea0af16cb02423e0a8831104f6533c98264fce6a59d055ddc55e15a986667cc8c46397e6831850ed94d3416c320ea1502570936b9ae649d3c22a6fe104c30c15a6a915c6416ed891016435c8db948cf796a99189fa8c1601d1ca03b93bf80bd47591342c6dd9d976c77ea631e2b0d15eb569f2d9cee48d4a4e7de8c17a5f8046dc83f83916fd6ced61cbb6a2058ff22e685465e5ba97cab0312f5669d458f7d596f2171582afea02549766d1aa09aa39054080b174574875ad0579da369079565ba413a360198f92f1fb0a3d3ba467c3c5f1218bb6a9cb94373e1e0d0bddd53d24bd05c101db21b2b41a8b20822829bbfbdd3a93821c6facc547152f71771492a0c2c709aa541b5fb0a43a50d9ac5fa414509d09d448f4f271620c1159026768bc46ea9364e906571fab6976105d34ae22cf895fcc087461706936ee0a0ea4a8f9b73039cf18b874a7582ac3af68855e1e9d8928256158b801ca93178a16ac0f61c6d0234549abfe1dcbb9386084295d43a4324ca3015f575235285e6a97a125fb088706dd0bb7922194631cb0b46fb11e66c5a2f753aa3812d74c62519230019f6f27759dad24ee2365d3ec13809c920abe9c587f817d265e1d1c551fb917e85d53ded3e530afd648f72076aa0f396d41d824dbd46a79ed2e276b0025bc49e4b738cd166ee9134b1366558ed3a3f838b6c55f2bceaa6b6a55ac181d591a5c3d69cd4be59a7ea68de6e00ae238ee37475c0221c2f0785fa3deaad4eda01505480a171095206794330a004c37e9c0a9af38936bab9bcaaef2496eeac863f392295eeb6fd793f681c39a3b255f4e91228ad9d6831039da8b9948da25b830102b8468be17a5a317732bae56f407a575e8448084516202435c22d42b1e08e8b127498f3f50b99e08719e4595ebde9b54a76d7b8e145ec48002623580be54e99c4696bd4c47d28f96079596311f7ee7951513040a9449f2a806a04f20e4d5f25a23c84f40262ab0f144ee2956b66c7c8e2c38ff0c0a29df461080cea94c470f90ed1635340949280ab15e9189e9f054e5a39797a291c724162f64df6a4ad93b3a4f80845411124fdfd61320a4176c04cde3011a770add6870e36c0b8594083ad7d1246a22ba1611f88290138d79f6249fde82a920fe95a0c3d1ac017ebe55205eef41a8c01f5813c05a70c11908a37546e4101af12342c70cd05d03a1ec5404ada42a2d29a9fc8811805e5490a0317e1667dacb21a9a1d2489816cf1e2deaa2c708b5b03216cf2350546c062bc6e6e81b52a851826e9aef2e4ed55d18e99f8401c5db7709f659b808007c847e90754cdd7c55d850b0fb5077fb606867e3e00b9b109552a61cb187c6416e0729a5294f4e6ebf892be54ece31c74507237edc5884987237d5c270f52a86c429781648188479268e9e7eea00d12f6e321857d7948d388de52dc5d52d46b606848ac970c8ad49610ee8785470f71a10cbe3e48bdc497e5123890e1a93586089cd917a14fea4e4de89c885db8bafd2615a6855e1ca1a303443af75ef9d1239c3465bc9e0b2880b89b0d0140e11c147e894fa1096e75c4b863e69ef2f2c45c4087d40dd64130b58739e445bdb141a7f39d7d9a2032da8bbecca12d5aa1a718040834fec212f139d8aa4f50ee5159ff5102c2dad585ce19c8972b215f761e87d71d45174c4486a2c43a4435400b986cf8727c2e2009127405e39b85e1cea1e9841912567200bc6e5b2fc52ac0b895043228292adab063ba81ed049f5e1e0749d3e025ad16459b4ca18db00ce61a164d9d352043a6f44e8e7949c393a0aa56fa0bf8d065e531cf570a09e1f21b6c7ee507d6e803999296576bd243f3410e42adbab7e19a3098ad75967c248dc0359cc68a5d6ac1c6c81fdc1c1f6a00f530aa2facc51b0ab9cf8f408afdd2967dacb586b721a54f7363d87f1af0ed354d017b567ae0b2440279f4c5e237360018194a8e38bba66316d7634f1002d5d245e5019ad08090a35b732e84aae82ef9bb329286661f9e5218da95a6deb6ab7416b551361444ed890866a8cbb70ea59b20c05a64fbc94efed92f72faca2584d779476d41c5427d9119ebd6d94af6ef9306637cc4590f705dc5f28007568c7748d49248483cca2accc1a6bf008668878c853a1d09c247e0c3854dbf55647ae9ba2194c4a111c99e032f830b69b9ef8c45a864c23876343ee870290ff33b8241a4a95808a0fd17217af5803d5f83e676d29914290ad98addc43f77a85fa6623b0a254af2a87ae677c18029049a225681da84ccd9d37ddd50b8a205c7b9f2e140256d278c4c858ffc9fcb5d7c2aa302abeb15c6c227f5a4508dd0579164264fb953487f5a077d9a4ed2fac17dfe22012a327ae89a1e6b99133ef6415ef953056117f9b476d58d6865f577d65576559a03660a912789870fbd42520
+InA = 38cbf333053e5c9addf8537386b88da15212a3a81ae15340f63f194faf1e9f38addc51fbaa72470e210d2a97f8c3b988456389d8a0c6928cbaa2a752d3e2a12d23d2297ec417b003776169d5b5b1198ce1bc10206f9ecd915d680b71ab0f14a87560400c8927492278ce10d6e3470912ce1bb275cc098356dcd9a3eee19704825332c146bf7dea0e02b3ec22802fd706da3283bb2bb7aa58d17c09264bd8dba2776fa9ab08ceed27aed39091d4ca732cdb4880ad35b201d0ad8bacd61015d07fe1ad3c9b1865237a2f28afc16b19311d61b3ba2021a8cf1d733f61e3609986aa006ba6053d1023b1e5a0b797900cfa59a1d5b40ea466830170f5187a4cde089752f4467b9ed487ea85335b4f7b2a8400133867ada22db09d79d478d0c9a88977450154bf74201e020c2458b29ec3d25b94d0992e4f89cca758806aaadee52a592913358da200d006373458cda6dc399d2ee4c765771a6d7e69057345de1047611125a9a04df955e71b3a026a5d5dcda81035470227e5188090462e64a806b9d539c0a13eeb9635710d516a10219683c459cb397b467e0fee4bb4d4d060d001093b93297889499c3698428107aa58f76c012d0e95d046c2066b94211f005e22a3b5ce5968a8c47a3fa9ead41e925356820b85b12ca6d588525184ac72ed2de5aa24e2716e944dd20d3e22e0c10b163c007aba809f95c6e4a1e6ddf0f4515e1094ecf7426a747f1eaada64b6ed1df26ff3e474a1586a090247558e050d162e1583151cd9694cf650208d6d600663ddda518fd7438036064c925bf5a5398e4f18aa90193100ae980b3c2633f43da46f1cc8a19c4bbc6b4cc0c595aef60254cb96350e105100715b084c100a5553337d107cd78444b1865814968303aaf28ed9c2edd7effcb51ad73146bf4c8900a15ff60449a19566b8ca6b4a75a76432c397d81e2eabec411ac409118cfe53b25041d146a5f8e579bcd59978a5afce582a519331a325b4beee5b4361199bfac6362bc76506138ab9fb38b11e01d6b78a2266b2f00a329a84a1873bdf85fae39d29a714c0d891d9b31647d052cee828a902b268eb593aeac0c45a55cea69c429040c5a1763c0f52e394fea300108476968529c24cff510ce92b97a6d2620946bb3c8ffbb518da2bfeeb69e7cf41b1d39859b24824b3f792f8758fcd295f21c3d6e428281a42a740f67896454ce5d50d8e984c9e0309828d303bcb2117c31a10a6cc7917c8ba803c464d06a2ca146d6e9e666045b78dd385356be976bc0963528b7a4a42524942a63921245a7a089ef92aba50afdaa629ab470fab604ccc39869ec496ec2c2a102e1871a54c5378880f05c380304067392629d5a1f121674ae09870e082ff29a1269a22ee9316e889071f21199a36e522baa3bd43e81186d217b57a022045c98f2a6b9a32b9dc9ea276256900feab7ad036c53202297667fdb681e996cbaad03269a01bfafa74d00f6525f5534fd09800155f74cca1206ae6e6d0e058a0538c5d8480aeb1ef4c755b21222ec265de576316b63829ed37cca935e154f10580c05c1d8f51fae6d6643c43a9d546b07deb89afd9780c5e7adc0baa69383f6b235b11e87a3660531039e89e00496a9be8088609318e166a5d0272aa473617359840e79c95faf9cd9f08547780cfe594d1aff6352b7d6b1468148bff2c6c37d6660aeae9b482543337b6453f531e805b60526fdd59e5c1ccb83568d65db81c1dabf5afa573a7190cd42ca1e459c145a5430b61eab011e28f965befb658b8844ff7b056777bd80dd2097245120f8e5887750d386b28302a7279d700d3772eee28f3cb68e562328a3226437b55b9b2be81d1318f5413ef15de9a48fa50a344b6c51399afca6a82301cf6417213014a5a45bbcd90771ac2397e19e117d5a92d0b94c71965a001159feb9325b961ae725b0b14722aa3a906b6b076e9bea80d7af7c6211c28ee6a44bd4c2eb6cfa93a332489572968512818799687422122a59ed981f6a3bfcd928f9f0372bf64b4db4cd315597642d80c7683f85839fd57eaf80b1542f84383e04e313b91a6a8798a729e02a530a621b5912a1ccecbfe7da8e067a543526130e06537ca89a20399e775a2e34ea739eaf8e04180043f01d74a9a954a4a5b6b87cfd43fa4e1a9e36beca135e56c23f2756791cf1814d76537074575e18c09a5f68187c34d2223358f59c220b5229f69f948156e9f658d74d59292542ed226b8cd4e074ee6d0d0d1c64a6a9c1765e90c67f35bbbe342120d40826b174a2dbc4566309368500010d289e942d421bee3e7c5b90471ff8b9be754c168ccd5ef640e56bfb2d1628146dc0a752305f41316859ecd263052a90c149cf2003fdc791a1b4e555cdd163eec93346742b8199eb17ad1c66e342b991a1cf950225532e5ddfc8cb0e36d3b390d253a193b955a124e01606f51e14e20c0435a36924a2e79c5ddf12d126c73925a38c4f8109d09737459fc6826ef12653648a52665f80664b147ed544653d3ea09259b511be4c406
+InNoiseSP = b1854163d7624f012383189759bdcd5ccb464ded5d1cd229a2c4fd610eeb3a568e2900ed165616cea24d09853c0ab8658ced40e7751bf1b34ae4c9896ab621992aef37b9041446a9a3495cd942ff266a04c5b9039b5f18420f51b976a1b4d9a81095f00d4cb4e87144284df1a470c25637ed724b21da34206369bb7a5624e341449421da69a3464451c53c3893919533443594761c30da94ec8295807b78e8ac8e80d05e745375a37f9027691b2a309e85d255bf7c06178ac212b90d1c3d262d9bf6096c5d806e39ada889afd21db68d6192a318a2fb09288c6180c7c4843129e0eb9db966aa317d127d4318f9a677e95294283452f8612635294a9fa31cb08bca6d4dc0a3e2239c753301080c4a142d08502fe898b288bd6c4230046c103103aa3cf84a65860951a0fbb990394aa03035b6d49342a57a86cf687860ae0f70544aa6f2020ee558e5911161b793d1764fc55aa2098de4bd9a6749ebf2298c9941de469b94891004ae06d944a7902f02093b404b684f5c6bb0b000bb608ff2b7a904f7a266aba00d04e30fb915d40893d411b91a0785a037477f344aa02a57e81ef7b88d49f6c0b589af5152cd16492b5c16a3cf4da893452ea4986347b22cbe8ef48945026ef68f822af9f6e18ca0fe403e12a1ba187412f2e6c4e59f2f0ece65fc4d45ecc7f47a058a5a55e503cb5a485e23573de071388365a81e76f98eb6ec4203f346e0b670d29464974249045239e119f545ed6a6f57c5e80ab15266c2a87d15418ab3588c218477ceb65679020f0a96d9c74be12fc064b999f5ce7a24e36d89b6714d3dd52af3145849689dadf603f2bd7ba3e3127a4c03ff2a90f7f1cc1a4388a05a1b6098a6236b32069c0f5baeb8b2be20125d80e9f3576c5b114968e1d9c43159a281a9c70c87291f6646f3e2a28796898132218890a62cd799fd1bb14b979a0758665c11b7a690dd05dd2e59b68eaaa98ee1fdc6aa111fdd2a11fa1150b99b10ad47ecdd6b2481dd63704c56cfad7ce0e7bc64ea169bf25f799a279bb12969683fe493069b7422bcefa49b12c964700a66dda50e525ba04d4f0be93aabb7e0b1335888a5de0e9c431c4592fb6d2384322c26f005a7a3134ebd48a5b299a94d6d7ae4d37438d55f69101b457a7198cbded8ba2f5d85360b70fb1476bc80281c77f4cc5b9521aa52e01443f09e30a0929a8aa804e9f0f5b52b1fa0c805d604989ed3d9cbb1c66ea8a7e160e9b01d0d642ecae2b91548023e41125e5b96ddccf5f35a89b4c0c79a7259614921b9862b6a91674d49a8353c63f89ad3eae1ea5040d176e28632209f5dd2d37182035d0b34b2d2fd49ab1b3885d55180691ca7c93bca936dd9f7b71c741b7eabcd71eba93b6cc8ed29de343e00a6a7a74ee6913b160bfb8ea4897fa97e2b8f2d27456bf945c121b29ce9e8c4749d14161f65d2dd3db0ca1f2f853975191e48aae5b7e684fc5ab599ed11b83b61cebba59e4ffec46830ea1cb11e2b5075f0ee4b58538048c62241f2d73baa39fc8223268f818660bb9b96fbd42ea50f7e0199760ff07254e913530a112f7c2b35a7177aae3c9f60d8a62238979d2d81988d084045abf10790beba42ee8b07a006098bdb42cac11dea20f5e2981880dadf42f59bce784f130da97c645c2f661b8167f1435ad8eea3e004459e0d5628bca93a390a530b70148fb51ca130dac87f96559146d66010d54820f525d469622cf13a5a8a79f09a1088178e39e794ec756ee15a351651f6fbcc4cb786f6d60e1a53cdc5251631f84e6d6cdbc9e9dd41165e4872f6ee35c0d8b6db7dc48d6384a9287f65461044d08be3c29f2708a57496fe966a659db13d496ce16c39c34aad76ab80a330726078a0a8f9429ddd7e9c91c2b3b1594044a658e3f46e3a079a98222a9a5074883095a6717ab807a4b2b77a4894c5c6e0dfae62abeaaed26ece6b29553413df7448fc4e40b7311e3bb556716ab2c921d36b1ee7e65111c6224c300e466a259309c39de94a7d5a32764c4259add929900845829c91a677fd39355e2d3392d0c547875a43f05f3819c1ed74a86a890cbfa8255645916b62a1dbeaaa5d94e80f54d831240ed266e07bafa0780f92fbb147109e2a65ba6536d01154cee3e577ae2afb8a3a761d9169b5afcd322f85558bd0a762be2821a1290af2c50c194a2a7a85aaaa1d68c11642de8a3c1a22674481782f8847b8330ee4091a281e9bd3e4a5925bcf54f062bc4aa20780497200e61e4bd537e0515fda23246c04943d0d3b59205c501610118ac73c2f33e5b15b3c49123e9e1be9b6b8984b13146497b53b48574b85c376565c5cf8e82d0049f3d591e652947fa027b011fd008042ae6cdb7c6e3e55833ba0b0a00cc1248405b9d90a17cbd022fcb049c0cb6f0516c2a566eb776be7194df155e3ba46f10ec3272f879dc1186d2b8851b938119656c563b95d7977eefb73a1929991c0f413b99049269597796688020ca0a6e401263ab5691934a3d971aac2ce626b811c7c1394237f3c91
+InNoiseEP = f3add13126a14ead16967a55997c47a25801efca5d3a8633f38ca2bacc15aea13b784a90c920c0ffe1519e275f8051fe6133ca42b6184899c44057c686c24b85e2341017714d72231f95105209269c6f5a6b1c6b1fdf0e82048d9b5b8ec355996aab3fdf5ed55e44b64a48d0421dcd69464568827a3206f41aa0f444b2b197025d03b9dea0c442ac07137e85854239248d080f3e9f4aa8ca86039d519d45b2d424e5928ab6b39a6658e65bc119006672daa2cb0c54783e455456c43862d10b050a2d1611144d2b5b21d6668129ade5ef1165ba58e0769c2d31fbd19ad144cc38566e243b83362d51c8d72937e54d10db9e4428f4aea5ab7c22d22d07079698d671a8b7b58edfc181d53fafd1a2c0034d8c2382807b85f82f9a025320ea7d768da0cd03aff8b7eeac270883cd27dc664976e301524aa8eec82da0163cd6b8b456881af113349915c5ae9515156bdb820018c6b895c2357e93e2e1b04acc54c75fae61ce1882666ad3a95f7d10b32c73f2c3f97d215c34a36391059742b597e0c26a30103b8824311500dc416a33c68328266394f16a57b684c21b2b785f77eed6e7c5ad1f7967b6095912455c48cd96b6a2629a82ce277c3a0c2b01bda0e02d6c201b2f249e6d4ecc910fa38c6d703b868a637f050da4c831390bba28b65f39d48824bbe88402c6794a2c4f0b63b713f09c69592cc79b7e5e5b224fb8a38c9c2581e7602e5039b64ca7f468e99e1f6bef7878842d5ba1cbe54c5dae6ca7c360ea8488681bf48850b805bc82a1d07bf630d90188aa68cd1edfc22df57bf1abed5a10f230f1089a40c531a841a15e094615c732a42a4005c3815d2d272711079124400f23e9a7d0f112c5db8f02b958621ce6c7d6010c35249fc5c06e2c505565de5708a6448707c9a5ff0943b709c046fb2d00c5e2b4b356f15bd0ac0d2af0d237134acc6b2ae5b2d9436870aebe62f26415966695a42011bf301775340f52c7567924b9d4e977b8d03121afe7b5f111d9a5a6235f054e8a98078d74d4ac3a6b7d4b5b555e6d870c032b8b4d451898abef511add7a235c6aa3d62e2b40e757b876c6ab7addbee704cd39beaf3164495a95de5083d4a26833f3a75e397c58598a5e484be40544ff1def8329806948c94238f5ae0f38d4f287748ea04e1c74e7b9f45ca426cdc8aeda5c940d7c3940e68926d4523a5c4ab89fefe9109876064fd710bbbb18b24a9f149a8752a28d4284346bf1b76382ca69f000a6d8052200ad202464d44072820c3f012d280b310951d2593624b80485504bdc25749e166d929824057869a763f9849671a349267b8ae75a7fb1274b53f02d3f8f98e822ad1461d35faa83433a1f2e0eb3598ef23f0aa765b6f96506fe50be77dfac62ef0f74d0db752d0ba8a0586eb51d14a83e69ce197318c08562b3727597ceb25b48fc395211c262f618590d834c602b4c6e81c93fe3f8558272e25dc6b184a01f8cb5e5b7d66c102c7a47fe55535067690440b2895bc96b5b73ea2fcca448e9dd389b725e91c379f296e313d6e44c40b575aed932fe628341c066f36dd8053d81776973448191a3f2b5cd8c52e3a3a7416bb234a59ddf2567ae92839e1a7a71aa0d175f0503729a1b6f5fac31ba5552ad481ce0ce8208ea98ea3a33c1acdce0c31a45f06c8c10cd4127f24edc116a13db464a7fa00ee7f92629918db067ed9e4830ccb830a95840971a492a838217dca136c9149c2f245cda65f58c4996d12639049a648ec6845518488e1ae8f4d23c14102b9d90b38b6a1b47d44cc7fb458a230e59c4d42e366414b6577bd567c7ec70d779ed277ea4d3e7107a1fd20d9ff85289bc7d626264544aa8b24dee58a94e12871b23ab97945f630a6125037087924399a8a60c8a66599f82c1c496078ddfa400e0be15a41849d940a8941d10a322d951b98522cb30426092c5419882e06fa0cc41119b3e540e240c506d2898305b5ed2c9324310c530d67a7072870269aa338db4a26551122f62abe129fcb8f0163975cb8636360ca331d966902b9d28dcc016549942310209a7c64f261e998f6421c074007adee784c4beba5fc2f1c5a9a6a40907dea8dde52c3c99b330cede97e06a4421bea9a073808d351d2d411d63d1ca113939ada555263e455c7e19a1d8c9c271fe402191dced3d0c01718607185a329e42216de02d9857da9936f2b2bc47076b6bc92672e831d66060a5bed6b077abe2301a60376418a125e9216888f5e151858c3ee799794ba347f5b26c18608c93f2b09d0e87d8ad03521c1100181581e617a23466ae3496878cadfe5922250226403c0706204161ab546ff9875c910b694c69f0d3c08a901fd3e8f79e052feb55d1010c58d590b8295ec6b09f586577ba1e2f900ed856140020aaa1f8e25945bd91add9b0109a38f75fc886ab422a37e673206c8612861e9093d2f20293c7a42346b05e32d14f177f8586c74492e0f27e04376f88c61f6c27c302f5c5866d96a36c53d709b63aa94e14ba4fc43e5c8edb93cf08a1
+InNoiseEPP = 00b000000003c0ffefffdbff0600038000000000c0ff2f0000000c00010000e0ff0a00038000000000000040ff0b00ecbfff2f012000f0bf000000e0ff12000680ff1b0008000200005c0010000180ff3b0000c0008000c0fffebf01c00060000000fd6f004000080000c0ff0b00fbbf05c0002000080000c0ffdbff0200ffafff2b00000000f0ffcbff06000280ff1b00f4bf00f0ffebff02c0000001d0ff0a0001000050000c0002c0ffebff0e00fe6f0010001800feafff5b0000c002400020000000003000200000c0fb6f0000000f00020000e0fffabf04c0ff1b00f8bf00c0ff1b0000c001c0ff4b000800fdeffffbfffabffdefff1b000c000000013000f0bf0080fffbff0e0000f000e0fffebf0480ff1b00f8bfffaf003000f8bf06c0ffcbfffabfff6fff0b00fcbffc2f00400000c000000130000400020000dcff120001c0ff0b00040002c0011000fcbffbef000000f7bf01c0fffbff0200fd2f000000f7bf03c000e0fffebf0300003c00fcbf003000100000c0fe2f0040000800ffef00f0ff12000200000c0010000240014000080000c0ff1b00f8bf0140ff0b0000c000c0ff2b000c00000000fcff0e000140003000fcbf004000e0ffeebffbeffe0b00ffbffbef000000fcbffe2f00000000c001000140000000fe2f00fcff060001c0ff0b00f8bf0440001000fcbffe6f0030000800003000000007000140001000fcbf028000000000c0010000fcff120001400020000800ffefff0b0007000180ff1b00080004800030000c000580ff2b001000003000fcffe6bf00000030000400ffaf0060000c0000b0ff0b000700020000000000c0048000000008000000000c0003c00240023000f0bf01c0ff0b0000c0ff2f00000017000440ff0b000000014001b0fff6bfffafff0b000800fc2f000c0003c0010000e0fffebf0240ff1b00f8bf028000e0fffebf030000fcff02c003c0ff0b00f3bf0240ff2b001800ffaf00600000c003c0000000fcbf034000d0ff02000080ff0b0003c0fe2f0000000700010001200000c0014001d0ff02c0004000f0ff060000b0ffebff0e00fd6f0040000c00007000000004000030000c0003c0ff6f000000130003000010000400fe2f0100000400004000500000c0fc2f002c0000c00040fe3b00f8bfff2f01f0fff6bf030000dcffeebffe2f00fcff02c000000020000800fd2f000c000f0000f0003000fcbffdef01f0ff02c001c000f0fffebf0540014000040000f0ff1b0004000300002c00fcbffeaf000000070001c0fe4b000c0004c0ff0b0018000100003c0000c00100000c00030000c0ffcbff02000140000000080001c0ffebff02c0034001f0ff1200ff2f003c002000fd6f0000000300fe2f00dcff02c000b00000000400020000c0ff0e00014001100008000030003000100000f0fe0b000400054000f0ff120000b00010000000004000100014000380ff0b00ffbffeafff0b0007000040002000f8bf00b00030001c000340ff4b00000001c0ff4b000c00fd6fff2b001000fd2f00e0ff0a0000c000700000c00000010000ffbfffefffebfff6bf01400040000000fc2f0030000400ff2f000c00ffbf00b000f0fff6bffeefffdbff0a00ffeffe1b0000c0ffafff3b001000fbef0100000f000200ff0b0003c00340002000f4bf0040012000f8bffe6f0000000c000440002000fcbf010000300008000400fffbff0600feaf001000f8bf00400000000c00ffef000000130003400000000f000280fe0b00f8bf060000300000c0034000e0ff0200fc2f000000ebbf00f0000000f7bffeafffbbfffebf06800030000c000040000000fcbf003000400000c0010000f0fffabf007000f0ff1200fc2f000c000700fb2f01100000c0007000d0ff0a000180ff0b0003c0fdaf005000f4bfff2f000c000700fe2f00fcfffabf01c0ff2b000c00ffaf00e0fffebf0240002000080000c000f0ff1a00003001a0fffebffe6f0000001b00fc2f0000000400fdefff2b00000002000110000c000200000c000300fd2f00dcff0e000400ff1b00f4bf0070002000040004c00000000700ffef001000140004c000d0fff6bf01000200000400fd2f002c000400feefff0b00fcbffcefff0b00f8bffe2f006c0008000040ff3b000c00054001e0fffabf0200001c000400ffafff0b0008000070ff0b000f0006c0ff0b0000c0020001d0fffabf0440ff0b0000c000c0ff3b00f0bffbaf00000017000480ffdbff1e0001c000e0fffebf04c0ff0b00ffbffd2f001c00ecbf0000001c0018000300006000fcbf02800050001000feafff8b0000c0ff2f0080000400ffef00000004000380fffbff02c0ff2f00e0fffebffeefff0b001300fcaf00a0ff1a0000800040000c00003001000003c0fdefffebff060002c00010000c00050000f0ff1200007000800000000600001c001000007001000004000600ff1b00040000c0003000080001000000000f00007000100004000000001000f4bf
+InRand = 452a15b4d9006730f0a433be2d84ea6706f03119ad2410292922375e0f7d2c3a
+OutPK = 5696358110206fb1cced54bffe3e0fa80884f17ab7572dfdcb8b290fd99c29c74d007d68410e52899001aa27e511076d11acda1ee6ae52b3489831c4ccb89b331bef19c5beb666d2f331fabc0e96d4bdf5815d394ac99bb410a83e29c731e06c5403b0075cf15ef20edf09ea6a012aaf589a1f670cd6adf8920f177155aa0fd094c101c5487c682f0054152fa2676800673843820172f8cf5c5a64d47a881fd69327cc4885295a5be6c2805acbc8ae6cd8c6512d9e94f84baec76f419e03a272132c3884840610f58fd6bf6893da49d4549d5c0e87d28a417097daa1917c691b08076564d1c6683a139792e6da65d66115026755730d9a61b9f09ab158cece142fcaaf42d56397affd9a7ba6f8c40c7e5cfcd48b81a9b6819ed631c709f28329823c4a64947a3bcd47920dfc949b56eef44c9a256ed225da70d8245c444f98a2c49e3ca97b4632d8155d14aa35c7cc6051c57aab4ca84a24180d3adb15051a49afb9b6982a1a2ce99137297eebe64103fd51646cd6dda0f612268607e1f6aa213adb97a595ec6d9ae20730f6d12da5e6d6273178a294030cc3a4427eb2a1ea9d3a262079eee0165732a8460116d76ad5695dde58dba1edeaad26643a67b3c815970911caa9189244558e20083d1783d7c85aad881bc3cf6194cd8a46a7560c74d1a81df1c84832c91d2e3ad98669b709757d08b534b356b5f0948572bb9023dfdebd5b3650bfa995a4965e3d45e84c06e7f15d731264eebb01c10dd3a7381661cc9491ac3e76efa0ada251c9f79790549f2c9af179b91b44533cc8b2f67f7d6f587bb3c50ab14634ba8d8e41cf4a58a728f55c2b87fe67d7580e8aa3ed249284244f97a693e35d67ac1a00888ee63482107386ccd2023d9465bb7671b3341636a856b8b90aa38b78f25e434c6d8e6b0b20633de72e63750d834ed714e46f7dbc5d14046692850a9846e28518ec0cb78e4fb15bbe3738e852a6d84876fe279266621a5fb2c65453e33e9eaccc95265a668266a6c0ab15bd1a70c525e18f6d0dde6fcb4b23e5b8a8a715e05060209d1f89fa07b1816181f740ded8271e059018408e5a2044df41f81db0376aa2aae69dab1b6e88675aa578f8d5d243e838a231859364cb409fa21042196721a0af53d1a98d82886ade64b64d316204e4d6c7a5389424aafbb787823d87e1f379d5a6622b870e852f7d8db69f14ab905a153dceaf291034841ddadd53129d010b6ff232aca879c11e45c02095394cecc045a70d8ff5c57ad14df16b0c15009476986ffb93abc8848d79801ced33e3f03e37811a545b6808e9461f7a2752afadd6db15e316a599c8979a05c849d54345f83dad8ad8d10bd1f9152dd11884bb981273af1e4ae5386eb33e8f2b7800267eb78f71ab0cbaa05d8fc13be72c5aaa46bf089b5e150b967b17bd242be86df331e7c911a9cefb9b16fc5379c1bb0b8481b3f0ec7ec3fa3a956ac47e1ba69db083055e56c32941e1efd032bd9e413b63737bb99130ec99b1035509ac4611fa27afa265f9e52238e7211e62d5e1faffca7e8c4552967bdca8c32de81545767b5f033a21d1b07131e5ce85f3718f4bd00518f08946854b2e667f7e49291196a5400450ef446eb76ae05f7e1e52f56c49725bc087a3c7288e931d4d87a8ca8e651e7f2ab0b008c56f68a01fceaed626ee5666722603247f6bb2e05038e93c70e1cda82fc2edc3ae5ca6b622ff4af401b7f4c09ca4e9084ceb2812b8ba36435dd1cf55b896250824351149445d6fdce499c6ec94f19bb6abefb2b6fecdb7c90985b93d8c068373210d1ca87d09dc9e78d81b9d2659f939ab1e59b1a58009f468ff887c489fcd4fe3392749554024995aaeed8d57846ce261c0776d540647e8484de8c780e02725a37540f3e216456cc40c5d14e3b412cf5167937bdda6d809727ae5483f715acfd9d422488a1c0bb553ed8a83cedce18e427905c58bb998fdae6fc377f155185d085f83a71364430d275949afa59f4294e7718b56b24a67b114ee7d5c945741c710aa191b202e43ba894917a21fb39266a1995e8e0017007f281bf8781b02918e4b27f6f36d75ddc0c767349a31d35c3af3d8b52c5bdc2e01a29566f1cf94f256206e1d8afdd3f7c20a6a6d98c46b8101fd648484b5fc2f038dd4d8c410a0f3976ad0499873bee69c131d0daaca531a853fb661798967ca011d7251a234d6c94e326217fbc72e364fd02f3f4336e5afe5dd6ee6ad9a411805dec8a2253f778d89d29c2a5d76a544f30818b32d8c5710224090f32a28bac4b2b04920cabb12514ce5d34de66b627ae1a524974c55990a92bd4a01bd0fd7c8fa527b7236421d99b1df396912895da67132bd48158ca540a69c962c222019a1157dc90639743522db4e4a656e307817aa52632add1b026ce82709e50057d81c5bcd3080806ea630a1740bff4cc938b434475028cd1084ea6b2595f77a165a86b327e9c9f2dc0e480934fbaf86951269c5a6c1e9873a16e38033555be2dc4063144d5244e8f3fab06442
+OutRec = 02c00030000c00000000300008000000002000080001000020000c0000c000300000000240001000000003c00030000c00020000300004000000003000000000000020000c000340002000000003400020000c00014000300004000240001000000000c00000000c0001c00030000c000280000000000000400030000800028000000000000300003000080002c0000000040003c00000000c000380002000000000800030000c0000800020000400008000300004000040000000040002c0002000040002000000000c0001c00000000800000000300000000300001000080002c0003000080000800010000000004000000000000000000000040002800010000000020000200008000200003000000003400010000800008000300008000080000000000001800010000c000340003000080000000030000c0002800000000c0003c000100008000300002000080001c00020000c00010000000000000100000000080002400000000c0001000000000c0002c00000000c0003c0001000080003400020000400030000200004000100003000000000c00020000c000380003000040001c0003000080003800010000400028000100000000080000000000003000020000c0000c00030000000000000100008000380002000040002400000000400018000100000000180002000080002c0002000040003000020000c0000c00000000c0000000020000c0001800000000c000300001000000002800030000000038000000004000040000000000002000030000c0003c0003000080001800010000c0002000010000000010000300004000040003000080003000020000c000340001000080003c00030000400014000300008000080000000000001400020000000004000100000000340003000080003000030000800030000300000000140001000040001800000000400008000000008000380003000040000000010000400038000200008000280002000080003800000000c00020000200000000000002000040001c0003000000000c00010000c000180002000040000800010000c000000000000040003c00010000400004000200004000200002000080001c00010000000018000000000000000003000000003c0001000000003c00000000c00008000100004000240002000080002c0003000080003c000100000000080000000000002000020000c00024000300008000180001000000002c00010000800020000300000000040000000040001800010000c000040001000040001c00010000800038000300000000200001000080003c00020000400010000200008000000001000000000400030000c0001c00010000c0000c0002000000002c0001000040001400010000c000240001000040002400010000c0000c0003000000002400010000c0003400030000c00008000000000000000003000000002c00020000000010000300008000200000000040001c00010000c000340000000040003800020000c000380003000080000000000000c000280003000000003c000200008000000002000040001c000300000000040003000040000800000000000024000000000000100002000000003c0001000000002400020000c000180002000000003c0002000000001c00030000800038000000008000240003000000003400000000c0000c0001000000002c00030000c0000400030000c0003000000000c0001c0002000080003c0000000080001000030000000020000100008000300003000000002400030000c000200001000000000000020000c00020000000008000180000000000000c00010000c0000400000000c0003000010000c0000400020000800000000300004000300003000000001800010000c0002c0002000080002800030000400008000100008000080000000000003800010000c0000400010000c0000800000000c0003400030000000000000300000000240001000080002c0002000000002c0001000000001c000000000000240001000080000400000000c0000400030000c0001000020000c00000000100004000280002000000000000020000c000380001000080000000030000000020000300004000080003000000001c0001000080001c00010000c0002c00000000c0003400010000800020000200008000080001000000000c000300000000340002000080003c0001000000003c0003000000003800020000c0001800020000c0001c00000000c0002000030000c0001800000000800014000300000000180002000080002c000300008000040001000040001c00030000c000140003000000003c00020000c000240000000040003c00010000800014000200000000240001000080002c0000000040000800020000c000240003000080002c0002000080002000000000c0002c00020000c0003800010000c00018000000004000080002000040001c00030000c0002800020000c00
+Key = e99667992da3a284dc25fbf5e0856d5877938a2b7e96172e49f5b6cae78afb8a
+
+InNoiseS = e5c40729d83a968c6b2ae550c89b6623e77579f20c14a6c8cb4a623b25da3973ebcc3ee5c92a34345957fe5d10827aa05da022a399332066a2679d11e83e00ac2be799dd3eb7a6a4c787e0b59fee900013ac050b77cbda453cfd06f0de51694b12433fdc32e37b16a8e60d2bb02b82101415850212b676144ba4145ef47731af3419fc8e406be62485d7da056868435a8d1c6a52823fd4ff3db975998aba564e7274525407c318a604a4dc1360c6629f9d425963019f2c9d05901e38abfe87ee51e4ea7c8591ed84c2f991669d6454d9a1b3b88e41e9309e94ae8fa797a91e27fe08f09a2c5e826b44b1626bc88098a4280428c05ffd8129939d450bd912784ae55e13c7044bc593e9406c1ec0c262ca59f225f60a812217471d1fe6af221c98a43135f6f6696441f17b698d92702f811702ce6b292e852723d21f996675c77070427be30a70f8fc8decd69c94c19c88949ac9b528261a26a77016952a7e91a17ea81be4bc4f2175d8b44835472e1606d0059a2e4d86c236cd9c8f27dbe9fb71800b5c335862f62acd0bafa1aa6821d585f7e6b4a5718a6020d4c53244b99d80718a09621766b7c158ec90cb0dee4bd630a9264a49db854e3af0126b17359842956ccca27e498df495c220ab9968000c021a7386464f958f8691a66c671186a26e484f04e5b29112e409ca5f366091d69ab4492f52e8f6abc7e561394ae89ce050bb776b7c3cb3c334f9e5da9fd3af1de2c68a2109ec683976a24cc4255139854c4a482fb8555e926c41a96db8f62e62f4ae6783bb48622a8e2373c7b0252dc40d52b1713fc48b0058b1f65a0fcdb3b8d07c3febd7eed55021773a58e9017aa90934c55f5799d53ee4aef2a8cb2209c01fafba6151be916bfdf15862204c52adcb0da5231408ebca29c02029cfda60baaa5aa09da3f3719495fa8de6107a6d175b030d8b84fe4e5b4f17032f447a20695f349ce8124d868eb7f2dab6820e6f78115c53514ab631f6fdbf3dda71b1be890d12e5bab273a9312d2afe739b6d75c6cb6446c445aa0198eb862748b55de2054acdf0b54bcd323ac6f27f4de55e197f7517210142e179d81afc501a88661d89be6c7e6aabac160704a5b6c1a2b829d9ce7486418fb92cfa23bd1ca3872a0b67b5ce4c62caf1a495bc442c11cdc87c06563d1a73941ae907d46ab77059166dcd11d12221582bb49ae411debc6cf36a9ed3c68643f7c18af0cf107e7dcabbb221cc201023a6156bdabde7e9b12bb3c64e0f0fb92a87ba2c59dcb8a5d48d97fce343ca0e69210b1c4d01897141ec4627e3a7ce05f848c4c558e0af50c36c053b100df69532935f46293a29c5c8e24ca3ade25bb427712f80263b736a6403cdd4c47b284d22ba4575d066d202d498e86b6ec23dba8abe87f63e375b0b6f41601c68fa1717e67b654ca21bfb428a0ca7ff5d2f51447e05a56e550a6790657cc3b0c736922fbd21b491694a64a11f45108b605f06d8610686f2912f504ff07f313edae07930cf8a4e838b0606a402625c494205fdfa764a5a9416853548364b0cd84ede3d3ae49af22f4d01ab127d31264eb8ace5d2554e55290a2d8979aaf88a761582f5c92a19f49ee4f573d54a61a638703e7535eb465bb6fa3a3dc1ab5cc452d826ef6e818a65aa842f1b60c57a50354fdaf1518f4d94c088ba049a5d963105f2a8e0819da6192361240474c5cebb328cdd907a2e04b0bda41c720c23c808a0918e68fb83dfe12684a4bb471eba7a0d48e75847a44042220ab85b412048da1981306d52fc659f34876d16ae89ccba803080b9268a8597bd57f00dcf79012cbb0528f9830864a129a5495879d228ef86fbc5bb39ac450b196a97200a1829323781d64fe981fac57b5228719adff3ee5e72c29af5a18d3e9635574cb65b4086e92fbb1ba62d36a823139955d186f65d05b6bc3915e5061416f548837d532a453aa50eb26848121a3a33aa5604c678249c676c8ec973c558f2e8ef88fb105998550da3cffa09838974403e8610370b2937bae154f488bf31c816890c83b878cacc577f2a3bb256687025c17cd595614fd2e803d1fa2891634772badad84549a71a5ae83e3b9418f6f9f6ca6d4a67d9c30459554bee4ce413091e1ca092a507d9685fd259d5f0b991d0645dc6d48a1fdf8171aa8e4c210c6cef97360155acdbe19b55f000012120e221240964cdf57b09900791e02f5168ddb798e3bdb1056298ef04d00a1bde9653e073e8899530db2d30961a4a58d604ae055ab56e5a0dcb77403a41e51b5d0895c675900c9e253d1851e9d87eabf235056bade602f0952ca1c8dbd5cd4a59324d5dfbc309518b5769926a4c7863c51db8a4249c6fce71c92b9c086c217f987a38569d923b01f58c3c3682a5a796223f89c7262160226cd8ef3730ec71a43d4e3053b2f15b855e3934501a90bfc6bdd9c3d6003ce2d86076215ce2db3e31bdd2266c8693e020129d63576617d3c68127608b7566b4be9dab7576b4167fa0cf610180153207d5ff9413488a
+InPK = 5696358110206fb1cced54bffe3e0fa80884f17ab7572dfdcb8b290fd99c29c74d007d68410e52899001aa27e511076d11acda1ee6ae52b3489831c4ccb89b331bef19c5beb666d2f331fabc0e96d4bdf5815d394ac99bb410a83e29c731e06c5403b0075cf15ef20edf09ea6a012aaf589a1f670cd6adf8920f177155aa0fd094c101c5487c682f0054152fa2676800673843820172f8cf5c5a64d47a881fd69327cc4885295a5be6c2805acbc8ae6cd8c6512d9e94f84baec76f419e03a272132c3884840610f58fd6bf6893da49d4549d5c0e87d28a417097daa1917c691b08076564d1c6683a139792e6da65d66115026755730d9a61b9f09ab158cece142fcaaf42d56397affd9a7ba6f8c40c7e5cfcd48b81a9b6819ed631c709f28329823c4a64947a3bcd47920dfc949b56eef44c9a256ed225da70d8245c444f98a2c49e3ca97b4632d8155d14aa35c7cc6051c57aab4ca84a24180d3adb15051a49afb9b6982a1a2ce99137297eebe64103fd51646cd6dda0f612268607e1f6aa213adb97a595ec6d9ae20730f6d12da5e6d6273178a294030cc3a4427eb2a1ea9d3a262079eee0165732a8460116d76ad5695dde58dba1edeaad26643a67b3c815970911caa9189244558e20083d1783d7c85aad881bc3cf6194cd8a46a7560c74d1a81df1c84832c91d2e3ad98669b709757d08b534b356b5f0948572bb9023dfdebd5b3650bfa995a4965e3d45e84c06e7f15d731264eebb01c10dd3a7381661cc9491ac3e76efa0ada251c9f79790549f2c9af179b91b44533cc8b2f67f7d6f587bb3c50ab14634ba8d8e41cf4a58a728f55c2b87fe67d7580e8aa3ed249284244f97a693e35d67ac1a00888ee63482107386ccd2023d9465bb7671b3341636a856b8b90aa38b78f25e434c6d8e6b0b20633de72e63750d834ed714e46f7dbc5d14046692850a9846e28518ec0cb78e4fb15bbe3738e852a6d84876fe279266621a5fb2c65453e33e9eaccc95265a668266a6c0ab15bd1a70c525e18f6d0dde6fcb4b23e5b8a8a715e05060209d1f89fa07b1816181f740ded8271e059018408e5a2044df41f81db0376aa2aae69dab1b6e88675aa578f8d5d243e838a231859364cb409fa21042196721a0af53d1a98d82886ade64b64d316204e4d6c7a5389424aafbb787823d87e1f379d5a6622b870e852f7d8db69f14ab905a153dceaf291034841ddadd53129d010b6ff232aca879c11e45c02095394cecc045a70d8ff5c57ad14df16b0c15009476986ffb93abc8848d79801ced33e3f03e37811a545b6808e9461f7a2752afadd6db15e316a599c8979a05c849d54345f83dad8ad8d10bd1f9152dd11884bb981273af1e4ae5386eb33e8f2b7800267eb78f71ab0cbaa05d8fc13be72c5aaa46bf089b5e150b967b17bd242be86df331e7c911a9cefb9b16fc5379c1bb0b8481b3f0ec7ec3fa3a956ac47e1ba69db083055e56c32941e1efd032bd9e413b63737bb99130ec99b1035509ac4611fa27afa265f9e52238e7211e62d5e1faffca7e8c4552967bdca8c32de81545767b5f033a21d1b07131e5ce85f3718f4bd00518f08946854b2e667f7e49291196a5400450ef446eb76ae05f7e1e52f56c49725bc087a3c7288e931d4d87a8ca8e651e7f2ab0b008c56f68a01fceaed626ee5666722603247f6bb2e05038e93c70e1cda82fc2edc3ae5ca6b622ff4af401b7f4c09ca4e9084ceb2812b8ba36435dd1cf55b896250824351149445d6fdce499c6ec94f19bb6abefb2b6fecdb7c90985b93d8c068373210d1ca87d09dc9e78d81b9d2659f939ab1e59b1a58009f468ff887c489fcd4fe3392749554024995aaeed8d57846ce261c0776d540647e8484de8c780e02725a37540f3e216456cc40c5d14e3b412cf5167937bdda6d809727ae5483f715acfd9d422488a1c0bb553ed8a83cedce18e427905c58bb998fdae6fc377f155185d085f83a71364430d275949afa59f4294e7718b56b24a67b114ee7d5c945741c710aa191b202e43ba894917a21fb39266a1995e8e0017007f281bf8781b02918e4b27f6f36d75ddc0c767349a31d35c3af3d8b52c5bdc2e01a29566f1cf94f256206e1d8afdd3f7c20a6a6d98c46b8101fd648484b5fc2f038dd4d8c410a0f3976ad0499873bee69c131d0daaca531a853fb661798967ca011d7251a234d6c94e326217fbc72e364fd02f3f4336e5afe5dd6ee6ad9a411805dec8a2253f778d89d29c2a5d76a544f30818b32d8c5710224090f32a28bac4b2b04920cabb12514ce5d34de66b627ae1a524974c55990a92bd4a01bd0fd7c8fa527b7236421d99b1df396912895da67132bd48158ca540a69c962c222019a1157dc90639743522db4e4a656e307817aa52632add1b026ce82709e50057d81c5bcd3080806ea630a1740bff4cc938b434475028cd1084ea6b2595f77a165a86b327e9c9f2dc0e480934fbaf86951269c5a6c1e9873a16e38033555be2dc4063144d5244e8f3fab06442
+InRec = 02c00030000c00000000300008000000002000080001000020000c0000c000300000000240001000000003c00030000c00020000300004000000003000000000000020000c000340002000000003400020000c00014000300004000240001000000000c00000000c0001c00030000c000280000000000000400030000800028000000000000300003000080002c0000000040003c00000000c000380002000000000800030000c0000800020000400008000300004000040000000040002c0002000040002000000000c0001c00000000800000000300000000300001000080002c0003000080000800010000000004000000000000000000000040002800010000000020000200008000200003000000003400010000800008000300008000080000000000001800010000c000340003000080000000030000c0002800000000c0003c000100008000300002000080001c00020000c00010000000000000100000000080002400000000c0001000000000c0002c00000000c0003c0001000080003400020000400030000200004000100003000000000c00020000c000380003000040001c0003000080003800010000400028000100000000080000000000003000020000c0000c00030000000000000100008000380002000040002400000000400018000100000000180002000080002c0002000040003000020000c0000c00000000c0000000020000c0001800000000c000300001000000002800030000000038000000004000040000000000002000030000c0003c0003000080001800010000c0002000010000000010000300004000040003000080003000020000c000340001000080003c00030000400014000300008000080000000000001400020000000004000100000000340003000080003000030000800030000300000000140001000040001800000000400008000000008000380003000040000000010000400038000200008000280002000080003800000000c00020000200000000000002000040001c0003000000000c00010000c000180002000040000800010000c000000000000040003c00010000400004000200004000200002000080001c00010000000018000000000000000003000000003c0001000000003c00000000c00008000100004000240002000080002c0003000080003c000100000000080000000000002000020000c00024000300008000180001000000002c00010000800020000300000000040000000040001800010000c000040001000040001c00010000800038000300000000200001000080003c00020000400010000200008000000001000000000400030000c0001c00010000c0000c0002000000002c0001000040001400010000c000240001000040002400010000c0000c0003000000002400010000c0003400030000c00008000000000000000003000000002c00020000000010000300008000200000000040001c00010000c000340000000040003800020000c000380003000080000000000000c000280003000000003c000200008000000002000040001c000300000000040003000040000800000000000024000000000000100002000000003c0001000000002400020000c000180002000000003c0002000000001c00030000800038000000008000240003000000003400000000c0000c0001000000002c00030000c0000400030000c0003000000000c0001c0002000080003c0000000080001000030000000020000100008000300003000000002400030000c000200001000000000000020000c00020000000008000180000000000000c00010000c0000400000000c0003000010000c0000400020000800000000300004000300003000000001800010000c0002c0002000080002800030000400008000100008000080000000000003800010000c0000400010000c0000800000000c0003400030000000000000300000000240001000080002c0002000000002c0001000000001c000000000000240001000080000400000000c0000400030000c0001000020000c00000000100004000280002000000000000020000c000380001000080000000030000000020000300004000080003000000001c0001000080001c00010000c0002c00000000c0003400010000800020000200008000080001000000000c000300000000340002000080003c0001000000003c0003000000003800020000c0001800020000c0001c00000000c0002000030000c0001800000000800014000300000000180002000080002c000300008000040001000040001c00030000c000140003000000003c00020000c000240000000040003c00010000800014000200000000240001000080002c0000000040000800020000c000240003000080002c0002000080002000000000c0002c00020000c0003800010000c00018000000004000080002000040001c00030000c0002800020000c00
+Key = e99667992da3a284dc25fbf5e0856d5877938a2b7e96172e49f5b6cae78afb8a
+
+InRandA = 466e66f041312a755f555a949a661f8966f440cc2d3a4cfc08ad7aa8f018a681444247d0dd37b2ea61a2496ad9880bdda2c2c41895f83180f79cda5ba1f202f19896aa9ba51443ab58f7349c1fdecef93b444a9996a13d716e709efd1c08e2e2768daf974c78dce6a18b5eb9ba8db402ad955609740425aa21457adfe5802991075b62dd62ee55135b4040a3b32147748e9980e0958736c66c24262cbf55c782646c255712e4665ff80576774d420f4e13892016e6530001df93fab40ed9d48ec5d2d44726cfd0dab47094b8dbf0da6da5b4f7534e680166788daeb2a7bbfa2f746fbab1346d3f3d8f82d859f973661c3c6bb624bc0ed2de274789275110fe50b9e18ca5196040006e9dc78be2bbf1214e6e47e305f54e7d1b51450781123ae01ba6774ca51a7745f2a68aa44e37a8d6444fc03aca490fd4a1aa02908a51e1df4cbc1d0804d70f9d94859b01264cea842da37d86fdf97f5cad10b03aee627545aa02c3d67f07de5f63624e45615308a8e81d55698851ba625188624b032aa52cbbda9c80f715897fc86d300b527d303aeb03b8b18440b21e2b0a682da5740dc9c6863a5a1606ba784e2e47a4ca2fb09bbe641346d533e82c221d6fbbd29a2cba99d71fc153959c62985bb092de06c2253a032ecea0f6d8bb041ac2236a98f51a7220a73c52f4498d153ad99774883f85680410944030fe28204db6ba2a454a0928b10af2b920b3658e92c3bdbcf4681c7993f2aea59c419a979687a3ac2180f94c8e50c293b627c0216f5c0ffa2c310b7d49ccbafa14875e8a94b3ef1e3ad7926db6eafa0e87cf04a8f5101a8407f0d7e731ae31ee23f14c09609c29e254dc781588648e89abe662fc5a79e30cd8559bae7db123b96f4dd878526374311b681c45ddad6d96a520a13d6860e967e3f7daa8718f86f5c4cca4309f5caa4646b2ab5787033553b4149de6d63aa4593a70e6486b0c3d4d02dce897d0e14bfa6bca6b261176ead285e7007905672a76754c8d66414d99781eca5f9e83fe7bc3066c139eb909d3156d79d1860a2650149683e34578f272bd185a93b0418e50844fc04b253504e8e2f7a60a50c1ddeb747c357f249164d437e0bf53a8df2a01a836fa69d85893ea895c449fcb7e6d7c9f24565848b97f529e376885a219640774898a96aaf7c1260b871246949f6874c23e28e2adc98b3d6e4fdf8fc091a45e75ae6503f535f4b1ec20f66b61152f63dd8e3bc512305a0cfe9bd09a5c65910586123a246cd8188764c5895d278ba01f91196f4c68599cf1b3b800c37bd3f813a5ce326b0d9952ac4b6b96bf2468de4837157451177dab8ccb5d90591f5c81f5d8f14855a22ca4e89522fb4ff333756021f4c3b5245738293d8c81d4b0dc7ed618ac14c712350ed97d1685388ec2e14317a2295710418889fc3e214d2d225869509b068ca5032af80db7587b759b4c073069a4c4fe9a8be40f39d500667dc720b90a2ee17785644a6a3be55f51260736ad6525d7e121f413165bb38142621191b7f21feddbb8a658cd013187b246051ccc0cf952f574148317571a6643666d9fdbd4fd7ed343519b791c131c68ee85850595339c962335351744db3738569cb5bd42becb2e3c0c2be214592d1aa3f1d3cefb6b364896cb12096b2491df4381d50ace9f766cf140fb289a5b6415f0fa72548ba6e54a5da261bd2606150ff6003c87af1a687512645cfcd2cb555962d59c5affec340c9460218541228c99df057601824715f38ba0a27f945125fa1322a02c4b0e3388866cb349f4d0a1e423cf20d41055a46be20e0a43d70183de531537c9ec0229a65168027494f19a4ce8ace666298bdbe3db10bafb4661d7c9f8b70ca955d7054a25dbcc6575a18979ce4d42118039a739811429d0e26f4f6b842890e47c6d5178d5f2ccac590157f9b35aa0746b9c9353181a546ecfc92131ba556c1638a9529c6688f037ebf8879e15ebaae9f881c9db1143d7509b2b8ca242ecd245dc0898f847b96bdc4c273908a2149817eb2bb0aa9963e54007767ea0afc0d9508f0e5039cfa257f19cb57898c52737f16958e30101d289a484e7e460643409126c6610a15570648a40a0233cbdf863cd1384299f6cd5b8a88c700bff8faf80bf35874a024db6164195bde038e2f61c4d9e6994643ef0923f6c795a8f2a9d24a2bc391b4046b8cf4bfb40287893254c493a70434b12af36c64d645ccd6e4bd8c003674bf315e512bc9d21b6121ad11a790197bbf5b453f8443449012544e02c5045705c908a89f2d1faf0309d0aae891efc1717aa3f32ce3645138c13125db68d06effa6436359783c4d863702e6b2b4f7eea76a4504a8d01d39ab252d66a64f3b19186fc5918f19d4a36d2415aa943d267cb5d4673990e74fb8ed8484af02df782cd23e302574069aba1a631959be32831c3a27b35a3ff909de8a1fb2a6c852fd05affdff5fa11ce353ba7a3b1e1920bb62c497acdea0243431d8ae65459e867aa8082d44a5ac8fee3bd3d1653dcd0d209a62c
+InNoiseS = 55d10f4b48067ba8ef2308defa0285cec13987c82d528761f851ce55ef4f40659ebd2f0b6deae54a28ad4dcdcff387b99a8e4639c0cf354127186a92f6c0b1735f6d34d89596800646533332b2e5dab016a3d5129f8702223a94003c03774bb2061d322a86d3b7727904414df6c1c03c1a680863a43a09a862e6a0a0921eeb4431188c4c7b79edd293f24c3a1496763936b23d599d922b82663fe59836743d843046d5ac7493a95e36d16b770b7a47bf5b958355fc289c653e4637dda5ea68d40253440eb96f5976ad7a6248a138e760352792267249e91239050d4cf24406a57b2d98025bf104e587632aa7c52f65e781561b0e71c5ce16f371fe50da1f6008f2824828523fd3e2a201050b17a2b474491d49a0b36c8c34eea3adf9339c20a651d6eaa5205f406d933113816e1b5e587ad49a09de8e6e6630f60ed96163833a8560385c1b2124f165ece2ec52af9a9b612f9dc03a81190e5f46eaeda60faa0b7fb79c047207cc4e48078a46a0c49cd1132e9c9a00f85a193551a8cb4b99ec1d6c07491c114969b652935a82bba252326dab5440cca66fe24c37fae468a32b22d21540862f062c148fbda0f0a320ca12ca1ddadc661b19b45c461a38171ad57da96b89c01aba52ce596ebb325a22016e2070d5420284e4a319bf521480181ac4294d28ee037016f03149ad538e632f3c274a162e93b982079fa85aeadabe3cc58671e4bc0a2604243037ae98211789dce0b5a59dd89cfd5b13c56c97d520d73a4c373501f604c3316ce255df320b9494d10d9415faed012ac6b53400bc6d47e3307852697a142c4a9bd28a16b11cf93af3914d31e020ebf4ce8dd41aae69e8885ba641b47352212e69c03f932c5c4d54687a3503288ef5c3d6ab83fcaf2059e9098b59a898c7801683d636e45cbbabd1d8268606c3764111666fc3d57845891126dcd9faa5191a8bdae12466d62cffca274b10129b5d1d5caba36c15bf1e7de911b471a3c7a82ac6ea2374122e2770f8237c0d48e4e25c112b2f6659582567088482c9e9e0789191d226353878202120448980a6b7069bc71bde617452fd2317ed4e989f771032c46ba99724806f5998c8e8fe940b7ea24e6291ea5e550e7e5e2088dcdc6c60dee55496f22c870ca597357d728a9e45c4a8a44c984f48a62281a994098558f77eb70d2b690601a92c8327ea246355744ad97d912ca63d84eab3e0cfa521ce800699989a79269d10fb9285826da751db0dee4c716eeb946b59bf312226e7b95171915ea15615a1bb1c59a749cfb12761edd989e08a79079af4a781dc4f5d6056a91a0661742e5d54673a6c1cec1013739c2e71df299942769ef25da2e5daba26f9addc5155a8608aecbf53254c2d27a588b0823aa54d0bc24a2131b7d842edb3f9666a798f3e86abfe279d86259165bd93e8e7f913ab7d14a94f40cb44062a3d2728e9029ebaa6865be89d7d052c049e7389ca866022c267a3392f689d7ae627fa3b58141ab762d10be4e6d8752edd88cfa3985bfc723023dc380398ee9d9b9b9153a5a06eb295858397fd7719400f80e38aa18fd1eba6c324b15726f4907b84897aa3ff347578a13f1b905a148db1ffe55813c17831f54ab7eb52b44545427a25c17481d0851b590c4e1ea2682139c421108dd2bda3fdbe90549a7548e1463cf0a51e4abe1c171f4866191cba036d270248635c48848fdcb690a0bae3240029cbd688a4d6f150d08d6a0b4e62e2714e57806aad69420c71a72788c996b19b5fd5870506262b878e354056ed2dc4cc6bf00e59acd15ef776d1ee75970799c95a5a32814f8e790d459d32d4ccd807117acf2d2ff290a57342e9b439fbc6163c268953fcc0444d5afd040dc035a3aaa54884c09b4d60f2c0cf2c1e91cb1dd5573e26f3ca8609d3d582c926d429005891c02699e5d3c40eb203a8641fb8bc5dc13a04e832b954cc0003988ab691495e5662e21afb22ba667836bb7f177301005ba3124e4f947f851e5de9b8042b5da3476cbee91e588626da672217be58d146a2f3eb590be8832595455972b5531a87b1e63c20ec19bb9ee925ed1d5c7765b19c199769920d8c4ee6d7eaa3973995011e9e77c6de17662beb49ee169dcda4c6d7091459794277a0418c55926bbbc83a320cc38de4126612a3bd8a55ebfaa897c9e17082319d71b2c964ca7471721e96c69bf84d2ce9149069e119b3f40617d20dc20404dd587aef66972f14369056e2673c5cc54877f69bf8e0ada3527c58c9d8c408ce218c04858e5b94c4ba2e2da592b4c0bfb2c9e0a894e614e7a21baad239149743d1e4b3b068c5c324e1080c09eeca22487b2d807620ff20f64eb1ce404ff82f3926c0673b4341c6a6a1005b08e1fd27578ed1373af6879be3159b2cad27a29eb0c9fab2358258d0a946b1396e6d007995c291cbee1837b4454a13c84aa7b4da799bdebe33b9d2879d11f02008c82a7f9d48c33e5c57a74f731496b62a180db690406a9d8828c13550093aa1a29309ffb96adb68cda1a1089a
+InNoiseE = 121aa624d30404040175048b103de50d947082212327e5c6d7208da2728f9ea5ef151880c98011516e525785943af3824676c562531144a82704add92ba0079da53dc88ed59d32822781a41949f60ee8a8b35822bf8bfbd3ffa47b0a6b46a16926ab810de79289c15659261bb4c91600975658b4239a00406233211799177811256b0f7597ab4b169bb0424a900f76759682b3d542d341e60066ceead0b319e40edf5333177f712c4a9788c11d701f2e1a214aa7d87210a1df861de92d676999e4c68e0ddb41de716c0c569c5e8bc62ece83ebc14266c819573edd33f5c52c286d65dccb8a3444d228800b1dee5d88430fba5a708637abfce060c57cb926dda157092959e01b455e754065dfb97092c965b0e861fb7dd150f811e5c3f77d41c7dc5356f0f497c0e7185702398a8dc5d311c58c02d00d18155e1901ff0afdba08724a5883e7b2a66a4dd2d85cab4e2d8c87856cb93af91cac1337c828565d8950fae2582177bb40c3da5e5034e9478b2789d163d720229b7be153d5575c86cfe58129eb1435cd8e4a816e76e94411077d9d9837463884452e5dc8471c71b5c9fdb859d25734295fe0be0c551fa901a6fc4515e7554cd3bdb87bdfd9f17a41a13396d806751c1138e81995ab879d59aa89df001fd882f5138df1bf62ad4d96ef641c3577e04ea5e372ca3a47d7b8c8829d0f9da89c25a394a0921f4eab11ad0e17e931c1ae1e89ff0c59e025bca569823017f9cd007605d156a2ce6ecadba763dba289f6805261b0d23cd8aa9ae759f066c0130e675ec52f0797e278b0eea94a6ca80729459acb40cf19af581184590eb70b8c1566534de4f5dea35c61a9f62fdc307f282fb33d84ad5718459287853f769ce497d25c3fd55192468524293aa906a6b1f11524804375f8b8324d084f639e5506bd55ab5732669df1159c70b3ae32ee63cb06317e645d241c123a787402491c31afed53e0228dc0e2462e86e70b8afcb0065f13fa8193be55a29a59327788518ec8ff3b15d290366bb93698f82c2bc7d0a2e9c50f042708b403982dad02ac976d9aad53a2a8195b6844da8475772ab8a322ae12c7b81ca7401d5942c8763c00c503e6650a95108ab596b1814c4f919213722a4a36d7045b9f801ad9a872b3913e41ea46d01434f9b90ce4b751e01821bcd883a63a2d9837121ba23b2d72bd8a07e22b14bdb3c616a832940100541936aff634965b5c0b9c9051dda6fd7593f43e266e56469c0a90c0ae5e57f781780b111bdbf2c9667542ac025f6697cec7a215cb765016ec07224b4d58f18350b2aa764368a69ec4913a3534c455f9f2c6a10d6172d61c8a950d8fa6f5c6a5b8885de6a227b5a8708d868a51315ab6c61a16e9786e08cf3c857c415662e32ef97b8e24c5166c9821c02f8be965d890d154f01f5eda8136713607740a122eb26c0910040ae879bc935798da8413538e2ea9568ebdc9504c202f9a8e79098ce92e1e6115c507a06ebc055e64094711c5388695b84858989cc2eb96900a48129198324af985281ce6ea74d0c2a4dd6515a23bf488808344f00f3023905de32185a915fddd9901c0f5724eadc850439e2de4e166a5814c3e40d36686c5115ed5c13d7146c1031182e3175de04cdb54add2ac990600878f858ee4970a89286ab7e04587cfd879a8ca8e2a2dfef6ec088090dd20e0d2624ce5edb6f57f46aed3ec8039196e9c7bcd353acde58e65c26b01a6dc7f03eb1de5c97d8c9c97cf9b5062341800e7fbe0de48686645b79c257feed2253a1ae5a29ea0ba1479da61130159b8494663f56d465b91026cb7ee7a56867688575c0268f0ad053151716b37a9b9dd6fc4e6738132f4e4dbab3ad61ca24bbe49897958bba0d0db6276100c2fce04e04e392cecdd6799126f8f179494f1563eca6a2c930acd95f169b4308e1e62689c14b8e3f27be3c1a772948a77e4d38990a9983a744400bb0aec769b21db0ae10963d80e65619a7a39eb6bf614b64811bc452f67a60d595c6230c802f252cbdc008afb351cc4268137f48031d32ac71b997d9f6eda00f5efe28078a31bc2ca0e77304191f6d7aab3e561a7577aa218a18eba60257a8bddeabdc61164a8111886d89000478f9c1bd005198e5be5ed27078e096fd56030c51c04cc673f09055d3de26119834e668192d045a03cbe054768d05be3a8895205e4713a8e826bdbd6660bac715125f928839981ee898fb4e89d196b213f38643a3b9008d9c8cf4a2f5d43e232d70582c9e9c0767d64068ea447256d9e1ddf9e0e3b831a702acda0d110b522ef157ce9674d119ca14dcaec20371301c89263e42f57d15999165d0f44d11a54564a083059f5633cb9bc4e825f6bef346985ee571b8f1c45ec8a42b9cbf4abf214ce904e4d5e41636f57243a0e7ba4a52aff900cc25eda444e814c9f253fe34532a198dcab228ba12f2b576784f7847a8596fce7caae95eaaba06b74b67c90def7db4fc10d645b28d3bcb40c0606cdbb63a48284405053da8d2d67d68bd3b1aa0a
+OutPK = 9b9c71049e319792e1110bea4da03eda4dd5220d01ddc3c921022e5d3bcf8b70c1218b77d576d564c08f95d6fb271fd09c6c546e764e2d8b36a72e852de90d89683e9b54598fd7dff269431685381ff842643813944c2d502a582162ab35125938acde5ea3b2644c16dfca13360efd8c0dc02284750c8e8255aba28d2411591463186d4c5b63caf21a9972560c848c01d650b256a0b2f312850de681720a35012ad22a1fcb89d491768f9524e74453370075d5a60d6e470cc348f1e20afcddb41bf44c73428f41dbc50e27248f7f11683e0abf5e1bc4e1e1255fe2b22b1bec643389d453a8e58be11205237d8e9578ca9b822c18856f6e2434d39286dfcf2b6280d84f6ee2e1c3fc007394240e448a8429bdac9dd659edab45adc3608b1050c7c521aa19e056599b8c820e740f22dc6e15b520a8f4933f53adec2e9d270100389991eb00f6f6f21676699d72f95ae838dda9f5e43bfc985c554532801122e86527aa690c4567af3eb755f540abc6abf744ce8ae69f83111a4c9a618373c5cbb61ab2a91b028338b1242e7f170196331e0883c66f784c6edbbe8b0aad15572a9116fb3d50759a3695e38d4ae7c61888a15e056ec2057269f5600424256435bc2321ea102a333531a96ddda6584dbd3d171109b2b533d00720754d99b4d7ceecf891823b2a95be9bbf960a2626281b7402a1555ad5933c793757abc611e9ae555e882257a4125882438134c89d17948cdd4174a28178cb0242a55571dcaab8cae3494578ab84124ace3edf82645ac1386c12595debb108951e4d32567fda2e12cdadd810ea61166dc2a83e6d9c4a578c212df229cd0b8ae52e89584b2729359f912a6e6fde14b1e22a78191bb26259912be8ef71edd98d85484e647461ba9c5ac332d8959a42c5088990ba08cc877b0acfc964b31de2e8411a5cd6d94f769c605c8a5a2b25c2e66f42983281e41143c489ce29887e1f7898a4606071bee156bef0d49a455b21f5ca7beaab014fe597ef3d9d514d56110d21b532a5f0401419663d215b81ef7d7f28df3f1b2d401df4d8659381ed4ff8db80e964aa1b7297f0632d2c8b2b822678e1b861ffa9bdb03e013e916a392895c91e890c60d65c3650b1cb8d4adbd014f45ef50617b48a2353db272160a8d48728c2565c6a0511b934a3050a246a200b6e296d694c324376a9569f0df0c525d24ccd9b1a779da422591cefb952dc72f16859a1e6b84db768233b03581853ec7a40bbf98980411ebb5a396352d492b6accc79129b964417e94871c480a08e867c2069d5e03b994084e4c5f3d8c499054c2903d1c0913864b92734008bc396448340b91c5157c325e1a107774dc1779352164508fc721d268393442c7212e8a9da833c851b224ce7975e621dad0a191575571e6d505b91c7423884bb9a464a64e6a40e566a70c8c74940768fca4b62d03023c430826005b7bf9dc6f863f51e98aa713b781d8aa1aa65f73de019be459852850684f963502a82c9619867026064f9543a13dd7af9bd77eeeb25d2566cb2326b2d50805602dc270655d8eca27320d5302bca56ef5eccd4046066a4d9778675e15a01d17363d0c5076f43de1084f551674a6b02a990ae164284e467dc300b5c619bc0a45e411b8e5b15121d1e62668850d4a45ec7a56113e213dd291a40d80d33be8c0cc3fdee08e0a94182b63c4d8de78c1aabd5ab6cd90b18de9e7e5684f8b497a1751867af4218c20ca949fc8506a837fe9e1843b4da6dd690c9cab2e00880089bf0af4914c1ab01241c5e9816efe9275138230327e23a6ef42ce810c088feaa8b2a5d120837bca64b54a57618228b5bad1c02d33591d71790027780113804dc60757991c1150580398a45c1620bb17c620db8ec78d04770b2295086a6a6ea36ab0f44e13f70364a890532f08a8f9a11557093a27ab8ebd5a0bc9dba17a972c4db39aa6580c6b1a4a1208e5af6cb6d246ec44fb463cae807f668eb27c3390a60ad3cb3ca021e06d295ba7bf07483076f73ba44ba81609259aa0d7b48a975b56aad075c06002696da667bd23ccb26045bfadb6121dd810ea05b77195dc66cc5c68de68df80cdd2ea6a699c451c2d6d033c6c4915c8408009494029fa3782442f83d0fa2e8ea536d1a8f4f146344a639609753810a512539eed3673fb60ce58dc07b97d80369021f6738c92ea445c038e0cc89d8596e6268641b2604b3a6635d594b9348e73a6a448840623966fc5497d1cb252714b993ef45a27b3d36f01da8cbface615dc349b0d8d168b1aed283bd38302fc181984734231660e076f7dd56eaa839f398d18c00cf4a418961231a506ec185b862d4c442b2820053831abcb609e13956d9440150e50da9850f95ea8a93bf54984b0c000bc299a721a35ab9882e5c9b7da11265cc36115071a6381145b22246a0d3e851d2d901b79b1b7bb2b8d659bd5b9aeb9288582b69b124e189a914a9645056603db6649cd5ace453c80fbd592a06779567e41532ac0318cf3eb8d3fa154d6197216326aa
+
+InPK = 9b9c71049e319792e1110bea4da03eda4dd5220d01ddc3c921022e5d3bcf8b70c1218b77d576d564c08f95d6fb271fd09c6c546e764e2d8b36a72e852de90d89683e9b54598fd7dff269431685381ff842643813944c2d502a582162ab35125938acde5ea3b2644c16dfca13360efd8c0dc02284750c8e8255aba28d2411591463186d4c5b63caf21a9972560c848c01d650b256a0b2f312850de681720a35012ad22a1fcb89d491768f9524e74453370075d5a60d6e470cc348f1e20afcddb41bf44c73428f41dbc50e27248f7f11683e0abf5e1bc4e1e1255fe2b22b1bec643389d453a8e58be11205237d8e9578ca9b822c18856f6e2434d39286dfcf2b6280d84f6ee2e1c3fc007394240e448a8429bdac9dd659edab45adc3608b1050c7c521aa19e056599b8c820e740f22dc6e15b520a8f4933f53adec2e9d270100389991eb00f6f6f21676699d72f95ae838dda9f5e43bfc985c554532801122e86527aa690c4567af3eb755f540abc6abf744ce8ae69f83111a4c9a618373c5cbb61ab2a91b028338b1242e7f170196331e0883c66f784c6edbbe8b0aad15572a9116fb3d50759a3695e38d4ae7c61888a15e056ec2057269f5600424256435bc2321ea102a333531a96ddda6584dbd3d171109b2b533d00720754d99b4d7ceecf891823b2a95be9bbf960a2626281b7402a1555ad5933c793757abc611e9ae555e882257a4125882438134c89d17948cdd4174a28178cb0242a55571dcaab8cae3494578ab84124ace3edf82645ac1386c12595debb108951e4d32567fda2e12cdadd810ea61166dc2a83e6d9c4a578c212df229cd0b8ae52e89584b2729359f912a6e6fde14b1e22a78191bb26259912be8ef71edd98d85484e647461ba9c5ac332d8959a42c5088990ba08cc877b0acfc964b31de2e8411a5cd6d94f769c605c8a5a2b25c2e66f42983281e41143c489ce29887e1f7898a4606071bee156bef0d49a455b21f5ca7beaab014fe597ef3d9d514d56110d21b532a5f0401419663d215b81ef7d7f28df3f1b2d401df4d8659381ed4ff8db80e964aa1b7297f0632d2c8b2b822678e1b861ffa9bdb03e013e916a392895c91e890c60d65c3650b1cb8d4adbd014f45ef50617b48a2353db272160a8d48728c2565c6a0511b934a3050a246a200b6e296d694c324376a9569f0df0c525d24ccd9b1a779da422591cefb952dc72f16859a1e6b84db768233b03581853ec7a40bbf98980411ebb5a396352d492b6accc79129b964417e94871c480a08e867c2069d5e03b994084e4c5f3d8c499054c2903d1c0913864b92734008bc396448340b91c5157c325e1a107774dc1779352164508fc721d268393442c7212e8a9da833c851b224ce7975e621dad0a191575571e6d505b91c7423884bb9a464a64e6a40e566a70c8c74940768fca4b62d03023c430826005b7bf9dc6f863f51e98aa713b781d8aa1aa65f73de019be459852850684f963502a82c9619867026064f9543a13dd7af9bd77eeeb25d2566cb2326b2d50805602dc270655d8eca27320d5302bca56ef5eccd4046066a4d9778675e15a01d17363d0c5076f43de1084f551674a6b02a990ae164284e467dc300b5c619bc0a45e411b8e5b15121d1e62668850d4a45ec7a56113e213dd291a40d80d33be8c0cc3fdee08e0a94182b63c4d8de78c1aabd5ab6cd90b18de9e7e5684f8b497a1751867af4218c20ca949fc8506a837fe9e1843b4da6dd690c9cab2e00880089bf0af4914c1ab01241c5e9816efe9275138230327e23a6ef42ce810c088feaa8b2a5d120837bca64b54a57618228b5bad1c02d33591d71790027780113804dc60757991c1150580398a45c1620bb17c620db8ec78d04770b2295086a6a6ea36ab0f44e13f70364a890532f08a8f9a11557093a27ab8ebd5a0bc9dba17a972c4db39aa6580c6b1a4a1208e5af6cb6d246ec44fb463cae807f668eb27c3390a60ad3cb3ca021e06d295ba7bf07483076f73ba44ba81609259aa0d7b48a975b56aad075c06002696da667bd23ccb26045bfadb6121dd810ea05b77195dc66cc5c68de68df80cdd2ea6a699c451c2d6d033c6c4915c8408009494029fa3782442f83d0fa2e8ea536d1a8f4f146344a639609753810a512539eed3673fb60ce58dc07b97d80369021f6738c92ea445c038e0cc89d8596e6268641b2604b3a6635d594b9348e73a6a448840623966fc5497d1cb252714b993ef45a27b3d36f01da8cbface615dc349b0d8d168b1aed283bd38302fc181984734231660e076f7dd56eaa839f398d18c00cf4a418961231a506ec185b862d4c442b2820053831abcb609e13956d9440150e50da9850f95ea8a93bf54984b0c000bc299a721a35ab9882e5c9b7da11265cc36115071a6381145b22246a0d3e851d2d901b79b1b7bb2b8d659bd5b9aeb9288582b69b124e189a914a9645056603db6649cd5ace453c80fbd592a06779567e41532ac0318cf3eb8d3fa154d6197216326aa
+InA = 466e66f041312a755f555a949a661f8966f440cc2d3a4cfc08ad7aa8f018a681444247d0dd37b2ea61a2496ad9880bdda2c2c41895f83180f79cda5ba1f202f19896aa9ba51443ab58f7349c1fdecef93b444a9996a13d716e709efd1c08e2e2768daf974c78dce6a18b5eb9ba8db402ad955609740425aa21457adfe5802991075b62dd62ee55135b4040a3b32147748e9980e0958736c66c24262cbf55c782646c255712e4665ff80576774d420f4e13892016e6530001df93fab40ed9d48ec5d2d44726cfd0dab47094b8dbf0da6da5b4f7534e680166788daeb2a7bbfa2f746fbab1346d3f3d8f82d859f973661c3c6bb624bc0ed2de274789275110fe50b9e18ca5196040006e9dc78be2bbf1214e6e47e305f54e7d1b51450781123ae01ba6774ca51a7745f2a68aa44e37a8d6444fc03aca490fd4a1aa02908a51e1df4cbc1d0804d70f9d94859b01264cea842da37d86fdf97f5cad10b03aee627545aa02c3d67f07de5f63624e45615308a8e81d55698851ba625188624b032aa52cbbda9c80f715897fc86d300b527d303aeb03b8b18440b21e2b0a682da5740dc9c6863a5a1606ba784e2e47a4ca2fb09bbe641346d533e82c221d6fbbd29a2cba99d71fc153959c62985bb092de06c2253a032ecea0f6d8bb041ac2236a98f51a7220a73c52f4498d153ad99774883f85680410944030fe28204db6ba2a454a0928b10af2b920b3658e92c3bdbcf4681c7993f2aea59c419a979687a3ac2180f94c8e50c293b627c0216f5c0ffa2c310b7d49ccbafa14875e8a94b3ef1e3ad7926db6eafa0e87cf04a8f5101a8407f0d7e731ae31ee23f14c09609c29e254dc781588648e89abe662fc5a79e30cd8559bae7db123b96f4dd878526374311b681c45ddad6d96a520a13d6860e967e3f7daa8718f86f5c4cca4309f5caa4646b2ab5787033553b4149de6d63aa4593a70e6486b0c3d4d02dce897d0e14bfa6bca6b261176ead285e7007905672a76754c8d66414d99781eca5f9e83fe7bc3066c139eb909d3156d79d1860a2650149683e34578f272bd185a93b0418e50844fc04b253504e8e2f7a60a50c1ddeb747c357f249164d437e0bf53a8df2a01a836fa69d85893ea895c449fcb7e6d7c9f24565848b97f529e376885a219640774898a96aaf7c1260b871246949f6874c23e28e2adc98b3d6e4fdf8fc091a45e75ae6503f535f4b1ec20f66b61152f63dd8e3bc512305a0cfe9bd09a5c65910586123a246cd8188764c5895d278ba01f91196f4c68599cf1b3b800c37bd3f813a5ce326b0d9952ac4b6b96bf2468de4837157451177dab8ccb5d90591f5c81f5d8f14855a22ca4e89522fb4ff333756021f4c3b5245738293d8c81d4b0dc7ed618ac14c712350ed97d1685388ec2e14317a2295710418889fc3e214d2d225869509b068ca5032af80db7587b759b4c073069a4c4fe9a8be40f39d500667dc720b90a2ee17785644a6a3be55f51260736ad6525d7e121f413165bb38142621191b7f21feddbb8a658cd013187b246051ccc0cf952f574148317571a6643666d9fdbd4fd7ed343519b791c131c68ee85850595339c962335351744db3738569cb5bd42becb2e3c0c2be214592d1aa3f1d3cefb6b364896cb12096b2491df4381d50ace9f766cf140fb289a5b6415f0fa72548ba6e54a5da261bd2606150ff6003c87af1a687512645cfcd2cb555962d59c5affec340c9460218541228c99df057601824715f38ba0a27f945125fa1322a02c4b0e3388866cb349f4d0a1e423cf20d41055a46be20e0a43d70183de531537c9ec0229a65168027494f19a4ce8ace666298bdbe3db10bafb4661d7c9f8b70ca955d7054a25dbcc6575a18979ce4d42118039a739811429d0e26f4f6b842890e47c6d5178d5f2ccac590157f9b35aa0746b9c9353181a546ecfc92131ba556c1638a9529c6688f037ebf8879e15ebaae9f881c9db1143d7509b2b8ca242ecd245dc0898f847b96bdc4c273908a2149817eb2bb0aa9963e54007767ea0afc0d9508f0e5039cfa257f19cb57898c52737f16958e30101d289a484e7e460643409126c6610a15570648a40a0233cbdf863cd1384299f6cd5b8a88c700bff8faf80bf35874a024db6164195bde038e2f61c4d9e6994643ef0923f6c795a8f2a9d24a2bc391b4046b8cf4bfb40287893254c493a70434b12af36c64d645ccd6e4bd8c003674bf315e512bc9d21b6121ad11a790197bbf5b453f8443449012544e02c5045705c908a89f2d1faf0309d0aae891efc1717aa3f32ce3645138c13125db68d06effa6436359783c4d863702e6b2b4f7eea76a4504a8d01d39ab252d66a64f3b19186fc5918f19d4a36d2415aa943d267cb5d4673990e74fb8ed8484af02df782cd23e302574069aba1a631959be32831c3a27b35a3ff909de8a1fb2a6c852fd05affdff5fa11ce353ba7a3b1e1920bb62c497acdea0243431d8ae65459e867aa8082d44a5ac8fee3bd3d1653dcd0d209a62c
+InNoiseSP = 6b8addd536524101c8fa265801addd950fd2d7b19fe4a590e175300c2ce7532a467165019fd7d1485a779105b51720b68eccc12c95622861c18d5f3679a2a11466ef66aa258e61cd0f26b2eda7f1400703868030296c41c241cc5fa7aac5212c6e52a8c20013d9017ab951af7513c82d1f8531abb4214cfcd5cd72377563db181ab084f6afca162a866a941a899cad20cc1156078a71c6f6f8662e6424f87b8e84aee1ce925bf273969256645e648ff6286677915257c2d49210a1b04e7b29eaf030ca2dcf8c0d3375096d41a904c36b2d1e9e466c73d319ba3cdd79b8081e1d7c6ee100ce0e7a40496be1f70e338edd9aa2e1ec869c859f1817456ee14fa8118f7832f50ae0e5a73a8964527d421b76678fe346d8f31511576e2c84ea6415d1061ec46455017fe70910d36c76cd131f272ba180ba12a3cb23ae6079892c058a8a0d01a54b398579b1ecc6a1f3960092d114343027695b87eff62bd35691251b935ab332aa00068a89fcf25b14d6e9084044959d830d686fb92ba222d7bb712c0572c8fb99eb4285fec5dbe5d7b83f8582c49928d65466c479831d116482cae805037ebc2200fbdb1519555c125db380ecb068df5efbd33a7df5c257462c3215ae29bf316d72bc7c4834a55332995ec99882efd9666be73afa6f8e0a3f877e9290a89bfe47110284b8299727c05a38b20807a93d17e4c55595e8a392deb58cdc568796b9f6bfd0d34b3af9318ff9955da956b5a555a023f6a68455a794e6d3c86a6c46a70591e598074eebfc87f348bdbb2b21399b3d35b360d429f341238d4ce695a8699f4c6a41a6d865a9475879a1fd9a0ae62808ab242920bcc8011611dc677aa938564b38b3911ae2721f02aa9e8701b686ac17984190ea11ecbd090e2a4b4f11821daf62f570150ba8ee08e0493e33fa0b108a9ba2a897859cc94a6545c34329462df93f84c3b35923cc0fac9442025cb028fc9519b70dde566d2c3f2899690cbf4b6656e979571fd0aa5af21123c753f1d4a4fc24db4ea19623ec2ae5cfb428d9a054c00eb53068bd37baaac8eb18723917ad7737e819a189928e8149ec83f7da1807fb21b5a644c3b4c77479529e4cd112451384275d869be843ce9479723d8a074cc66be5054197b9e0fcb0c2260e7219ce86c79e0f4ecac526ff5a716059e4a9a1f6501bacbf905a3c99af11e7e242de820b82795407da6ab558bbc4d5567e44d24bb8561557f49a675357893dc8d5e873dec55b62dc0fc77bd469274cc425c1a174c54ad6e6f649b38a8b6749101623bb5b2e38d1eaac041ccefa6c1569adca16843b059fc35f9ac600ca1a911940ab15de9c4c144a21e6e452899c9ee173113fdc2d90950ce26d38827c21c83c1e63e61a7a3d3a06e8171660467595b1671829ac485503164894bcf240d2a05576f20a78869a7899ab682c5fcdd067da91a099a64266ea34a513666e89a292bf1fac7ea8377e5b51e398e48ec92622597d03c4054cc94593175a28a1f981990509eabef568e4e65e99437a2b8291a2c60a6f69cfe8c82aad1759fafb716d63675040859821ab1c9be1b36c2265ac80360afa196e22c4a1d945585f4e2996b4e91866cc28ab21555954844d9e714d96a6145778a9e6603abd4ca802778ea5748a4799b7faa04345eff917ca729dd1a1e5bf88b8ddaa7a33aafa6e5eec53c7173222d4ea96a1446a512b6e12564c0048df48fb88549a37d2065904cf88b3804cc20136f98aa69cbca686115f9daed1a622746ee9993fea934ab3d991e2b2081202085e3ff568a098a39e81145a7a15bc48c26a47ae28f0691f33fcf8515345ebe88a09656544f3a17f5d41dfa4926815ecbc10424a9219e62a83584382fa38bdb00623ba0f20379691e17479fc8ebd12607bf3e4adf559e51a1a1d8788d32269187532c29982899e5a83b7c6d929584c91dc5769fa5b1489499b4fc4d5a479ce12d4b4b2067628c37205d19d00874d3181a0981718816202f6ad6c8de8fcdbe270a30bc6f1899c2e8886a1cecbf68e2542a7040abf2c0540a9f823997db447149503f4764706615db6655c0978e31dab5b256995a08f7110086602ac6f204b55799bc8f68616010c86c4a090cbc55b1385f3d231aab8988ee810249c4dc82bb1a96485afd3093976b54588b145a3e4f426bb80c32da5d7099100c54df1360d8001cee5b9d89c19d501fd6b9e7596b20969330a117b5c2d492950841acfec61e20bd8b55222389624716fe859aa2bd21043082b0b8be3991bf7cf8843f4322a6e167b24941e7ede5b5d0442c166d6a00a745d1c8cbcaa56889fccabe0ec2048cf6d30a98e64c5e152676f04b6b50d85ba068ef0c2a148731b0132f50f6e869022c446bad8ac219fb3c96e754092e6b7f64e608bfd0e72e7015dbb3c1f210254745e135bbfe8c46488a05065f7d97a90b61bfe24232aac498494f0f89d1e0293ecc78fec02c78c30a636bcaeb86de704b10cb411292b84027c1ff3460016b4cca36c6bb2fb32e040050b5c368082b9
+InNoiseEP = 3bc5cf207e017b682a21a47b75503aef0fe96bf80d73a0cbe9daf58eabed30e0c9d0a1fa88bb7a42761bb598d4c37bb61386a63344aa8c42a39b13cb87d902a112e264c4fc286e6703a6cf506e8fea14a1b4a4a03ae998b995909d2fca5196d80c176b1a3f351e3d7a56d08f8a235daf03c80a9501c08756ebf040190eb76e8d740223a43f2853f251432825485f97497090b3b9d7191925a28a70d32646b1486743cea5d364c248d3e474e27e8c173218428af32eb5780c4ff9c47c2c455d0b83f01089b3652cb921560f7c646c27e670a359537731cd9e149323df20c199b40b66c06642a256d016b4c56cba3de19be9853a30a39b2959cb215d2eac56d5d4dfb06a4f82da34cf108804d754587ab450f06327b2cd88550feadabb8e9d1404526cf74ea4125a5eb5c790ca16594739d54e946779abb3012689b6066aa2fb7d925b9893e1f067d5512190a349785c58db4c9fd265148d3344f5c1b3aa18928899b33aee55050451fb167811ae8a5c50b9f40400a4c28bba64096f088af54fe4885197b814c2be2dead7c2e7f335916aefd94297b89a384451b7dba87b01cbbc36c37c9bb09661a4f8389043253331e2cd6a41c948d6309284579dbb3648e86f9cde470b8400089a966888663117e9dc21580889bbe9ca2517bdb9b58d5740f0c16a8dbee0a3b1569c8d219808a9a7289b94268a23f1c958d2652877172d917da3d305757d098986f6e2e1e460a3cf4b0094d8a050e998a6b4885ad106f0c98b102b58c5c4b63b5e1d442974bad2f06c9feb0d01219e652e90db2338fe4b4041b665668c5a00a24530b3a181d2089bb6a4b599d2294d2036562f5047d8938715213f90630a58014e174f906ad0a20821a539775efda2b4e25abb4fd0090ddac2774db411ee4d43339c081aba8f62f0e291351b1fb84a3e28191714bf94b3a94aa529eac8b0aab51945d185ffacb823e163b379fda4de57d23046618180e0728367b262ed6da3629fd91e2baf7cb9d4d401d219221527da00a0a0c778621aa7bfa73a2677dc10ec81a1db301884b86e5b0ba0928e4d29e10b11243fd39990a25a416d3ea6d214620645969be0e634544df6c48e1643964e68a338d5633e4b085f2f36d234959b69b309f2f20015dbf9f71bda678b85f186d75999ec1c3da0b6128f1304976b381c3f2c118312af521b0f810ac1d190876c5499aa1e0a0c5e8b9d7975c92d31014177bb310c2a282be0740297629c54f5d1ae79361cc77650c0a6206fca4441a52e780bc22b71dd1dd12f4f5886449a1702cdf04c114c628e0d7975110e85cf045bb820bafa99432033de0408e1b81a12ee4f8a6f043a1d115d145d729b15e63db3d4e5926f76bca550785be6ca3e7b640f77e82c145e8b9717f2b61ba223248202b68772c9de72fdaa4bbcdf4ac433187a85ec03f8588530dfdd3bbbe5a0490294c5900f8080ba647bf3b8c0a6b624da805f4ab6f04981d550f29219eba6051058ba1a87e80839a572f76320a31731002184843259f656904f5dfae05c91c8df4350f425bde08b2b2651feb012df0ae777c842a44103db2c861b45658fe1413c256ae47ba944ca2f139338c44fa80e59445b88cf6156bfed02166df2b3970fa2daf1c9832de4f5a3b3b199108a0d2af2d237751e868a234a5ac36f8959cbda135e63ac98a91884ca6c62c9930507559a7d51ab52bf3da1a95b545cadc34afe4b1add66fe24b531380811a31d9716972c2e2e261b805c0a1ac70d956720902eec010c78c6bab20a2936522f75bb5dc361f494e289ef5ad6c8964d6dc8e883a1b0e036920a5e011c8416e881de84b809854ca0ec128681ba989db383a1827bdf8c61d997196ff8809f68c651aa6c27f0b825ea227ccd9972efc8a79d80a4a5fa0a23f9035298703208be84b5463a703356a7039563c627841786d0417579e69f495510fa6d6ba2e6e5d5de05de899f53d3f9256ce94079722c6d9bd16d220a3e6d399bff03088e38e3db2ac9d8f44fe426d3f5968539392845cbe00d8f6452d5f1c87d9a4745391338127996d52e49b809354fde1bf189297865aa2d712f80ac4ecdfde7c58d51e89cea5bd36690276b056b4569257ea78acbde485924026ed86d741356ad5c575aaa6200a5e18b81cd99332723133dc5a00595cd9a7cce957164b3e6adaca3f6ea7d687e444ef39269e65ec81320c5cd283fa250bf4bc246e5595600568440f73a0ca8a30da4e6ac8af4ccd0705ac62f3865f676ddcd9a85c38757f628bf0655ebfb941897fc62e5007bd145fd66fd78b5ad4bcd1392b826554f0a2c1702b45865fde2e1e7f4fe0f4355cbb20b4a16dd9fc0e88e7c57eaa8a7d56d21b89ee79edad6e82b950066f9c06050689b4505e396530c05940a92cc87d79531169c566960802de5b278168563d05908061df9dcbd31268e4429e008eb9e3a4628a194023d1412334975b4ac35a1e4ebf6197e6150b60ca4370a2e3fa9c897554e5a9fa3cfa5a647695c6ca865e402bc5536c2bd65e9112a
+InNoiseEPP = 00f0003000f4bf0100fffbff0600ff2f003c000000fbaf00d0ff02000440003000fcbf034002000008000180ff2b000400000000ecfffebffd2fffcbff0200048001000000c0fdaf00b0fffabffd2f00dcff02c0020001e0ff0a00010000fcfffebf0040ff0b0000000400003000fcbf0280004000f8bffcef011000fcbf0000000000fbbfff2f00d0ff060000f0ffebff02c000c0ff0b00000002800000001c00034000a0ff0a000100005c00fcbf01c0000000ebbf01c00000000800ffafffcbff02c0010000f0ff02c002c0ff0b00f4bf0480010000fbbf0200001000fcbf020001e0ff12000200000c00ffbf01c0ff2b00f8bf010000c0ffe6bf007000f0fff2bfff6ffe0b00fcbf00700000000b000280ff2b00100002400000000700fcafffebffeabf03400000000c000030002c001400fa2f000c00f4bf04c0ffebff0600fdefff0b0007000540ff4b00f8bf034000000003c00080fefbff020000f00000000700004001f0ff0600fd6f00300000c0fd6f010000ffbf038000000000c0feafff0b0008000030005000fcbf02000000001300fe2f0000000b00040000d0ff0e00014001100008000000ff2b00f4bf0280ff3b00000002000000000400ff6f002000000001c0ff0b0004000200000c0018000300000000f7bf044000c0ff0a00f9ef00f0ff020000c0ffebfffebfffaf000000f3bfff6f00600000000030001c00f0bf0100000c00f4bffb6f0000000b0002c0ffcbff0e000070ffbbff060000f0ff3b0000c0003000000007000240ffebff120005400000000b00fcef000000ffbf01400000000000fe6f000000130001c000f0fff2bf0100001000f8bffc6fff2b00f0bfffefff0b000400ff6f01400000000030000c00fcbf03c0ff0b00f8bfffef003000f4bf000000f0fff6bf0300000000f4bfffefffbbfffebf000001e0ff1e00fd2f000000f8bf0280fffbff060000f000f0fffebf0280003000f4bf01400000000400fd2f00f0fff2bf03c0ff0b000000000000200004000140ff0b00100001400020000400008000d0ff02c002c0ff1b000400f96fff0b0013000180000000fcbffcef002000080004c0ff0b0003c0fe2f000c0008000680ff3b00fcbf0200feabff0e00fc6f00000003c0faef001000040002c0fe0b000f000340000000fcbf03c000f0ff0600014000e0ff0a000240ff0b000b000200003000fcbffd6f00f0fffabf00b000e0ff12000000ffebfff6bf0140000000fbbf003000acff0a0000400060001400020000f0ff160001c0fffbff02c0fcaf0000000b00003000fcfffebffbefff2b0000c0020000f0fff2bf0480ff0b0000c00100000000030002c0fffbff0e000080000000040000b000100000c000c0ffebff06000380ffebff02c00030ff1b000400008000500000c000c000e0ff0e00f96f01d0ff0a00010000e0ff0e00018000f0ff0200040000000007000180ff0b0000c0ff2f0110001c00f9afff0b000c00010000ecfffebf03c000f0ff02c0ff2f00000007000280ff0b000800003000d0fffabf0480ff1b00f0bfffafff1b00fcbf008000b0ff0e0000c0ff0b0007000070ff1b00fcbf0000001c00ecbf0300ff4b0004000070000000fbbf0240003000f8bf0000000c001c0000c0ff0b00fcbf0640ff0b000c00feef00f0ff1a0004c0ffebff0e000070ff0b0004000240000000070000300010000400fceffffbff0600030000dcff0200054001f0ffeebf0280fe2b00fcbf0680001000f4bf004000e0ff02c004c0ff0b0000000300002000f0bffcaf00f0fff6bf050000f0fff6bf0200fffbfff2bf03000000001b000070000000fbbffeeffe4b000400038001d0ff22000000005c001400003000d0fffabf00f000f0ff0a00020000ecfffabf010000f0ffeebf01400120000800ff6f00100014000180fffbff02c000300010000400fdafff2b000000fe2f00ecff0200feaf0020000c000000003c001800003000200000c001400040000800fcef0020000000000000e0ff02000100ffdbfffabfff2f000000fbbf03c0010000fbbf0200013000fcbf020002f0fff6bf0580001000fcbffd2f00bcff160000c000400010000180fffbff0e00ff2f015000fcbf00c0fd2b00f0bffeefffbbfffebf0070ff3b0000000030004c000000fcef004000ecbf00b00000000400038000a0fff6bffcafffdbff1200feaf002000080003000050000c00fe6fff4b0018000180ff4b00080001c000000004000180ffcbff0a000070001000080002800000000700fc2fffcbff0a00fd2f00f0ff06000380000000fcbf0070005000ecbffe2f00dcff1600003000f0ff02c0054000200000c00500000c000b00020000dcff02000300000000000000c000500004000300004c0000c0feaf00100008000540ff1b00f4bf00c0ff2b000c00020001f0fff6bf010001100010000030fefbfffabf00b000f0ff02c003c0ff1b00fcbf00800090ff06000000001c0000c0028000f0ff1600
+InRand = d7e1e1191de63a93fd94e7106466467856449206e281c17eddfe5597c5ba7e7f
+OutPK = 73ae7fcb7366049e5c2060340422d555213529f573740c28c3f7e11191d2ff660c2c9789d31cc5cfc91227e48ec3c9593df0524f9998904f8d04d3a82de231ac4760a3097911c216159909a08c42195a7661ee825a93108560d582792bb5566f900ff301118ae6607d8282bfc340de1ea6463cab4734ad43e15dea831c599fea681947790c8b1ae4f24ed2460b68d371b24c80474ce5a551418bfed86f0349695f6adf26da3e9a65d3913e29f96eb9ad94452847d43b0aae7401d46aa384108de8ef5a906299744b19ed4f62ae99a6bd18580b6d736ac04a5c450901b8c61843470c23d37b964a200863097bce54f9588db1ca487107eed30630b013774770f881e9375e99ab44a978663d1a22b0bc3e38e19e4f1042e07fb8c3340873b60def9f9cd605eeaae4609742139517ce5f4080ca3a2e6b189b4bd26a6700d6bb7bac648774962aa27ec4a9c5c89c9b264d0757497b88825859cfa682db002a9665864b5a1d9154456a1872321e6f596b87a810aa3cc326070a06be443d5894e981bc4552abf2faadbc37a356f8e5f0655847a6d7aa8e8dad54442ce0154546f784609855b677986523c111b54221dc88e7a2519500da5cc2e9b0ab31db066aff6e3c1de5de84f8893ac361f494130943c724dd563070a23c0f7601ee0077f46b38033f2d493d29c27062953d7594f5c2381e5500ed684550b40959ce1a8327b474288e0fb052a0466a11239574f9ad38467541aa1276cee8aee57b3ea1f20d8cb40f74925415e8099c896e6fcefbd8574a47496028db135433d888690a701118bec07ed04150956586ef56a4321aa18a5197553aa37d1ab9a8d4905f4ece940b7442447f21048b562e75e490e46313a21866ae6be3951e3b9d8c56c940a46746d18b285e1c5409e5c6007b8214d8976e101c161e1e9aef577614b08b1db9d4ebcc2c568598e5d35a45394233254a651dd543db9081ee320207e173732e3c3f19707a0db288e2635029be6e7266d37332994c52e3d445573aa088abcb5faaa5de1dc801112649ed8f4e95190091e00482024a96d96e1a0b14d7c3374c2df96689e53409239f03d9e576c9a3da4725d4dbc58aab1f36a4ce346102923a9052f95703ece5208e9cb6580c9006fab2520549ec5ad3ea5ffdd7eca486a016cea353e89918a8aaee98fab66493c5e8ebb6e7b90da7ef7a812ea497541065098b265200ec25c6d4ba175b6b26e3b03c550668bed246ba5d178f260693858897969608116250652146d3819a5535efc598ab217ea94587042c15711590b3c0e746286a8c521806d99329a8f424c9046336578e85ab3e17ab40657a86b6b4dae8de63bb0573280417c7dfda172320613122592ed64572d38d94864884642553190af01aaf4a5439499883ded55a7a2e3e6b7fa06e909b225e48513cc82fcbdb9c497cba02c06eacc707d5b4825ffad9ca16589fe2c7a365de96b7e2d1a3b7a54ccad5f0f0777834a41ef870ae4560158d35e7e12902b26325d5e52d3efdca6290e3b601f581454236c89d1d9ba978760eaa1018fef4482a6111eb871024d81429915ce552852bfb561ed55bf14eae24ddbaa024935aad9523dc8e7b5dc72b933404ae6dcfd97a8cfe27865774966d74b8cf53df557f8d9b8203fc3824dd44658c23e3e39da6d0c9d007960469768352c42a6d8e34940d93582559494ef581b7b2a45c294de684718ea09009aa1778925818d86b0ee8a76bee470246e480b76716497aac21a9173d1657488a24ac57824174372e89e8f369586ee4545a06c2f960ccab7e21237d9b0a44243082201c57d7e69be972b5f899438a54d490e9c255c222f64ebc4165a95822964242cce9773968271d15081e821931ce05f265441a226d8435ac0a163849c945ad9a3e29c64fc4ff8d298f46d683ca240f0fed020189a9835c592d67777e3b0f559be8dbfd377594a28a55a85fa8d415e190616eb0e2a4039f8cb9c6a5c8251709b4fa9992f576fdba9355dd283d6646b90a80b2e7c54d4f69c97366f884571c5548cc7c5671d76ca5664abbf75bcec6ce22554a68c023b98d1387090f91f0318d5092c667e2124da5540aaa5c4e2dd6638d7751940dea57df2726e151e5a2332bd5d608e169ded8e4f2adb9cabe03afa2be4641879a36e40054dc2f5be00405b71ddba7774991678b6e39cd2c7215ce06e1bedc8b004af437b579273303f8637840487002ff38d176274c156617ddf1173653a9967df61a144b61942b6093d18e0a631ab58539824a70b7b181d36339169d3d44f903fea37818983d663baae9401d3edd00e3ed6d704784d2208d584c5d486e723e11691b4ec8cb164c78c4208e24f0d81a33d178a4eae516a0130c499cb56a4ca4d5b1e54c73e28c70394db17539a958a036123157e97612caad06011c57c5e0be2484d17ee7304824845aa2c0142280e5aae956264e71865958c671652c4f440583cc4e9df15235d90b2c8d5298bb9551de2c14cbfa90cbd283d6a4057661582b55da53e2d37134
+OutRec = 0300002000040000c0001000000002c00000000c0002400000000400000000100000000300000000040002000000000c0001c000000004000080001000080002400000000400004000300004000200000000040001c00020000000018000100000000280000000040003c00010000c0001c00000000400038000200004000300002000040000c00000000c000140002000040002000020000c000200002000000002c000300008000040000000080002c00000000c000080001000040000800000000c000140000000080003000000000c00004000000004000140001000040000800000000c0001c00030000c0000c0000000000003000010000400000000300000000080002000080000800000000c0003800010000c0002c0002000000003c0000000080003c00030000400038000000004000300001000080001400000000000024000300008000240002000080002c00030000c00030000000004000000001000040002c0002000000002400010000000030000100008000300002000080000400030000c0003400000000c000100002000000001800020000c000000001000000001c0003000000003c00010000c00028000200000000340000000040000400020000c00018000100004000100000000000001c000200008000240002000040003400010000c0000800010000400018000300004000100002000080000800030000c0000c0003000080000c000200008000300003000000002400020000800014000100008000200000000080003c00010000c000000003000040000c00000000c000200001000080000800030000400010000200004000300000000000000c0000000080000400010000c00030000000004000040001000000003c0003000080003800000000c0003400020000c0001400000000c0000000000000c00030000200004000240000000080003c000300000000300002000040003000010000c0001400010000400020000300000000280000000040000000000000000008000100008000100002000040002c00000000c0003800020000400030000300004000280000000080003000010000c000380003000080000000030000c0002c000300000000080002000000001400020000800034000300008000340001000000000800010000c0001800030000c0002c0001000040003400010000c00018000000008000140002000000000800000000c00010000300008000040002000000002400010000000038000000008000280003000080000000030000c000080001000000002800020000c000380003000040001c0003000080001400020000c00028000100004000380002000040001c0002000080003400020000c000240000000040001400030000000008000100004000100000000080000000010000400020000100004000280000000080001c0000000080002c000200008000140002000040003400000000c00028000300000000000001000000002c00030000c000240001000040003000020000800018000300008000000001000080001400000000c0001400010000c000180003000040000800030000c0000000010000800024000000004000280002000080000800020000c000280001000080000c0002000080000c000000004000280003000000000c00020000400018000300008000380000000040001800030000800004000000008000000002000040002c000100004000240003000080002400030000c0000c0001000040001c0003000080000000000000c000380002000000002c00000000c0001c0000000040003800010000c0002c0000000040002400030000c0002000020000800008000300004000340000000040002c0001000000001000000000c0003000000000c00030000200008000140002000080003400030000c0000000000000400014000000008000380001000080002000030000400014000000004000080002000000002c0002000080003c0000000000000000010000c0003800010000c000040002000040000800010000c00014000200008000080001000040001c00000000c000000002000040002000030000c0003800030000c000380001000000000c000000000000000002000040001000000000400004000300008000140001000040000800020000c0002000010000000010000300008000280003000040003c0002000000000000010000c0003000020000c0000c0001000040000800000000400018000100000000380001000000000c0002000000000c00000000c000140001000080002400000000c0001c000200008000000001000000000c0001000000003c000000008000040001000080000800010000c0001000020000000038000200004000040002000040003c0000000000002800010000c000000002000080003c0003000000000800000000c00010000100008000080003000000002400020000c0002800010000c0000000030000400
+Key = 8b02bb704b579798db6aa226b731347518155ce79f24d9005c79f17d5baa5b1d
+
+InNoiseS = 55d10f4b48067ba8ef2308defa0285cec13987c82d528761f851ce55ef4f40659ebd2f0b6deae54a28ad4dcdcff387b99a8e4639c0cf354127186a92f6c0b1735f6d34d89596800646533332b2e5dab016a3d5129f8702223a94003c03774bb2061d322a86d3b7727904414df6c1c03c1a680863a43a09a862e6a0a0921eeb4431188c4c7b79edd293f24c3a1496763936b23d599d922b82663fe59836743d843046d5ac7493a95e36d16b770b7a47bf5b958355fc289c653e4637dda5ea68d40253440eb96f5976ad7a6248a138e760352792267249e91239050d4cf24406a57b2d98025bf104e587632aa7c52f65e781561b0e71c5ce16f371fe50da1f6008f2824828523fd3e2a201050b17a2b474491d49a0b36c8c34eea3adf9339c20a651d6eaa5205f406d933113816e1b5e587ad49a09de8e6e6630f60ed96163833a8560385c1b2124f165ece2ec52af9a9b612f9dc03a81190e5f46eaeda60faa0b7fb79c047207cc4e48078a46a0c49cd1132e9c9a00f85a193551a8cb4b99ec1d6c07491c114969b652935a82bba252326dab5440cca66fe24c37fae468a32b22d21540862f062c148fbda0f0a320ca12ca1ddadc661b19b45c461a38171ad57da96b89c01aba52ce596ebb325a22016e2070d5420284e4a319bf521480181ac4294d28ee037016f03149ad538e632f3c274a162e93b982079fa85aeadabe3cc58671e4bc0a2604243037ae98211789dce0b5a59dd89cfd5b13c56c97d520d73a4c373501f604c3316ce255df320b9494d10d9415faed012ac6b53400bc6d47e3307852697a142c4a9bd28a16b11cf93af3914d31e020ebf4ce8dd41aae69e8885ba641b47352212e69c03f932c5c4d54687a3503288ef5c3d6ab83fcaf2059e9098b59a898c7801683d636e45cbbabd1d8268606c3764111666fc3d57845891126dcd9faa5191a8bdae12466d62cffca274b10129b5d1d5caba36c15bf1e7de911b471a3c7a82ac6ea2374122e2770f8237c0d48e4e25c112b2f6659582567088482c9e9e0789191d226353878202120448980a6b7069bc71bde617452fd2317ed4e989f771032c46ba99724806f5998c8e8fe940b7ea24e6291ea5e550e7e5e2088dcdc6c60dee55496f22c870ca597357d728a9e45c4a8a44c984f48a62281a994098558f77eb70d2b690601a92c8327ea246355744ad97d912ca63d84eab3e0cfa521ce800699989a79269d10fb9285826da751db0dee4c716eeb946b59bf312226e7b95171915ea15615a1bb1c59a749cfb12761edd989e08a79079af4a781dc4f5d6056a91a0661742e5d54673a6c1cec1013739c2e71df299942769ef25da2e5daba26f9addc5155a8608aecbf53254c2d27a588b0823aa54d0bc24a2131b7d842edb3f9666a798f3e86abfe279d86259165bd93e8e7f913ab7d14a94f40cb44062a3d2728e9029ebaa6865be89d7d052c049e7389ca866022c267a3392f689d7ae627fa3b58141ab762d10be4e6d8752edd88cfa3985bfc723023dc380398ee9d9b9b9153a5a06eb295858397fd7719400f80e38aa18fd1eba6c324b15726f4907b84897aa3ff347578a13f1b905a148db1ffe55813c17831f54ab7eb52b44545427a25c17481d0851b590c4e1ea2682139c421108dd2bda3fdbe90549a7548e1463cf0a51e4abe1c171f4866191cba036d270248635c48848fdcb690a0bae3240029cbd688a4d6f150d08d6a0b4e62e2714e57806aad69420c71a72788c996b19b5fd5870506262b878e354056ed2dc4cc6bf00e59acd15ef776d1ee75970799c95a5a32814f8e790d459d32d4ccd807117acf2d2ff290a57342e9b439fbc6163c268953fcc0444d5afd040dc035a3aaa54884c09b4d60f2c0cf2c1e91cb1dd5573e26f3ca8609d3d582c926d429005891c02699e5d3c40eb203a8641fb8bc5dc13a04e832b954cc0003988ab691495e5662e21afb22ba667836bb7f177301005ba3124e4f947f851e5de9b8042b5da3476cbee91e588626da672217be58d146a2f3eb590be8832595455972b5531a87b1e63c20ec19bb9ee925ed1d5c7765b19c199769920d8c4ee6d7eaa3973995011e9e77c6de17662beb49ee169dcda4c6d7091459794277a0418c55926bbbc83a320cc38de4126612a3bd8a55ebfaa897c9e17082319d71b2c964ca7471721e96c69bf84d2ce9149069e119b3f40617d20dc20404dd587aef66972f14369056e2673c5cc54877f69bf8e0ada3527c58c9d8c408ce218c04858e5b94c4ba2e2da592b4c0bfb2c9e0a894e614e7a21baad239149743d1e4b3b068c5c324e1080c09eeca22487b2d807620ff20f64eb1ce404ff82f3926c0673b4341c6a6a1005b08e1fd27578ed1373af6879be3159b2cad27a29eb0c9fab2358258d0a946b1396e6d007995c291cbee1837b4454a13c84aa7b4da799bdebe33b9d2879d11f02008c82a7f9d48c33e5c57a74f731496b62a180db690406a9d8828c13550093aa1a29309ffb96adb68cda1a1089a
+InPK = 73ae7fcb7366049e5c2060340422d555213529f573740c28c3f7e11191d2ff660c2c9789d31cc5cfc91227e48ec3c9593df0524f9998904f8d04d3a82de231ac4760a3097911c216159909a08c42195a7661ee825a93108560d582792bb5566f900ff301118ae6607d8282bfc340de1ea6463cab4734ad43e15dea831c599fea681947790c8b1ae4f24ed2460b68d371b24c80474ce5a551418bfed86f0349695f6adf26da3e9a65d3913e29f96eb9ad94452847d43b0aae7401d46aa384108de8ef5a906299744b19ed4f62ae99a6bd18580b6d736ac04a5c450901b8c61843470c23d37b964a200863097bce54f9588db1ca487107eed30630b013774770f881e9375e99ab44a978663d1a22b0bc3e38e19e4f1042e07fb8c3340873b60def9f9cd605eeaae4609742139517ce5f4080ca3a2e6b189b4bd26a6700d6bb7bac648774962aa27ec4a9c5c89c9b264d0757497b88825859cfa682db002a9665864b5a1d9154456a1872321e6f596b87a810aa3cc326070a06be443d5894e981bc4552abf2faadbc37a356f8e5f0655847a6d7aa8e8dad54442ce0154546f784609855b677986523c111b54221dc88e7a2519500da5cc2e9b0ab31db066aff6e3c1de5de84f8893ac361f494130943c724dd563070a23c0f7601ee0077f46b38033f2d493d29c27062953d7594f5c2381e5500ed684550b40959ce1a8327b474288e0fb052a0466a11239574f9ad38467541aa1276cee8aee57b3ea1f20d8cb40f74925415e8099c896e6fcefbd8574a47496028db135433d888690a701118bec07ed04150956586ef56a4321aa18a5197553aa37d1ab9a8d4905f4ece940b7442447f21048b562e75e490e46313a21866ae6be3951e3b9d8c56c940a46746d18b285e1c5409e5c6007b8214d8976e101c161e1e9aef577614b08b1db9d4ebcc2c568598e5d35a45394233254a651dd543db9081ee320207e173732e3c3f19707a0db288e2635029be6e7266d37332994c52e3d445573aa088abcb5faaa5de1dc801112649ed8f4e95190091e00482024a96d96e1a0b14d7c3374c2df96689e53409239f03d9e576c9a3da4725d4dbc58aab1f36a4ce346102923a9052f95703ece5208e9cb6580c9006fab2520549ec5ad3ea5ffdd7eca486a016cea353e89918a8aaee98fab66493c5e8ebb6e7b90da7ef7a812ea497541065098b265200ec25c6d4ba175b6b26e3b03c550668bed246ba5d178f260693858897969608116250652146d3819a5535efc598ab217ea94587042c15711590b3c0e746286a8c521806d99329a8f424c9046336578e85ab3e17ab40657a86b6b4dae8de63bb0573280417c7dfda172320613122592ed64572d38d94864884642553190af01aaf4a5439499883ded55a7a2e3e6b7fa06e909b225e48513cc82fcbdb9c497cba02c06eacc707d5b4825ffad9ca16589fe2c7a365de96b7e2d1a3b7a54ccad5f0f0777834a41ef870ae4560158d35e7e12902b26325d5e52d3efdca6290e3b601f581454236c89d1d9ba978760eaa1018fef4482a6111eb871024d81429915ce552852bfb561ed55bf14eae24ddbaa024935aad9523dc8e7b5dc72b933404ae6dcfd97a8cfe27865774966d74b8cf53df557f8d9b8203fc3824dd44658c23e3e39da6d0c9d007960469768352c42a6d8e34940d93582559494ef581b7b2a45c294de684718ea09009aa1778925818d86b0ee8a76bee470246e480b76716497aac21a9173d1657488a24ac57824174372e89e8f369586ee4545a06c2f960ccab7e21237d9b0a44243082201c57d7e69be972b5f899438a54d490e9c255c222f64ebc4165a95822964242cce9773968271d15081e821931ce05f265441a226d8435ac0a163849c945ad9a3e29c64fc4ff8d298f46d683ca240f0fed020189a9835c592d67777e3b0f559be8dbfd377594a28a55a85fa8d415e190616eb0e2a4039f8cb9c6a5c8251709b4fa9992f576fdba9355dd283d6646b90a80b2e7c54d4f69c97366f884571c5548cc7c5671d76ca5664abbf75bcec6ce22554a68c023b98d1387090f91f0318d5092c667e2124da5540aaa5c4e2dd6638d7751940dea57df2726e151e5a2332bd5d608e169ded8e4f2adb9cabe03afa2be4641879a36e40054dc2f5be00405b71ddba7774991678b6e39cd2c7215ce06e1bedc8b004af437b579273303f8637840487002ff38d176274c156617ddf1173653a9967df61a144b61942b6093d18e0a631ab58539824a70b7b181d36339169d3d44f903fea37818983d663baae9401d3edd00e3ed6d704784d2208d584c5d486e723e11691b4ec8cb164c78c4208e24f0d81a33d178a4eae516a0130c499cb56a4ca4d5b1e54c73e28c70394db17539a958a036123157e97612caad06011c57c5e0be2484d17ee7304824845aa2c0142280e5aae956264e71865958c671652c4f440583cc4e9df15235d90b2c8d5298bb9551de2c14cbfa90cbd283d6a4057661582b55da53e2d37134
+InRec = 0300002000040000c0001000000002c00000000c0002400000000400000000100000000300000000040002000000000c0001c000000004000080001000080002400000000400004000300004000200000000040001c00020000000018000100000000280000000040003c00010000c0001c00000000400038000200004000300002000040000c00000000c000140002000040002000020000c000200002000000002c000300008000040000000080002c00000000c000080001000040000800000000c000140000000080003000000000c00004000000004000140001000040000800000000c0001c00030000c0000c0000000000003000010000400000000300000000080002000080000800000000c0003800010000c0002c0002000000003c0000000080003c00030000400038000000004000300001000080001400000000000024000300008000240002000080002c00030000c00030000000004000000001000040002c0002000000002400010000000030000100008000300002000080000400030000c0003400000000c000100002000000001800020000c000000001000000001c0003000000003c00010000c00028000200000000340000000040000400020000c00018000100004000100000000000001c000200008000240002000040003400010000c0000800010000400018000300004000100002000080000800030000c0000c0003000080000c000200008000300003000000002400020000800014000100008000200000000080003c00010000c000000003000040000c00000000c000200001000080000800030000400010000200004000300000000000000c0000000080000400010000c00030000000004000040001000000003c0003000080003800000000c0003400020000c0001400000000c0000000000000c00030000200004000240000000080003c000300000000300002000040003000010000c0001400010000400020000300000000280000000040000000000000000008000100008000100002000040002c00000000c0003800020000400030000300004000280000000080003000010000c000380003000080000000030000c0002c000300000000080002000000001400020000800034000300008000340001000000000800010000c0001800030000c0002c0001000040003400010000c00018000000008000140002000000000800000000c00010000300008000040002000000002400010000000038000000008000280003000080000000030000c000080001000000002800020000c000380003000040001c0003000080001400020000c00028000100004000380002000040001c0002000080003400020000c000240000000040001400030000000008000100004000100000000080000000010000400020000100004000280000000080001c0000000080002c000200008000140002000040003400000000c00028000300000000000001000000002c00030000c000240001000040003000020000800018000300008000000001000080001400000000c0001400010000c000180003000040000800030000c0000000010000800024000000004000280002000080000800020000c000280001000080000c0002000080000c000000004000280003000000000c00020000400018000300008000380000000040001800030000800004000000008000000002000040002c000100004000240003000080002400030000c0000c0001000040001c0003000080000000000000c000380002000000002c00000000c0001c0000000040003800010000c0002c0000000040002400030000c0002000020000800008000300004000340000000040002c0001000000001000000000c0003000000000c00030000200008000140002000080003400030000c0000000000000400014000000008000380001000080002000030000400014000000004000080002000000002c0002000080003c0000000000000000010000c0003800010000c000040002000040000800010000c00014000200008000080001000040001c00000000c000000002000040002000030000c0003800030000c000380001000000000c000000000000000002000040001000000000400004000300008000140001000040000800020000c0002000010000000010000300008000280003000040003c0002000000000000010000c0003000020000c0000c0001000040000800000000400018000100000000380001000000000c0002000000000c00000000c000140001000080002400000000c0001c000200008000000001000000000c0001000000003c000000008000040001000080000800010000c0001000020000000038000200004000040002000040003c0000000000002800010000c000000002000080003c0003000000000800000000c00010000100008000080003000000002400020000c0002800010000c0000000030000400
+Key = 8b02bb704b579798db6aa226b731347518155ce79f24d9005c79f17d5baa5b1d
+
+InRandA = 711d61a7cc0a64ee994d801efabd24af23056beeacddc2a453dbb25eaf9b22d6f8aa0cf11781712ea06ffeeb5adb4a20669ceb8e8a6f7867c55dc376d941a1300e68b06110738e1fdad3c68ab12bafb8d1ed723eb898ee9631304bd843dcd69c6a3d7659a872f74529ad5ab697b285361702dad750299cdd0d3f10cc680b94134898200463ee1d45e688520118cc162872fe87aa6707c57e291d490e6ea92f624f1218212ba4d08818960676831c2d21939bd680be8c0face78192423b97a37f4aad65ab00d24fa7aa8a13ef6987716ce45a2bddea183c5c37a6a64faa3c1a345f0ab811b768454c1b9335c5cd8db96e657a0cd635a20dec30ef425e18957053f28174f9514613a7685fe662c007f61a309959b8a09b22b341630c86f04870af4c57c64e6181f0047d955a2516b546fda3799e8ec3472982a57d249f29e88bb26064541da9a8867975acaf7861ecac944b2e37b8f7194a725342505e9855334d5dc6c7d8ad864856bbcf50490f23fe86e452b04e0134f6665295c26da31211890b9c5ce243713904415f8e71f42c0955e723815f7cad3726fc2a3ca861e7095f7277ceacd9a88f93c71eb70a9bfc600d7d959ad6171be74c29ca4d980676120c59879bb1de4c4369223e15c6f43d8b1e4e94344636f8496cea5f8d696f1414e3c5a20d239c75d0d21289615c2ad12c9654c623b24ae0008a342d8994c0ecaeb211c5079fc81d7ec6b0407d6ab042961d0962b21e23e09f11a39459095e58b8fc30b93618797954e1b87a0c7f42b5e28591c7cdd2a58e6f039a4ad3b054a328dfc0daf276b586dcb4c426c4406aa528f5f4fc497483312b7d3825b30cdfc6756852404c148bd751be30d2143a2ff2383d4fc3419c417c2093766355e938fd43263bfaedbeec42bab1d9f6ad8e90aa58d03c033720aa30d679085b4029a2cc048ae8545b791a253efea4464ad8d6b44b561395679c418e6a6c67cc7147218ebcb4dadd1d5f8d0dabbd79538d81b4d22151550dc8bf729cf63338ea5c4a950e2b50e2cec5a25187ad10a12729ad62806a92035eb49cf04e8fe35f1c40811a9987e0d06145a1eaab26d14a7e0e15bb7d4533e42dd2d430de6faccf2a25e3c132579e1a5103ae457a420b25392687a0d813e1caba3b1e11635198cd672eae29a1cd9d97478e2c6189b50b49ed4e68809d0d15035cfaf6943a378d107044f6674f9d811acad9757be85df6e52c082ada6d2688f2a6e12e4760f24abb3ba8f1d9d9456c94c20b3711dd01349fe70b16711f7209f1921e5d81ba25b3ea9af2bb51ed71215dd41a096bccc14ac4476e8e7702f9fd5d19e40bfb2e5164435534f1d48263afa708469b340d0aae57b1020988fae64c662e017ec68a4f7aa5d1b1ec82edf365b62d130e8ff28f6d511f97b166d1bc607b127f4a612e9bc5445f6055e9192529e528be112757a0abf2bf72544199806944e04b53d8e45a08fd96c9939b9874e9803e56bb16608a47cae265fa023d799646e0775c5c0518825000b872b7d65653424b050905e02ee6a732717f5a12b1117923376d9b8a728c3a24828123903426c0c27f9bbba84c94e18259bf2e0010244df8edf6a938ed1787796c32f4d26878e1cd7b520197c8838144f82c5c3a2e5837a89dcd95f6d29dab9d72ea63d41c9e072b67c61a1f182c2368c4a22fd46699e4a5d6a804eb6e974c8642f5ce9aea803522e66f81b21bc0323ae9410673a43683cdf61befa5b19496758ac456155103a38924f613215271c18892ad96dceb7a32b10a8e1e86d9588c7a5ed9690154f4629909e1d45b545f74a14480de196fe58b332a13acb353cad15bb85d87fb458d6b4f225524d3ad87d0985a049572a0f16ca1f81b5f550a4127cf9c9e9b5e39552042e624ebdc96f35f48647a5c5231889db3ba0ab8835aafd76719892990b2b75931568b9213b96d6da5c01455d5407534ca64f7d0a55a47c44f85e221489e42932d80e5d261d39159176dda667b2d2f8173798ae841e7d92b6c3f450ba9172ed635dace2592ccbc477cd72c2661513701262d84d9bc6611da3c26085d6978000f322d80374f6cef19100625972fd08610cc1810d147b6b7700872a4898718a2919d82d3e9f9d8064069d41301f060321e9b19f7851cb36b0f298e9d5cb4104feb8aca16f096390ada458cf0026fe6c74299e35f97b682d82311eda63b640991e651a940c5be02e74b2f74fe4953d61d09278be62956dff441b45434035ab0c9eb05543d8c6a2a480c0fa419b9e999844f5a5f73d4627104de298e80787542730d57d7ed35236be32271f1d034562b8484bfa101926cbb5098fa18f09a1ad54b0d1556598d9178f602b4deda672ea147e8c4e8a5029003f11a1df1cb6e6f17a24010630c908096a3712ba2b94717448374389aeb08c783adfd9491aaea0746481a6a24757712ed94992aa6e6b715974356d061c1449b1bd11cc64eed6b5c24f86b26a872a49936db6b9487c0cef621fe16a248921386c9dc49bb08c1c15d2061
+InNoiseS = 4ca10ae48258b14d83e48384f858eae4c130e49055a044c78590f0a74f1a19e8edd427300659bb38647c032c5722a6ac4b05413b4a0dc870ac1b16f25099428b9beb83af39887340a1c4bd986241429eb8eec081442a418b10ac60be94b3e34374a63c5582274aba579a03202666b16f3066985a26b96dd8993e242ccd6a3d9a2d287fdc82da9091830d0886b80bf3419ae968c615521160e85676c96af65dd92ea10e2c520bca4b882326b7b2c131d22d922827c5b41f2f33b281b50e8b64d92ac48a9bc4516a39272018ef5b707223b59bc2e07dd6831015b610b04638aa9d949cb7444c7d3162cf3a088b628f73c93d66375540330ac2d871d4b0405421caa142a0a2effcaacfe5173862deb228da286993d7605db54efd98f122b1949be7a15481fbd23d97d588b7bce9bf4da31481296149138c1b5753caaa9428b6d5f3be48c69979d351525c61532bf5535aa7d72850c294021d1614fda36c781f2ddbf10a4f723e578a596092ec312827ae456cac024c5a44bb68e5175025ce6876aeb1951d022426faab5a0db9d0cf369324a153533fb50b5a5866c77c00524265020b769517d7970918f5d2bc5a6e874332186d5f9e7a3a03aa28a39de5078002c0845c9eb74791088a81b185958e014f95d1219d702d2ec39a772fa82a3c91fc873a991d54c3c0babb64a7bdd15e78232d3b71a1c08bd60e68fc2f5e46348c8b948c1f93860eab88d24b736c785f2a4564a6754492c9c988c786166708d2b240d3da4c3280bd5616c0aff7a81a9a560809766df9b27e014c6c8aa45b38a6416046ba4b560804a90b54c3f5b6a2abaa7149968c8567c0ed07f2ee99218ed52b88bd98624c1c91b9ae1b082b6d07c8697eccc6a953cec576a25cdf548866a1cb03ded4fb26a1afa6c9287050459de64af1aac1572b1509643c6407f5d4a944904856c42f770717adbc701ff3c9f44aae6bea40c50bdd9f1f9368b667286732023d89581e7f872639f19766b65305b07babe9003e631b6a32511e690a864a18d45263c9436a0f1245db4405b31e1d9a6598922ae6f09a61975b3ac27225baa60e1bf6f01b8a0c07988dc9167648e9b1891c3e01a5031260cd52d08cce39498835b9122ef5d4f24f34c7623448294c4da985b5904583bd6f7e301bb911abaf1c778ee1567e8f4df0e05479cf1b5854e0cc7083a4463a96f2aa4d28944147464d249057b13c3eb8e0e93466a70194309f3339ef597459e9ffb5b15a1cf080c34713b819f6051d2baa142b9602460ac3451161913bd960202f68092c456b6ab71c638877f008862904b3fa62b815414e745b2309629d4691e894282c37e70ab15a82a7b055157b481552c6ee3ef7510a9d9420216b7f2275ef64dab95cc86b3e8ffbcaf508bafa0251c4755d287041290b4f6675f22d3ff9c31808c29d8281f2aaa7c7dede72a42592c10b20a35cee60b31b9d67f5ea6adaa33fb3dd911816aa142975551ebd40569bb1fd904a504b7ac811234029921b6b06b28a1df7c2a2ed59a4ad3541f8852e815b08c09444809decfd2904a62d991cc3c6659d6d4c6906d482bc03cce05cbb9ae142264aeda128148084c5b93b831458b061dd99e94e60a1ef51199f550156047901792628c6d5ff316c20be6d5ea59030d6abb624f8909e12a02dcf69f039ad45ffda6113f2f6aa9be6bb934122ae2de84b7a0add8488c052aaf50d0e098d58c7be3c80fe946c566c00b4739fd59aa2de006885b0cb9c65231f5fa760af69a929443aa3252aa16497dcb2c1180f42cca1310b99278a956a07cf540561dc0bb9e8b6b2ea25e57ae52d636b6297a2afbcb6d014942a33ce4869829de6f1ba761b60b6b93f993938884076c1e4976848f8bb6c4486daddaae7fb8073749a70f0eec61ff2c9687184c09bd15f849108700efe8a01b72c9c97d40957b4e3d64533411887541a5de6518ab756994bb5ed9f7af8da0bbe6959c57e4a2f346884a6716a847015c5545d69770d56d44500097f83ee4b736df867029d979848b64a2c281b2ac3d140ed854f12fd946b770754139e0e320223dac9823a14c28cbae29dc4af992ced62ab7255f265c533cb54b75f48a8321e7aa8f7939c468d26645c57b4abf0569260229a40611920af1add758474b8d026f41785559ad04faa501a649e44abee8607fc4eb21376552ba48931156485c7916d4d63247a757d4f92cf34322202b94acdc3276d99a2a899d3471475bb268ef9ea9976a949437e30e168301d027518aeec04ffc4294a00a2649b271b334f3cbdf88678b8b8c583f62c0815937667aede6ae53aec271e5d885a84b58d348449aa06649d6a635bd7d392885a0ae60218d8a085a509f5e5ad12e24c4d36b04600c0011623d4a4bd2206fce8d5003234405db3ad7e3d4dd6aa790abc6b1e49e8b26436ae6c9f1010b1e052158639c1582d641d8b3ed0a9c289aa5eae66e66a43048876b14cf4a69489224564c4932adaaf83e2b15e0b2248425d71198849f534d801b24cccb2aa434829
+InNoiseE = 349b8309537882c618c642ab2d78d380e2401039ac30ec4fd00536ad1d6297b1a4cc7dad96c8385cf90ce6e5f6995dfd317a510bcabc18a58ea4959286c491ae000ca949f92137c851e143c574b66e510b66b05ec661bcf0d32a401450af69e8a8943cd8b807ecc8be785a0ce5b840200fdc4c41c7a48fe2625853a59d807452ae647f3d139a97cb66aaf2b4988095d52ecc17e6a9ec41ee8821fbeec2d03d7a2466a0af2a211e718bded74735ac8e6a63cf3b18f16ae61619263bfc065e9c2197b9ca9b48e2ae35ab3c0500684e86c6e55e34a4d37415864578484180f53c500a16b601232987cdd02994ef560a8cc37f205ee27712e4a39104c23ec69e03c98c5c403cd7fc2b3f22aaab0c8dc50e6557995468564c100e37d009228b7a71fc98abe828810d4ec0a208103c1e5068029a86a8abc4e0516a96807de96a38ba7c16bd1e2dcf85d7ec192e9fd9a4822207640d6681b45c4f0d1b1ba2739ea684676278a5259e8166357aa6b90a1cccb8001e7e3aac2eb6c713a9705daf156015ccab64c49509760d4b464462ba92ce812aa10bd195c27e70a6254208929bcf85f5f23f583e1ec4b60123aa3d9217f37a33b19bd120aff2e13ab15a534d669701a9cb650a58958c5900a02938a7fd321cc4d07a0f4dbae65d00d44724377aa3ddd4a37d368995cc85fe5672d68f3c453b286fa5cc0b3322ca8d3eae302b982e732fa369c89ada8d45213ba560797a81d54f437a1e8708856781dbe5a5e013676bdfbebb758d41a500f466aad9ce997fd566a143dd299a5a51494de7aad82a820cc966901b9e0f326bfc01e77e7b78285c60fa0064c0e0cdd5e54112e51667323c9c4f842628c20128489ce13cdbc4366c7ee94791d936adad0c9a290e78931a2adab935664ab195e998108c50490bab1ad28a77f5a6b296dcf51e1b5850d2b9ea41ca1f45d96a1660ba055d1b441cb0702a8460dc1eab7642ee35f352bffd638be7148dae22cb8300e435364fe6481052506a9529426803b236ba6d8497214529a6ca9935ed79bdab27ddf330c20ba1d5b1959e487a206bd6706fd51ae3ecac0a7029485d13c9a84d1a1e0d9446a46d7c046ddef9bb50a5ada49a6f50612906b2423a4a7d30b837e39640b196a6a98175f05ea02c624c57186489be678f7981d5918c8a59ef3618245f45d5182b33ea6f7fa2f92004b043ffc9a4b88bd2b319c5f3a6a1f93511ef5ac6e9c2773beee23533b175cc67b6879840bb002bd6b45055a5f2acb6e8e3ad5cba250510c6758ff59e8257b051a06d8dab789d856165eae7c057c22e6ca3fee36a20052ac6f5f583ce2c1e48b172ca815bf84d263bbeae1d88679df8681661fb0650a48cea4ad15c78355429048a91a847d3c45c72e964db630073049a6ab35a9e1cc15aa979e05e81f8ee5945b289648025f6b86a489bb75023eb0c2a035cd211e5a88a3daa479c53098184359ed6e85a3c3d29e6f6e66e1595b3aa78abccb5485d67a741e211436513dd5ac5047068aa03ab59890bb148d809cd9cbe152996b5e8d266689276105c887b5268ecab7f2e68e045aea8082c0a535f3773ff614527616fc145e8228d2d467144a06077dfeda7ef2284b46dbb7861ba904f19429a15422dd79f4ab4ff912cc8ac83635e611ca79581f487b56c44a2f5f0f84d80f00918802571072e591cf8c81e1b831431117f30ac7e9ae6067f410e03d580231c86141e0ee1a6767a1085c3a1391ede006fdd47d5ea252bd1a723a92abab5a21ea0392f812235c40d7b2930405e2a8278b3e885ed41cb29834d09c7013d06596834bd465856f3e407600c29544380acfaeef9127af55fc150a08b8381a3450913dbc33d5f1591cc27cfa41ed705e8aa8bf872c0a31268fb329a3d14121898d213bca41d43d99c4c37eb0f454e4e8e889f35d12d1818c750ce16adb47eb6e1c006402992490158ba67b87b6cd6d5d787fc953fd66796fb8d1cd6e67d13403c7275d2ec56ce16a0792429f2b374b608ec3cd17a740055c0ef2162cd151d0025b23d6db53249f15409563e49595b26dc3970a8ef890280c64b56de24941208366558d1f601e921335c880af02d52e5ade6757a6019c6648a2a77ba634f802edb4cd0b6cf0f8b4bfbea2cf68b80f4b6f47e070eb87479b1996d1681298ec5445be5ff4761baa0f9a586e4ac2170d75311322c1a30301ee5275bca731052d4688f71774e5a1509f60d163c56fa403aa810f1804cc682cc3b112522917c51613d4fad32f401a02ba0b059c4b1136d07164bf935a3bc14ca8640d597dce54316616a38a41ef7fa54e0178c2111084742bef21667b6d031a5c5a962a23d3229715be995f18438f75168d7a69dac1c8f10b480841c001dbc6997003d0ae87d4424aa3a918b81c17894b16f4697559b2a0ef3ac68e61ea9a788407324235951e2ef01b0a260993c03aad0f00a433c2b40a90518a11eaea4756af408da6181c288fa82bb4c3b625b98096a62d6c15449234a609958e1955dcd40c4d9cb8d14
+OutPK = 5455f1b09dc660942d60b9e13ab27b43086b595a47099a78b526a4bff2e3ed7addf47fc796c09adf480b8a091d09111d0999d632d910c03dc1ea867aa458a99b2c9a4795393bb6a417085fcc776a6c49f32a8185e24c7662ef62bbbb184db4e73670a16279b1c0245d8aeb3c6aa93c6eb588f84bc89847e312c8b419fd8305ea392a32a297c449ccf51ba56ee566a6e91c9cb46417a927bd688bd0223232db5c5f62d85bf3bbbe2ff0021dbace3c8f3a6fd3991e70a277c2390a64b64c43907154d83e779e0358426e090fba1a3676c94652e20a40f3dae5bf08952265706a9fc942991a3cdd56265f48768096287598c820953d90728c57b0fd352be0db8e677824a7f92b6ce9bf68721b2251547f392200c5c2625448b11a8dc7a0bce8b6f0202a24b65d63a6d7479b474543d2d6c42508c8724996c335134553a6df4d88d5ac44560023a009d5561bd0a5d0d65859ffde9070bb2c72b616ea62b1647a0263d1ca4f3e7d35267e00831eb1dbc2f9a7a7793d1d6d575b77e6686b429cb771fa928fd55b0b48d4266f557b49800083f6425f9653f84763dafb03c8dea5aede1f86e69d37148da13afa4d9ffa4a435a23a93aaa1175224ff2667524ec7a8af29c518784e6f43c657fc4a023a2da2773ea7d19cae499cd5f244473aeae2865b92bfc248212e843c73b6879f769f9b5a8757e1fc4f61ba801613e8c004a61516774e159e14ba972b3cd3d77e3f6b4f093aad5906d91f6c4b9f19cb158e05a652135bc11e89735f4b6bc2fbac84ab8c849644d1678522e3109e8ee32d3a1c407e993d311b0baaaba5aeac6ed11a904092044e8028964044b01ef56663b908aa3cb2a5fdb23121aa12d80ced256d5501a57f1c99ca0a69848859b8ee4484dac685a02c2c37a7baa0a0b7029d1190e89dff2e44d2afd5461c2f05a040a0be2e0652e4e9c041e3405112fa12e869069e1081666c509c60186b512b822274d27c9c78f413fcdb48097692115a461daa70688fc093ed22d9663818e238a25a0b2413176e1687f20320c8efa9d2666a2444d88d452717e0608c98c91fab266143bdf5698b8ac22de8576c672da2993cf0bd6c2c638f19ca672603da4355226a71e8465bc51cc96ac7c34a0e91a777962249a6429a6810405828093709d9cbe465c446371188ce0c4caaaf1849210cc5ec084fe2de62773191e3d9c7290caa4952c0a5b2ad4c4b6907c616a55a8c7768d1b9b45b8872819a4e44b47a3c92f86411c14530db4d82a83c0678e22834408d342117fbb414d8979718499231f43a960281ca12974a6b08f2258a7879a3c67d0afaa6451c9167a4c79d04c909fff62d2ab71e116ea58dd41057487db414bea87b925e5ca33c88852a71a104d3600942fac9119a7512054b32d7b57e23554a026d7510996738d844792050519d5a0226812ba5a1998098213008d08d91f14a2b8088b5ccf2a5e003bb84bdaf9e25c4d1692420400c19f21d675f686290df3295ff814de1e3c09d74504696e0ea29d357e76b813d2339880f293419098851b665fab0dee933352274157f944701459b9da26c745fe73729e7757f46c03066e9ab8e1a863a8e1a430ab719c3b0e342617d80859c200b787996abc02b00232728741cb34c4478644846acfda8f393789e259abf7fd67a188c3382c0d8c0c4d427b5e2e8650d440177ea64e3720e6e8a4864c7cacdd65f25c2817c5b2832be22ba31bff60e540318449f9f55451aa04db2215846d9b794b949b09e66f59e84f70f278bce0aaae026e79132c8be008ae6db23869e58b2c9695149bdef339753759043463628c2690d6aa352c1410f0e99ae326fa9b678add542c9e2a44d1a3815aa06c5cd6f5b2c7023db2ad0b6773c4121ced854a27ed579189a014f5fa43d38cddd1b412a8ca6410a32e553d70e5d4d90a84986cd0abcaab4e73f0cdc68b6d7d710d5e9b83ff482f37a8237289255001801aea39a5641da06a21b3ea2dcf057f27c210acd300750a06c991e7633942204897101182fa9f2049286143ba79666f18905719c0e879d7d442e4c7a537c713597308b54f261963f7e8bd82725e5e8837e23253667427753d78db5f22e5891eaf9b459ed8f86516769a44c03a528d45ca13067056225b430bab658496220edbe3a70c5e2daf0736da80076ec85ea08cc259a40f412296861d37af6f38610624291e7f410abaa56edb34c20ecd2bc8c2e4315b3850bae021906498497912a70266259824976aa9eb88049c4b08f6876063dca72331c5a9ba0e2f8e21e0668db8d1c105566e39c51910268e551dbb146a9aacd8a457a91e49022e8eb318d216dcf086454d0a88a5ea27364a27d3b585757ce194255d857d9b12e648661659c4c16a9b954216bda445863828ab799d45b61184b8fad5613199eca1cb59a5c69c4843d8a8dd0ab9c149f6035dc26cd4bdb59fa3b6ee699781cf3b06977d22ae472155bb5e64c96b1241f5e67aaa2b73335032aa34da0ee50a0145e92ad0f2011e57151a3f1a01ee5b
+
+InPK = 5455f1b09dc660942d60b9e13ab27b43086b595a47099a78b526a4bff2e3ed7addf47fc796c09adf480b8a091d09111d0999d632d910c03dc1ea867aa458a99b2c9a4795393bb6a417085fcc776a6c49f32a8185e24c7662ef62bbbb184db4e73670a16279b1c0245d8aeb3c6aa93c6eb588f84bc89847e312c8b419fd8305ea392a32a297c449ccf51ba56ee566a6e91c9cb46417a927bd688bd0223232db5c5f62d85bf3bbbe2ff0021dbace3c8f3a6fd3991e70a277c2390a64b64c43907154d83e779e0358426e090fba1a3676c94652e20a40f3dae5bf08952265706a9fc942991a3cdd56265f48768096287598c820953d90728c57b0fd352be0db8e677824a7f92b6ce9bf68721b2251547f392200c5c2625448b11a8dc7a0bce8b6f0202a24b65d63a6d7479b474543d2d6c42508c8724996c335134553a6df4d88d5ac44560023a009d5561bd0a5d0d65859ffde9070bb2c72b616ea62b1647a0263d1ca4f3e7d35267e00831eb1dbc2f9a7a7793d1d6d575b77e6686b429cb771fa928fd55b0b48d4266f557b49800083f6425f9653f84763dafb03c8dea5aede1f86e69d37148da13afa4d9ffa4a435a23a93aaa1175224ff2667524ec7a8af29c518784e6f43c657fc4a023a2da2773ea7d19cae499cd5f244473aeae2865b92bfc248212e843c73b6879f769f9b5a8757e1fc4f61ba801613e8c004a61516774e159e14ba972b3cd3d77e3f6b4f093aad5906d91f6c4b9f19cb158e05a652135bc11e89735f4b6bc2fbac84ab8c849644d1678522e3109e8ee32d3a1c407e993d311b0baaaba5aeac6ed11a904092044e8028964044b01ef56663b908aa3cb2a5fdb23121aa12d80ced256d5501a57f1c99ca0a69848859b8ee4484dac685a02c2c37a7baa0a0b7029d1190e89dff2e44d2afd5461c2f05a040a0be2e0652e4e9c041e3405112fa12e869069e1081666c509c60186b512b822274d27c9c78f413fcdb48097692115a461daa70688fc093ed22d9663818e238a25a0b2413176e1687f20320c8efa9d2666a2444d88d452717e0608c98c91fab266143bdf5698b8ac22de8576c672da2993cf0bd6c2c638f19ca672603da4355226a71e8465bc51cc96ac7c34a0e91a777962249a6429a6810405828093709d9cbe465c446371188ce0c4caaaf1849210cc5ec084fe2de62773191e3d9c7290caa4952c0a5b2ad4c4b6907c616a55a8c7768d1b9b45b8872819a4e44b47a3c92f86411c14530db4d82a83c0678e22834408d342117fbb414d8979718499231f43a960281ca12974a6b08f2258a7879a3c67d0afaa6451c9167a4c79d04c909fff62d2ab71e116ea58dd41057487db414bea87b925e5ca33c88852a71a104d3600942fac9119a7512054b32d7b57e23554a026d7510996738d844792050519d5a0226812ba5a1998098213008d08d91f14a2b8088b5ccf2a5e003bb84bdaf9e25c4d1692420400c19f21d675f686290df3295ff814de1e3c09d74504696e0ea29d357e76b813d2339880f293419098851b665fab0dee933352274157f944701459b9da26c745fe73729e7757f46c03066e9ab8e1a863a8e1a430ab719c3b0e342617d80859c200b787996abc02b00232728741cb34c4478644846acfda8f393789e259abf7fd67a188c3382c0d8c0c4d427b5e2e8650d440177ea64e3720e6e8a4864c7cacdd65f25c2817c5b2832be22ba31bff60e540318449f9f55451aa04db2215846d9b794b949b09e66f59e84f70f278bce0aaae026e79132c8be008ae6db23869e58b2c9695149bdef339753759043463628c2690d6aa352c1410f0e99ae326fa9b678add542c9e2a44d1a3815aa06c5cd6f5b2c7023db2ad0b6773c4121ced854a27ed579189a014f5fa43d38cddd1b412a8ca6410a32e553d70e5d4d90a84986cd0abcaab4e73f0cdc68b6d7d710d5e9b83ff482f37a8237289255001801aea39a5641da06a21b3ea2dcf057f27c210acd300750a06c991e7633942204897101182fa9f2049286143ba79666f18905719c0e879d7d442e4c7a537c713597308b54f261963f7e8bd82725e5e8837e23253667427753d78db5f22e5891eaf9b459ed8f86516769a44c03a528d45ca13067056225b430bab658496220edbe3a70c5e2daf0736da80076ec85ea08cc259a40f412296861d37af6f38610624291e7f410abaa56edb34c20ecd2bc8c2e4315b3850bae021906498497912a70266259824976aa9eb88049c4b08f6876063dca72331c5a9ba0e2f8e21e0668db8d1c105566e39c51910268e551dbb146a9aacd8a457a91e49022e8eb318d216dcf086454d0a88a5ea27364a27d3b585757ce194255d857d9b12e648661659c4c16a9b954216bda445863828ab799d45b61184b8fad5613199eca1cb59a5c69c4843d8a8dd0ab9c149f6035dc26cd4bdb59fa3b6ee699781cf3b06977d22ae472155bb5e64c96b1241f5e67aaa2b73335032aa34da0ee50a0145e92ad0f2011e57151a3f1a01ee5b
+InA = 711d61a7cc0a64ee994d801efabd24af23056beeacddc2a453dbb25eaf9b22d6f8aa0cf11781712ea06ffeeb5adb4a20669ceb8e8a6f7867c55dc376d941a1300e68b06110738e1fdad3c68ab12bafb8d1ed723eb898ee9631304bd843dcd69c6a3d7659a872f74529ad5ab697b285361702dad750299cdd0d3f10cc680b94134898200463ee1d45e688520118cc162872fe87aa6707c57e291d490e6ea92f624f1218212ba4d08818960676831c2d21939bd680be8c0face78192423b97a37f4aad65ab00d24fa7aa8a13ef6987716ce45a2bddea183c5c37a6a64faa3c1a345f0ab811b768454c1b9335c5cd8db96e657a0cd635a20dec30ef425e18957053f28174f9514613a7685fe662c007f61a309959b8a09b22b341630c86f04870af4c57c64e6181f0047d955a2516b546fda3799e8ec3472982a57d249f29e88bb26064541da9a8867975acaf7861ecac944b2e37b8f7194a725342505e9855334d5dc6c7d8ad864856bbcf50490f23fe86e452b04e0134f6665295c26da31211890b9c5ce243713904415f8e71f42c0955e723815f7cad3726fc2a3ca861e7095f7277ceacd9a88f93c71eb70a9bfc600d7d959ad6171be74c29ca4d980676120c59879bb1de4c4369223e15c6f43d8b1e4e94344636f8496cea5f8d696f1414e3c5a20d239c75d0d21289615c2ad12c9654c623b24ae0008a342d8994c0ecaeb211c5079fc81d7ec6b0407d6ab042961d0962b21e23e09f11a39459095e58b8fc30b93618797954e1b87a0c7f42b5e28591c7cdd2a58e6f039a4ad3b054a328dfc0daf276b586dcb4c426c4406aa528f5f4fc497483312b7d3825b30cdfc6756852404c148bd751be30d2143a2ff2383d4fc3419c417c2093766355e938fd43263bfaedbeec42bab1d9f6ad8e90aa58d03c033720aa30d679085b4029a2cc048ae8545b791a253efea4464ad8d6b44b561395679c418e6a6c67cc7147218ebcb4dadd1d5f8d0dabbd79538d81b4d22151550dc8bf729cf63338ea5c4a950e2b50e2cec5a25187ad10a12729ad62806a92035eb49cf04e8fe35f1c40811a9987e0d06145a1eaab26d14a7e0e15bb7d4533e42dd2d430de6faccf2a25e3c132579e1a5103ae457a420b25392687a0d813e1caba3b1e11635198cd672eae29a1cd9d97478e2c6189b50b49ed4e68809d0d15035cfaf6943a378d107044f6674f9d811acad9757be85df6e52c082ada6d2688f2a6e12e4760f24abb3ba8f1d9d9456c94c20b3711dd01349fe70b16711f7209f1921e5d81ba25b3ea9af2bb51ed71215dd41a096bccc14ac4476e8e7702f9fd5d19e40bfb2e5164435534f1d48263afa708469b340d0aae57b1020988fae64c662e017ec68a4f7aa5d1b1ec82edf365b62d130e8ff28f6d511f97b166d1bc607b127f4a612e9bc5445f6055e9192529e528be112757a0abf2bf72544199806944e04b53d8e45a08fd96c9939b9874e9803e56bb16608a47cae265fa023d799646e0775c5c0518825000b872b7d65653424b050905e02ee6a732717f5a12b1117923376d9b8a728c3a24828123903426c0c27f9bbba84c94e18259bf2e0010244df8edf6a938ed1787796c32f4d26878e1cd7b520197c8838144f82c5c3a2e5837a89dcd95f6d29dab9d72ea63d41c9e072b67c61a1f182c2368c4a22fd46699e4a5d6a804eb6e974c8642f5ce9aea803522e66f81b21bc0323ae9410673a43683cdf61befa5b19496758ac456155103a38924f613215271c18892ad96dceb7a32b10a8e1e86d9588c7a5ed9690154f4629909e1d45b545f74a14480de196fe58b332a13acb353cad15bb85d87fb458d6b4f225524d3ad87d0985a049572a0f16ca1f81b5f550a4127cf9c9e9b5e39552042e624ebdc96f35f48647a5c5231889db3ba0ab8835aafd76719892990b2b75931568b9213b96d6da5c01455d5407534ca64f7d0a55a47c44f85e221489e42932d80e5d261d39159176dda667b2d2f8173798ae841e7d92b6c3f450ba9172ed635dace2592ccbc477cd72c2661513701262d84d9bc6611da3c26085d6978000f322d80374f6cef19100625972fd08610cc1810d147b6b7700872a4898718a2919d82d3e9f9d8064069d41301f060321e9b19f7851cb36b0f298e9d5cb4104feb8aca16f096390ada458cf0026fe6c74299e35f97b682d82311eda63b640991e651a940c5be02e74b2f74fe4953d61d09278be62956dff441b45434035ab0c9eb05543d8c6a2a480c0fa419b9e999844f5a5f73d4627104de298e80787542730d57d7ed35236be32271f1d034562b8484bfa101926cbb5098fa18f09a1ad54b0d1556598d9178f602b4deda672ea147e8c4e8a5029003f11a1df1cb6e6f17a24010630c908096a3712ba2b94717448374389aeb08c783adfd9491aaea0746481a6a24757712ed94992aa6e6b715974356d061c1449b1bd11cc64eed6b5c24f86b26a872a49936db6b9487c0cef621fe16a248921386c9dc49bb08c1c15d2061
+InNoiseSP = ee8182d96f319477ec31a90e7e466e1fe90abbc0abd2e68e952c659794cfdf901eb0a0c481c3f11a46118f4b9a288f1827fadab55868d020e0818994bab98bfc0db557bdfe3fd4a1295a831258e76af1a85c019da0eb2fc25a5e2c9ba98448e865723e41f7f8a802aeb9a66b40ec249a225848777e05b27e8db160d43d43e847c339342db6fd648020f7a4421fed95b1b84868c6acbc953922173c41b0608cfd7b650d2f13c4b91aaf6600910d2a7d87ed8cb8a54c140c6aad638ff58d79046bca4f38b51801f6f6eafc94420dbc35bf019bebdfeda27d580d439505ba08ea976bc0f68112781399635e14d73622d469af175e7e2eef887575b112744683c3c9f37e78974cb7674104277d9e8fb9af78138c01e96af2105de9001f06e2295aa7a24847384ebad216ff597d787624240df403613d7922a7c68dbe6894cf60b669f8a18a0e84846e05303f68c8a9595c7a1c2e6b82fa14b00a2da0b369660286c1a7a86554a39905b01965665acf1f1a7200297b7382e3eb227dad0de70b30b32c9b495450d83b2072daa1d61b699d1d0166246b6efeb266cbd6729b3540fe14d3b272f1152d29fb405b4c2f2f96adb3e90e51ade8656ac8551054d10f05d51155b796d8dabfa4a35ec06dc325c92ed94a7bf28ed0974d54e8c4d9658f7ea4b7150d14716602e28755ce81a9a197379e25a5fccf49969754ad632f803592055c829ace64fef68ef324100bf61c714d82a9246e09bca1431833a3f0a3ecd4f2609488b172128127c12d6e9818e27a45f5918411c339e92c1dd829555afa4a1bc9d80292b7920400d75128ba54461bc3e5687455501fda0db5e990a6cd8e03a1b8ec54238197c22a017986d5a17722c605c42e493b4260676a9af43a6c5964c71ddd975bd8b49b1de569cc6c89b667ad5334ca7bfd1c0b5ae8c85ecbca5c59e9d84b949b31f2a1594eea92436715dca746435c554b386e2a6265a198b50ffc5c6c460f093ea12fa13718fa445dc0e4161ea6ae71673282905d302aa22d9587d10411d577117e947cca55b344f21141a92acd69296ab9b0583968f959365ca7b9f318c2180489e060e8bda8709bfb10ba75924e803d3466d23e7ee20efa1b964da2823a37fc8660900dc287488d1e918b8df40d0e4c3f059a91c00071ddc81b4836ba143fc22159802a655ddb52c7dc6e6f25aec2e48ea69bc7aacc94e7d00af08d09a0556c0a73d06ef464422c47ac23e0060a07b59ca109c54a8bdc094bc380de51908eb0b4314e1d9b8d3e87e8a621a1e7454445b6a23bd0d391d2fe3677aef161cb40129ca9422a379a379b693ae2b49175a71d758b79ca19ebdc8ee0b926a325e8bef852c96811ab1516fc294459de763b950aa4ba1f11b69789b529db2047ab541364c32dca3dbe29a1244cf56b6e8ebd19373acbe80d8cab9ea7889e3cea625df9d05e5f54e7d098dce2ba89ac7ea8fed87ccfd18d0165d53545405a51525ea325c19f4781f885d5a11ad7868876365e8f403451740a06896b558d593a5c46fb7e29b89c8beef2b0baab2595f611809e97535c90766239a287dc031012a44730a0664a195e225b53e9ab1f4882754dc5293e64328acde9901d7e96d3c32254e28d1c7dcda48564762eee27cf66a1c6813fe6237300e24b719d1d928bf979a4a5b0eb570960396c3c925701496c2e9896d3ccb2ce603c36d052bf3819cf19ac825975ea27a15cd48f2b117a2a37705f081ce6f069c577c4457d2054346acfd66650fa1c4f0547fc9ab1d0742769d44aaf6427cd8c689aa14497bc0b2c3a91fdb07560bd31feaa9a2e09bcdbd529afc7e2ab289a28290c07a273f45c7a10e3559a530876a6cfc1374a7183bf172574cb891e278b2541f2a111abcaa3f09e7cbb24ddc9ca99c555d600aee2592e45c148b2eaf1b5ae562988130f090e301f3f09714834d94cfb57defa53bde222c8cfdc6d7de54e67283a9c9387033147ec77844e9f538fd973639b632280411144ea53930d914e649b6048f22860f3d38f466e38301dedb309e64c5b2cc4e8c35d2e8e932290b9b33d4ced0bf87b8d2a558296c92664c0028c2ddaf499800f9c894283630e9694ad26381e5c92b5c860a279c403e602c929f7323aa4689f5244a8545f53187ab5a239b30167932c2e36c72d12ba671864b9c83d68c04a18ba622fa4654abda3e0f1d11f586e6080d6524bd9783f4a3b78a9992eb6972d95cfb14182448ce89aeda8a399a77abaf8bf56d49a6b294e158d19e8f3716211fa19cb0a2f2655f8ce24e4a101a35c68d5aaaa34bc2fcd4ec3354e2fbcc5a9b8d75d559bdabf02807a59c62fa3e960de7e460baaa4bfcd7a0ca088979bb124fbe5beaa28e42230943526a8fe48e5ad8d5132766415ca2f562a6654c3e1c2f3290c83276db375302267ac09fbf9a3f17ffc010c3367018c7b1b72c6fc6a02bf2d04db3e9a0cac601cca96f44104dfccb7024e44f09c0cd4b2e52666ee4e23f74618ac0b84f24f015f38cdfefbefd6567396ee7593f56f
+InNoiseEP = 5a9a43219eac7517ad1b9abd5ca888e84c953f48773e0cec94d4322f4cea9ddb830c1c3de76ea5564a5b3b2ec5476414ac2f4ca4b2b0de57cda2ffa9aaa58feadbeb403f057810881f56b5e60eaca35551eca91f36554610c8cc8cf26b75e939a84803d8ae1584890cd80aa728caad06a12c6f29560c8adda597e43a5d00a2c261fb8a9a37fb816c04331176c48d4670d7085adb9fc3077ed49172a81006448c3bf229724bee26b657eb11957008a653d9156ad76597e4138c866e310d285718a6e3a9bdc6af88b260cc24e9a7dd452fb81f099a464946caa2a4ca2e9b27dc48a2980db3ae7098f55d95d8eb0e19d380f6544119ae0f1430f82dea7490ac46b77cfdae116c4096d0de15c1a3c0fb861011821e80709fcca262a8e4f038c9555f4c17a278881f1e867c9761ea909c9e5aa3769a7e5748b0bb46bd782d212062744243239f1847ad5d9f449b9b80a934b5b702c758ed9a5efe5202caf6192e47aa49686eb612f01944715352b6e7c759802992b3248f7ec4a0d973829131c16a65ac97cca9b731757587a38776ce987d2f5f61f024993e3ae2bd95c7be68a723e590040c14e84ba7518ed54855dab19948f4945fe5771923ea97d0492902b139737a5181b9173a17742e27e626ae6475989bc68aa048339a80a3300879b72a0af0f4ca5f688cc6a6902a790a228356a9f576bcd07de18b583276e4977aa80d60a1acb0e88974a3775f31b76ffc4bcdae32e73f892f7ea1d9c6f21a073dda31a5def64d1e516a4af52c09095d21756dae530c53df12ae9d10916ca672a322893b69389464c0452186bd88897029818d0250df314d2e2efbd803353f431fea4b092854ff6fc5d9444129c49d0313c49e9be0516e414c8420fb2a1c28548d4a0293fce5452d6ff1da977a34a92711ce10480e0581f80fb0609458958f15bf7486447672905552dfce91976a0f261e94bc1eafad76fe7d6547105d0ac5d89d670464367ba27defa406c6f32c0e21166c605ab8ab0f5bf211b78190e9dffb8508f2aeaba52980eec98c3863b8b4fd81b67529132675992c272eb615794156e80a091772442f884d4630aa6e344359fd5694c910faabf198027e1ef5481ecba91245c1ed936a5416ab706796547878703c4126d5267596354fbdc518f95e7396b795de3c7996150a295d82056712e4288f99743c8b740703cd57ca668ad2bd5c50349e438522bd5ba84821a320410b27062fb5f196432955db86a6a88b306d0b71149c9b7d8204ab7cb6bc4299fe5598c490a79d53abd8ce6d71e0948b5dc41f8654f983350c739b1e3cc697a11e5306ca097b75a980d0f37b9044a6c3209570d09ca4cf8a3de989d11bad8abfd9a5254093d4d8482bae4e7125f2a6d27c49ef68aea073a505d86609040cac20029971d33e5c96e76e812114ce83234b56a89f5d8bbbd6a1e4e49a0cd08ee4fb354a6e568bff89d3b234d7e01543de4e60660dbd5b88d9073943e9f3f16aa5da91ad30819d59b94326da3909aaf0e7667394444ffdef93193daa21ed03847771ce981c40438a2ee8b472e494a9307d53254dc7c534dab0bb401a0ba434268022d8a7155e654c14e5709632bc9c2fd507027258edaefe73fd482be81d77b4955d22728819a35d26745edd9672c8a5615c510495abf2bacf93b358c0aa1e13cb6048be4082b95b3cb96015442fcc338677b204f6cacc907f5e8194994dd83b16a592defc349190532fa616ca1f763ddd6a575858f8885351c72aa2857ad30447c0f6564064187387820d3209e7d38329503ff89f54793300489dec9092007940ff8372222b3e1819c7996a13458f69068855b9f63dec8f9501ab0c799b6190e42edd417740d5a40684bb74946a64c3fe0c1e2f9674f6260e200d7b4913647ebedc75c20d023be90ec8d1eea1a9946143c249e572b5eb6119fa9a2ace5c46f281f9760f8f1769e8104c2441b4da0a5971ff22dd6343591977eb524235e4959804c00a39a43bb31a30024ac801a707c1f8e8983cd5e677b62d9e9ff4e0eaca214a5babda03690229ae91209964242d1acfea5416bc19743dd30c9111a660e3ac4627c4718cfa94c737af2468c52f8e47d9055399c52369b2c550ff62af79b75cb8dba1f538b61d72c5dee5a5ccb44a2f8b70190795942c64602482ec6cf8d74f75cadc921f4050c3e7e52b80cfbc6a29d5024e1de18be732b7c3a1d1eabac8603a8019e378f9a3b5128f8890047363d80be37b9464a213dd61202e7160037f57bb991ef214eb163d796957980177bda87897478e3a4d3094ef2e9a587c991fa4055540ef51a66983aeb2857215af46ea6b3a6d580099434bab327fb680d9097e3072a1637233d0559546e09853f8a6b448e814e7ca6a51482bb2958744692e55b43b8bcd9a5ca487589aaa848e955924169c13d0e95e9348c20c982e0d697a9a5b114708463ebd3b48c5dc7502c1bd3c69bfc97da18c60e1c7b4a4a29528a95bf4b258800208cca3c530a3c05eceb838d61cd56c40e4b41c08
+InNoiseEPP = 0080ff1b00fcbf0180000000f8bfffaf00b0ff0a0000300090ff0600ff2f012000f4bf00c0fffbff02000000ffdbff0200ffefffebff0a00ffafff1b00040001c0ff2b00000000400000001400f8effe0b0004000300ff1b00f8bf06c000d0ff0600000000100000c0010000ecfff2bffdef00e0ff02c0fd2f001000f8bf0180ff9b00fcbf0700003000fcbf054000000004000400001c0000c0048000000000000640003000000007400040001000007000f0ff0600ff6fffcbff1200008000200000c00300000c00f3bf07c000100000c0fdef0030000400010000ccff06000030000c00070002c0fffbfffabf0140ff0b000400020000fcffeebfff2f000c00fcbf0300002c00f4bffd6f00b0ff0a00074000c0ff0a0002c0fe0b00f7bf0240001000fcbf00c00020000400030000e0ff0200ff2f00400000c000000100000000020000dcff0e000500000000fcbffc6fff1b000000ff2f0000000c00034000e0ff0e000300ff2b0000000100003c0000000580fe2b0010000380005000f8bf02800000000c00feef00e0ff0e0002c0ff2b000800fd2f0120000400fcefffdbff1200ff2f01e0ff0a000000003c00f8bf0280ffdbff02c0024000f0fffabf0080ff1b000c000100003000fcbf014000d0ff0200003000f0ff0a0000f0ffebff06000240fffbff0200ff2f001000f4bffe2f00ecff06000080ff2b00fcbffbef00e0ffeabf0030000000030000300000000700fe6f0000000300070000f0fffebf040000d0fffebf0000000c000400ff2f00acfff6bf00400100000300feafff0b000400fe6fff3b0014000280000000f4bf0180ff1b000c000300001c00f4bffe6f00d0ff0200fe2f00f0ff02c00240002000040000f000e0fffabffbefff3b0000c0018000000000c00540fffbff0a000400ff2b00080008800010000c00048000100004000340000000f0bf0480002000f4bfffeffe0b000000fcef000000fcbf0000000000080001c0ffdbff060003400010001c00007000e0ff02c00280ff0b000000060000dcfffebf0080fffbff0a00ff2f004000140000300010000400010000bcff0200fe6f003000fcbf0200ff1b00f8bf00b00040000400ff2f000c00180000f00020000800014000000004000180ff0b00fcbffe2f0120001800f76f004000fcbf0100011000100002000100000700fe2f00f0fff2bf018000f0ff0200ffef001000ecbffe2f000000040001c00010001000038000f0ff0e00014000300004000080ff0b0000c00070ff0b0003000180ff0b0004000030003c00e8bf0280ff3b0000c00100010000f3bf00c000200000c00070000000fbbfff2f00bcff0a00004000d0ff06000030000c00f8bf030000300004000030003000080002c0001000000003c0ff0b000000ff6f011000f0bfffafff0b000400004000c0ff0200014001400008000100003c000400fb2f00f0fffebf0100001c0008000500000000f7bf00c0ffcbff0e000400000c00000005c0ff5b0008000100000c00f4bf020000ecfffabf01c0000000fcbffaaf00d0ff02c001000000000700fe2ffe2b00f8bf04c00020000800fdaf0050001400ff6f0000000f0004800000001000000000d0ff02c0fdaf00f0ff0200007000d0fffebf064001e0ff0a0001c0fffbfffebffd2f002c001400fe2f001c0000000600ffebff060004c0ff3b001400fd6f0020000800fe6fff0b000700fb2fff0b00fcbffd2f00f0ff0e0004000110000c0000f000f0ff0200034000100000000140ff3b00fcbf00300100000f00054000d0ff0e000100ff3b00fcbf038000e0fffabf00c0002000fcbffb6f012000fcbf0200000c0003000340ff0b000b00003000ecff0200ff2fff3b0000000080002000f8bffdef00d0fff6bf010000ecff02c00100001c00fcbf01800090000800000000ecfffebffc2f003c00080001c001f0fffebffdaf0000000300feefff0b00f8bf0070001000f4bfff2f00ccfffabfff6f003000000001000110000c00ff2f003c00040001c0ff7b001000034000200000c0ff2f00e0ff1600fc2f00300000c000b0003000180000400150000800fcaf0050000800010000b0ff0e00feef00900000c0fc2f00f0ff02000000002c00080000700000000800007000c0ff06000400000c000b000080fffbff0e000100001c001400fe6f00000007000030000c000f0005c000200000000100005c000800ffaf0030000400ff2f001000f4bf003001500000c000b0ff4b00f4bf0080ff1b00f4bf0300000c00030000b0ffcbfffabf0080ffebff02c003c0fffbff1a00008000000003c0fdef00200000c00040ffbbffeebffdaf010000f4bfff2f002c000000feaf000000fcbffcaf001000040004c0ff0b000b0000800000001300ff2f01100004000100000000ffbf028000d0ff0200feeffedbff0a00fbafffebff020003c0ffebff02c001800060000800fe2f0100000400014001500000c0ff2f01e0ff0200ffef005000f0bf
+InRand = 869e8bb1806d746f8978d27fead08f551a3825d1ce8cb7e0f07476ae742b8f82
+OutPK = 39d9341741d840b49a1ea42aaa9722c7dee138dd713741b43288ba177ce3c8e5aa59bedf4b449964e0a285205af18e087405025e068f8c0a0393eccaf4cc03081fc982bd9d5e6ca138020b9eb351d787104e9c58bf89f4f2bdbd4c65649308cc3d77eec7b1535d2635596a81b0da909fa26ac5254a6d09bd0d4edb5a797589194d94b3d65022a76e04766e934e91704b98e8b758d0b6f962915d302a7405f9ee58540cbac0b97940f1a3979080b876962a5b113779a60164a42bdfa64f36522516425e285d2fd55af31e0cf29e6e73ae5c991d922811d2d60bf89467458e18b7409e2dd354962123de0804b92a7951ca8ef8c1bdabc4ab0cf118f174af0721200d6241399d4ab35de597e56ba39b0b01215ba6a180467800e02dbe09b2e05760c714085c266ca540f6d872750103cf72918ea6baef8320f8199a2f975484576fd615895d66e4b37697a04e71b79fe92f745013872421ad346d8e5aa5e0548d451d7a0d92a3086f4d52849c84cd8a50ca7199411d91310b17a24523dd274541ea37fc48ab3771b110d76bc10a6fe22060459295a4699c11a0b832c29c3d844e8ab5f3226f04e826005bd0bbac50e7339c51a54a989d204ca1671e15d9531022729f541404840d7ebe90f9e1283e6561d3ed2bb4882a94e5112624e205d0d5eab574e003f24665d3e5b12e2debc982896a00bb6501e79dc887f3ae8352a7262f3fd33543c5f1a1126cbea35beeb09503c927a1de5e131ef644ec508872e143f7f51e47ddeb61105ebda015ef5573e0490c0d887cb676b0816c13c3061ad6a48d6fb3526dc03977a25ba445cd47442b9330f2e92f59efe62560cd6eaf408783a6b2b5744c507b575665bc8a0b80c6d42bbc237b8585a133b5eba767fac0783463c341c6267d082a986410e8a85387f5c48aa415dfd65921ed993ca46bd779219a678f423333d98a4d2f083260ef080b1a87281a6d5c984a59c1d85bb08a5b80af4243b00169c1f59265469f57d603b215f29f2f6dff032e551e0ddf73a6424db8ec1d4d84f48c332895a87be5c18a30629d6045900478db6942878680895223a2bca8195da9fc97e6e08e1a029b5654656a279709890294045beca301eb527625ad22968938235dad6df25de662ee6d687af6f559b809c63bcde4a4a20bedc5bce97264d69c14c462751c9fa4fa4c26054fe0f09a430431c4d63cc787100ac142741849219f0a8a0231fe2070ab87fc95b9596f354acc252ce0b4a00a53fb3e1191f50cabe214bd1ae618e2e83a32308d64ee02475e8b8d8530001804525017f8a9d1c197c903ed14eaf5b76c6418c8395972831be313056ca4759c11e4f9902febad2d2806c6300a6e7664512d68d9543c1090091f2edcd9c65f010313c3e18af7d15745ce168663d094dd6d45750c7094cd5cb6b57289af8c69fe1685840da00e5af305a477ddc150f3799cacb1c34297dc9d64ee255265dc254377220cd410089da86707d48c70b06785a7f113be123887b78af2fa7d9c8c6b292f0a4a0bd7c5a7982c6b3bd638b285300ecce36023dc2c329916b3596db2bbdcec5c8ae5ea1be382bc1520950f9260edc81c58be801574a33769520b2b09d329015e8618f95984c519931c2289ee4e949b29c9460d963c15d2dc488cc864a516f40ba5fab00e154e82054e4dccc3cfc73224589d6fade0f41e63021c9a5b85be53b325a7a311edbc559f565781d0909186dcf6be5869635ef36b110d5e7685ddc33372843fe425ebf5f990d2635280fb01a8bc007057af0c6f995e5d30e316a7ccc4d59243d8760cc930733e7a3972a467f15adaa37e476fd3497a50c905e261fbfa863edce31bf7f95eb5009ac796791e0ed0df86af317cbd6891d939647bfc2c815606ba465658e768fd1e1e5101ef1315481a5ce238885a98b7c2ad689785108fe59f2935328212aa83cac332c93fcb11a1621efa0b0c6d59418e1e460e1af0e3f7198fac9f7c4157c05806906e9a5cea7554255d22af04a631dd85643411b7a5a3ded243b1b3b1a334887a2241f001bf6403a5bdc569858649696a12618444aef605f5df1c13d2da470c513442e4f6b877ca0d163e2981d18c731263a40697d381709a8a25e445ea4b266a84efab42653fc09e246d8ce1acc40fcc0a6ababd28af2a141be523bc713dd7c4c333e9b55f0005c533556b5b07fef3fbce365423ffc3e398638ba10dc30a08ba9301e3cbffd929945e45fae3b41d69e1dde5a59c879f91a9946029b9761f2b641c5c393a95f814cfd806c009a6dbb0e6882c103497fef03e5a1aa152f7c816fd8aaec60b845177e421c510706d40d13a256035294cc0ab0be31e11d5af22235b9187d25964f77ff18ab6e91a3b8bb8731be50d610859020266b065392037db58b77947fe8048656ed0f49665a654a9d1dd681cc94f54d3999951add67369aab6afa00b4e76cfcd5a262b420bd19d189a87c0b8d7c154b5212ed36dcd01b70f540b7b08286ccd4e7a1802ae77115ae829fc7fc0469ce0671c2c
+OutRec = 01c000300000000140003000080000000020000c000080000000040001000000000800014000300008000200001000000003c0001000040000c0001000000002c00030000c0003400000000000018000200004000080002000080001c0000000080000c000100000000180000000080001c00020000c000200002000080000c00020000c000340001000080002c0000000040000000000000400014000300000000280000000080000800020000000024000300000000180000000040003c000000004000340001000000002000020000c0001000010000c0000000010000c0000400030000c00014000200000000280002000000002c00020000c0002c000000000000040003000080003c0003000080000c0001000040001c000000004000100002000080003800000000400034000300008000340000000000000000030000800014000000004000380003000000001c0001000000003c000200000000140003000040002c0003000000000000000000c000100003000040003000030000c0002400000000c0000c00000000c0001c0002000080000c000000008000000000000040001800030000000024000200004000140000000040001800030000800024000300000000180000000080003c0002000000000400020000000030000100004000040002000040001c000000008000200001000040000000010000000028000100004000180003000040003c00030000c000080002000000003c00030000c00034000000004000100001000080000c0002000080001000010000c0000c00020000000018000200008000140002000000001c0003000000000c00010000c000000001000040000c0001000040002800010000c00018000100000000140002000080000400020000c0001400020000c0001000000000400020000300000000200001000040000400020000c0001c000200008000140000000000002400000000c000000001000040000c00030000c0002c00010000c000340002000000001800020000000030000200004000080002000080002400030000c000300002000040000c00030000c00028000000000000040003000080001000020000c0002800000000c000240003000080000400030000c000100001000040001400000000800038000300004000180000000000002400020000800014000000004000180001000080002400000000c00038000100004000040001000040003000030000400024000200000000000001000040001800020000c000080001000080003400000000c0000c0000000080002c00010000c0002800020000400014000100004000000000000080000000010000c0002c00030000c00010000100000000000000000040000800020000c0002000000000c0003c00030000c0000400000000c000200001000000001000020000000000000200000000140002000040003c0001000080002c000300000000280000000080001400030000c0001c000100004000380000000000001000010000c0001000000000800038000300008000380003000000003400000000c00020000100008000340000000040000000010000c0002c00030000000024000100004000300000000080000800000000c0003800010000c00014000300004000180002000000000c00020000c000280003000080000c0001000040001c000100000000200003000040001c0003000040003000020000c000000001000080003c0001000040002800000000c00000000000000000200003000080002c00000000c00030000000008000280001000080002c00020000400028000100004000200001000080000c0002000040000c000300004000200001000080003c000200000000000003000000001400030000c000100001000000003000000000c0001800030000000018000100000000000000000080001c0000000080002400010000c00018000200000000000003000040003c0003000000003800000000c000240002000040001000030000c000240002000040003c000200008000000003000040003c0002000000001c0000000000002c0003000040003c0003000040001c00030000000038000200008000340002000080003000000000800030000000008000280000000040000800010000c00008000100000000080003000040001400010000c0000800030000c000300002000040002c0001000000000c0002000040000800020000c000180002000000002c000100008000340003000040002400010000800014000300000000340000000000000400000000c000080002000040002c00000000c000100003000080002c0003000000002800000000000000000100008000300001000040003400000000800004000000000000000001000040002c0003000040000000020000800020000300008000180000000040003c000300004000100001000040002800010000c000140000000080000400020000800
+Key = 76f2c93a81a15cc9e46a714d5ede343d56b2e08761c7c8df10b13e08db01ec06
+
+InNoiseS = 4ca10ae48258b14d83e48384f858eae4c130e49055a044c78590f0a74f1a19e8edd427300659bb38647c032c5722a6ac4b05413b4a0dc870ac1b16f25099428b9beb83af39887340a1c4bd986241429eb8eec081442a418b10ac60be94b3e34374a63c5582274aba579a03202666b16f3066985a26b96dd8993e242ccd6a3d9a2d287fdc82da9091830d0886b80bf3419ae968c615521160e85676c96af65dd92ea10e2c520bca4b882326b7b2c131d22d922827c5b41f2f33b281b50e8b64d92ac48a9bc4516a39272018ef5b707223b59bc2e07dd6831015b610b04638aa9d949cb7444c7d3162cf3a088b628f73c93d66375540330ac2d871d4b0405421caa142a0a2effcaacfe5173862deb228da286993d7605db54efd98f122b1949be7a15481fbd23d97d588b7bce9bf4da31481296149138c1b5753caaa9428b6d5f3be48c69979d351525c61532bf5535aa7d72850c294021d1614fda36c781f2ddbf10a4f723e578a596092ec312827ae456cac024c5a44bb68e5175025ce6876aeb1951d022426faab5a0db9d0cf369324a153533fb50b5a5866c77c00524265020b769517d7970918f5d2bc5a6e874332186d5f9e7a3a03aa28a39de5078002c0845c9eb74791088a81b185958e014f95d1219d702d2ec39a772fa82a3c91fc873a991d54c3c0babb64a7bdd15e78232d3b71a1c08bd60e68fc2f5e46348c8b948c1f93860eab88d24b736c785f2a4564a6754492c9c988c786166708d2b240d3da4c3280bd5616c0aff7a81a9a560809766df9b27e014c6c8aa45b38a6416046ba4b560804a90b54c3f5b6a2abaa7149968c8567c0ed07f2ee99218ed52b88bd98624c1c91b9ae1b082b6d07c8697eccc6a953cec576a25cdf548866a1cb03ded4fb26a1afa6c9287050459de64af1aac1572b1509643c6407f5d4a944904856c42f770717adbc701ff3c9f44aae6bea40c50bdd9f1f9368b667286732023d89581e7f872639f19766b65305b07babe9003e631b6a32511e690a864a18d45263c9436a0f1245db4405b31e1d9a6598922ae6f09a61975b3ac27225baa60e1bf6f01b8a0c07988dc9167648e9b1891c3e01a5031260cd52d08cce39498835b9122ef5d4f24f34c7623448294c4da985b5904583bd6f7e301bb911abaf1c778ee1567e8f4df0e05479cf1b5854e0cc7083a4463a96f2aa4d28944147464d249057b13c3eb8e0e93466a70194309f3339ef597459e9ffb5b15a1cf080c34713b819f6051d2baa142b9602460ac3451161913bd960202f68092c456b6ab71c638877f008862904b3fa62b815414e745b2309629d4691e894282c37e70ab15a82a7b055157b481552c6ee3ef7510a9d9420216b7f2275ef64dab95cc86b3e8ffbcaf508bafa0251c4755d287041290b4f6675f22d3ff9c31808c29d8281f2aaa7c7dede72a42592c10b20a35cee60b31b9d67f5ea6adaa33fb3dd911816aa142975551ebd40569bb1fd904a504b7ac811234029921b6b06b28a1df7c2a2ed59a4ad3541f8852e815b08c09444809decfd2904a62d991cc3c6659d6d4c6906d482bc03cce05cbb9ae142264aeda128148084c5b93b831458b061dd99e94e60a1ef51199f550156047901792628c6d5ff316c20be6d5ea59030d6abb624f8909e12a02dcf69f039ad45ffda6113f2f6aa9be6bb934122ae2de84b7a0add8488c052aaf50d0e098d58c7be3c80fe946c566c00b4739fd59aa2de006885b0cb9c65231f5fa760af69a929443aa3252aa16497dcb2c1180f42cca1310b99278a956a07cf540561dc0bb9e8b6b2ea25e57ae52d636b6297a2afbcb6d014942a33ce4869829de6f1ba761b60b6b93f993938884076c1e4976848f8bb6c4486daddaae7fb8073749a70f0eec61ff2c9687184c09bd15f849108700efe8a01b72c9c97d40957b4e3d64533411887541a5de6518ab756994bb5ed9f7af8da0bbe6959c57e4a2f346884a6716a847015c5545d69770d56d44500097f83ee4b736df867029d979848b64a2c281b2ac3d140ed854f12fd946b770754139e0e320223dac9823a14c28cbae29dc4af992ced62ab7255f265c533cb54b75f48a8321e7aa8f7939c468d26645c57b4abf0569260229a40611920af1add758474b8d026f41785559ad04faa501a649e44abee8607fc4eb21376552ba48931156485c7916d4d63247a757d4f92cf34322202b94acdc3276d99a2a899d3471475bb268ef9ea9976a949437e30e168301d027518aeec04ffc4294a00a2649b271b334f3cbdf88678b8b8c583f62c0815937667aede6ae53aec271e5d885a84b58d348449aa06649d6a635bd7d392885a0ae60218d8a085a509f5e5ad12e24c4d36b04600c0011623d4a4bd2206fce8d5003234405db3ad7e3d4dd6aa790abc6b1e49e8b26436ae6c9f1010b1e052158639c1582d641d8b3ed0a9c289aa5eae66e66a43048876b14cf4a69489224564c4932adaaf83e2b15e0b2248425d71198849f534d801b24cccb2aa434829
+InPK = 39d9341741d840b49a1ea42aaa9722c7dee138dd713741b43288ba177ce3c8e5aa59bedf4b449964e0a285205af18e087405025e068f8c0a0393eccaf4cc03081fc982bd9d5e6ca138020b9eb351d787104e9c58bf89f4f2bdbd4c65649308cc3d77eec7b1535d2635596a81b0da909fa26ac5254a6d09bd0d4edb5a797589194d94b3d65022a76e04766e934e91704b98e8b758d0b6f962915d302a7405f9ee58540cbac0b97940f1a3979080b876962a5b113779a60164a42bdfa64f36522516425e285d2fd55af31e0cf29e6e73ae5c991d922811d2d60bf89467458e18b7409e2dd354962123de0804b92a7951ca8ef8c1bdabc4ab0cf118f174af0721200d6241399d4ab35de597e56ba39b0b01215ba6a180467800e02dbe09b2e05760c714085c266ca540f6d872750103cf72918ea6baef8320f8199a2f975484576fd615895d66e4b37697a04e71b79fe92f745013872421ad346d8e5aa5e0548d451d7a0d92a3086f4d52849c84cd8a50ca7199411d91310b17a24523dd274541ea37fc48ab3771b110d76bc10a6fe22060459295a4699c11a0b832c29c3d844e8ab5f3226f04e826005bd0bbac50e7339c51a54a989d204ca1671e15d9531022729f541404840d7ebe90f9e1283e6561d3ed2bb4882a94e5112624e205d0d5eab574e003f24665d3e5b12e2debc982896a00bb6501e79dc887f3ae8352a7262f3fd33543c5f1a1126cbea35beeb09503c927a1de5e131ef644ec508872e143f7f51e47ddeb61105ebda015ef5573e0490c0d887cb676b0816c13c3061ad6a48d6fb3526dc03977a25ba445cd47442b9330f2e92f59efe62560cd6eaf408783a6b2b5744c507b575665bc8a0b80c6d42bbc237b8585a133b5eba767fac0783463c341c6267d082a986410e8a85387f5c48aa415dfd65921ed993ca46bd779219a678f423333d98a4d2f083260ef080b1a87281a6d5c984a59c1d85bb08a5b80af4243b00169c1f59265469f57d603b215f29f2f6dff032e551e0ddf73a6424db8ec1d4d84f48c332895a87be5c18a30629d6045900478db6942878680895223a2bca8195da9fc97e6e08e1a029b5654656a279709890294045beca301eb527625ad22968938235dad6df25de662ee6d687af6f559b809c63bcde4a4a20bedc5bce97264d69c14c462751c9fa4fa4c26054fe0f09a430431c4d63cc787100ac142741849219f0a8a0231fe2070ab87fc95b9596f354acc252ce0b4a00a53fb3e1191f50cabe214bd1ae618e2e83a32308d64ee02475e8b8d8530001804525017f8a9d1c197c903ed14eaf5b76c6418c8395972831be313056ca4759c11e4f9902febad2d2806c6300a6e7664512d68d9543c1090091f2edcd9c65f010313c3e18af7d15745ce168663d094dd6d45750c7094cd5cb6b57289af8c69fe1685840da00e5af305a477ddc150f3799cacb1c34297dc9d64ee255265dc254377220cd410089da86707d48c70b06785a7f113be123887b78af2fa7d9c8c6b292f0a4a0bd7c5a7982c6b3bd638b285300ecce36023dc2c329916b3596db2bbdcec5c8ae5ea1be382bc1520950f9260edc81c58be801574a33769520b2b09d329015e8618f95984c519931c2289ee4e949b29c9460d963c15d2dc488cc864a516f40ba5fab00e154e82054e4dccc3cfc73224589d6fade0f41e63021c9a5b85be53b325a7a311edbc559f565781d0909186dcf6be5869635ef36b110d5e7685ddc33372843fe425ebf5f990d2635280fb01a8bc007057af0c6f995e5d30e316a7ccc4d59243d8760cc930733e7a3972a467f15adaa37e476fd3497a50c905e261fbfa863edce31bf7f95eb5009ac796791e0ed0df86af317cbd6891d939647bfc2c815606ba465658e768fd1e1e5101ef1315481a5ce238885a98b7c2ad689785108fe59f2935328212aa83cac332c93fcb11a1621efa0b0c6d59418e1e460e1af0e3f7198fac9f7c4157c05806906e9a5cea7554255d22af04a631dd85643411b7a5a3ded243b1b3b1a334887a2241f001bf6403a5bdc569858649696a12618444aef605f5df1c13d2da470c513442e4f6b877ca0d163e2981d18c731263a40697d381709a8a25e445ea4b266a84efab42653fc09e246d8ce1acc40fcc0a6ababd28af2a141be523bc713dd7c4c333e9b55f0005c533556b5b07fef3fbce365423ffc3e398638ba10dc30a08ba9301e3cbffd929945e45fae3b41d69e1dde5a59c879f91a9946029b9761f2b641c5c393a95f814cfd806c009a6dbb0e6882c103497fef03e5a1aa152f7c816fd8aaec60b845177e421c510706d40d13a256035294cc0ab0be31e11d5af22235b9187d25964f77ff18ab6e91a3b8bb8731be50d610859020266b065392037db58b77947fe8048656ed0f49665a654a9d1dd681cc94f54d3999951add67369aab6afa00b4e76cfcd5a262b420bd19d189a87c0b8d7c154b5212ed36dcd01b70f540b7b08286ccd4e7a1802ae77115ae829fc7fc0469ce0671c2c
+InRec = 01c000300000000140003000080000000020000c000080000000040001000000000800014000300008000200001000000003c0001000040000c0001000000002c00030000c0003400000000000018000200004000080002000080001c0000000080000c000100000000180000000080001c00020000c000200002000080000c00020000c000340001000080002c0000000040000000000000400014000300000000280000000080000800020000000024000300000000180000000040003c000000004000340001000000002000020000c0001000010000c0000000010000c0000400030000c00014000200000000280002000000002c00020000c0002c000000000000040003000080003c0003000080000c0001000040001c000000004000100002000080003800000000400034000300008000340000000000000000030000800014000000004000380003000000001c0001000000003c000200000000140003000040002c0003000000000000000000c000100003000040003000030000c0002400000000c0000c00000000c0001c0002000080000c000000008000000000000040001800030000000024000200004000140000000040001800030000800024000300000000180000000080003c0002000000000400020000000030000100004000040002000040001c000000008000200001000040000000010000000028000100004000180003000040003c00030000c000080002000000003c00030000c00034000000004000100001000080000c0002000080001000010000c0000c00020000000018000200008000140002000000001c0003000000000c00010000c000000001000040000c0001000040002800010000c00018000100000000140002000080000400020000c0001400020000c0001000000000400020000300000000200001000040000400020000c0001c000200008000140000000000002400000000c000000001000040000c00030000c0002c00010000c000340002000000001800020000000030000200004000080002000080002400030000c000300002000040000c00030000c00028000000000000040003000080001000020000c0002800000000c000240003000080000400030000c000100001000040001400000000800038000300004000180000000000002400020000800014000000004000180001000080002400000000c00038000100004000040001000040003000030000400024000200000000000001000040001800020000c000080001000080003400000000c0000c0000000080002c00010000c0002800020000400014000100004000000000000080000000010000c0002c00030000c00010000100000000000000000040000800020000c0002000000000c0003c00030000c0000400000000c000200001000000001000020000000000000200000000140002000040003c0001000080002c000300000000280000000080001400030000c0001c000100004000380000000000001000010000c0001000000000800038000300008000380003000000003400000000c00020000100008000340000000040000000010000c0002c00030000000024000100004000300000000080000800000000c0003800010000c00014000300004000180002000000000c00020000c000280003000080000c0001000040001c000100000000200003000040001c0003000040003000020000c000000001000080003c0001000040002800000000c00000000000000000200003000080002c00000000c00030000000008000280001000080002c00020000400028000100004000200001000080000c0002000040000c000300004000200001000080003c000200000000000003000000001400030000c000100001000000003000000000c0001800030000000018000100000000000000000080001c0000000080002400010000c00018000200000000000003000040003c0003000000003800000000c000240002000040001000030000c000240002000040003c000200008000000003000040003c0002000000001c0000000000002c0003000040003c0003000040001c00030000000038000200008000340002000080003000000000800030000000008000280000000040000800010000c00008000100000000080003000040001400010000c0000800030000c000300002000040002c0001000000000c0002000040000800020000c000180002000000002c000100008000340003000040002400010000800014000300000000340000000000000400000000c000080002000040002c00000000c000100003000080002c0003000000002800000000000000000100008000300001000040003400000000800004000000000000000001000040002c0003000040000000020000800020000300008000180000000040003c000300004000100001000040002800010000c000140000000080000400020000800
+Key = 76f2c93a81a15cc9e46a714d5ede343d56b2e08761c7c8df10b13e08db01ec06
+
diff --git a/crypto/newhope/newhope_vectors_test.cc b/crypto/newhope/newhope_vectors_test.cc
new file mode 100644
index 00000000..fe84cd4b
--- /dev/null
+++ b/crypto/newhope/newhope_vectors_test.cc
@@ -0,0 +1,122 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/crypto.h>
+#include <openssl/rand.h>
+
+#include "../test/file_test.h"
+#include "../test/scoped_types.h"
+#include "internal.h"
+
+
+static bool TestNewhope(FileTest *t, void *arg) {
+ ScopedNEWHOPE_POLY a(NEWHOPE_POLY_new());
+ ScopedNEWHOPE_POLY s(NEWHOPE_POLY_new()), sp(NEWHOPE_POLY_new());
+ ScopedNEWHOPE_POLY e(NEWHOPE_POLY_new()), ep(NEWHOPE_POLY_new()),
+ epp(NEWHOPE_POLY_new());
+ ScopedNEWHOPE_POLY in_pk(NEWHOPE_POLY_new());
+ ScopedNEWHOPE_POLY in_rec(NEWHOPE_POLY_new());
+
+ if (t->GetType() == "InRandA") {
+ std::vector<uint8_t> a_bytes, s_bytes, e_bytes, expected_pk;
+ if (!t->GetBytes(&a_bytes, "InRandA") ||
+ !t->GetBytes(&s_bytes, "InNoiseS") ||
+ !t->GetBytes(&e_bytes, "InNoiseE") ||
+ !t->GetBytes(&expected_pk, "OutPK")) {
+ return false;
+ }
+ NEWHOPE_POLY_frombytes(a.get(), a_bytes.data());
+ NEWHOPE_POLY_frombytes(s.get(), s_bytes.data());
+ NEWHOPE_POLY_frombytes(e.get(), e_bytes.data());
+
+ NEWHOPE_POLY pk;
+ NEWHOPE_offer_computation(&pk, s.get(), e.get(), a.get());
+
+ uint8_t pk_bytes[NEWHOPE_POLY_LENGTH];
+ NEWHOPE_POLY_tobytes(pk_bytes, &pk);
+ return t->ExpectBytesEqual(expected_pk.data(), expected_pk.size(),
+ pk_bytes, NEWHOPE_POLY_LENGTH);
+ } else if (t->GetType() == "InPK") {
+ std::vector<uint8_t> rand, in_pk_bytes, a_bytes, sp_bytes, ep_bytes,
+ epp_bytes, expected_pk, expected_rec, expected_key;
+ if (!t->GetBytes(&in_pk_bytes, "InPK") ||
+ !t->GetBytes(&rand, "InRand") ||
+ !t->GetBytes(&a_bytes, "InA") ||
+ !t->GetBytes(&sp_bytes, "InNoiseSP") ||
+ !t->GetBytes(&ep_bytes, "InNoiseEP") ||
+ !t->GetBytes(&epp_bytes, "InNoiseEPP") ||
+ !t->GetBytes(&expected_pk, "OutPK") ||
+ !t->GetBytes(&expected_rec, "OutRec") ||
+ !t->GetBytes(&expected_key, "Key")) {
+ return false;
+ }
+ NEWHOPE_POLY_frombytes(in_pk.get(), in_pk_bytes.data());
+ NEWHOPE_POLY_frombytes(a.get(), a_bytes.data());
+ NEWHOPE_POLY_frombytes(sp.get(), sp_bytes.data());
+ NEWHOPE_POLY_frombytes(ep.get(), ep_bytes.data());
+ NEWHOPE_POLY_frombytes(epp.get(), epp_bytes.data());
+
+ uint8_t key[NEWHOPE_KEY_LENGTH];
+ NEWHOPE_POLY pk, rec;
+ NEWHOPE_accept_computation(key, &pk, &rec,
+ sp.get(), ep.get(), epp.get(),
+ rand.data(), in_pk.get(), a.get());
+
+ uint8_t pk_bytes[NEWHOPE_POLY_LENGTH], rec_bytes[NEWHOPE_POLY_LENGTH];
+ NEWHOPE_POLY_tobytes(pk_bytes, &pk);
+ NEWHOPE_POLY_tobytes(rec_bytes, &rec);
+ return
+ t->ExpectBytesEqual(expected_key.data(), expected_key.size(),
+ key, NEWHOPE_KEY_LENGTH) &&
+ t->ExpectBytesEqual(expected_pk.data(), expected_pk.size(),
+ pk_bytes, NEWHOPE_POLY_LENGTH) &&
+ t->ExpectBytesEqual(expected_rec.data(), expected_rec.size(),
+ rec_bytes, NEWHOPE_POLY_LENGTH);
+ } else if (t->GetType() == "InNoiseS") {
+ std::vector<uint8_t> s_bytes, in_pk_bytes, in_rec_bytes, expected_key;
+ if (!t->GetBytes(&s_bytes, "InNoiseS") ||
+ !t->GetBytes(&in_pk_bytes, "InPK") ||
+ !t->GetBytes(&in_rec_bytes, "InRec") ||
+ !t->GetBytes(&expected_key, "Key")) {
+ return false;
+ }
+ NEWHOPE_POLY_frombytes(s.get(), s_bytes.data());
+ NEWHOPE_POLY_frombytes(in_pk.get(), in_pk_bytes.data());
+ NEWHOPE_POLY_frombytes(in_rec.get(), in_rec_bytes.data());
+
+ uint8_t key[NEWHOPE_KEY_LENGTH];
+ NEWHOPE_finish_computation(key, s.get(), in_pk.get(), in_rec.get());
+
+ return t->ExpectBytesEqual(expected_key.data(), expected_key.size(), key,
+ NEWHOPE_KEY_LENGTH);
+ } else {
+ t->PrintLine("Unknown test '%s'", t->GetType().c_str());
+ return false;
+ }
+}
+
+int main(int argc, char **argv) {
+ CRYPTO_library_init();
+
+ if (argc != 2) {
+ fprintf(stderr, "%s <test file>\n", argv[0]);
+ return 1;
+ }
+
+ return FileTestMain(TestNewhope, nullptr, argv[1]);
+}
diff --git a/crypto/newhope/ntt.c b/crypto/newhope/ntt.c
new file mode 100644
index 00000000..163a9d1a
--- /dev/null
+++ b/crypto/newhope/ntt.c
@@ -0,0 +1,148 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include "internal.h"
+
+
+static uint16_t bitrev_table[1024] = {
+ 0, 512, 256, 768, 128, 640, 384, 896, 64, 576, 320, 832, 192, 704,
+ 448, 960, 32, 544, 288, 800, 160, 672, 416, 928, 96, 608, 352, 864,
+ 224, 736, 480, 992, 16, 528, 272, 784, 144, 656, 400, 912, 80, 592,
+ 336, 848, 208, 720, 464, 976, 48, 560, 304, 816, 176, 688, 432, 944,
+ 112, 624, 368, 880, 240, 752, 496, 1008, 8, 520, 264, 776, 136, 648,
+ 392, 904, 72, 584, 328, 840, 200, 712, 456, 968, 40, 552, 296, 808,
+ 168, 680, 424, 936, 104, 616, 360, 872, 232, 744, 488, 1000, 24, 536,
+ 280, 792, 152, 664, 408, 920, 88, 600, 344, 856, 216, 728, 472, 984,
+ 56, 568, 312, 824, 184, 696, 440, 952, 120, 632, 376, 888, 248, 760,
+ 504, 1016, 4, 516, 260, 772, 132, 644, 388, 900, 68, 580, 324, 836,
+ 196, 708, 452, 964, 36, 548, 292, 804, 164, 676, 420, 932, 100, 612,
+ 356, 868, 228, 740, 484, 996, 20, 532, 276, 788, 148, 660, 404, 916,
+ 84, 596, 340, 852, 212, 724, 468, 980, 52, 564, 308, 820, 180, 692,
+ 436, 948, 116, 628, 372, 884, 244, 756, 500, 1012, 12, 524, 268, 780,
+ 140, 652, 396, 908, 76, 588, 332, 844, 204, 716, 460, 972, 44, 556,
+ 300, 812, 172, 684, 428, 940, 108, 620, 364, 876, 236, 748, 492, 1004,
+ 28, 540, 284, 796, 156, 668, 412, 924, 92, 604, 348, 860, 220, 732,
+ 476, 988, 60, 572, 316, 828, 188, 700, 444, 956, 124, 636, 380, 892,
+ 252, 764, 508, 1020, 2, 514, 258, 770, 130, 642, 386, 898, 66, 578,
+ 322, 834, 194, 706, 450, 962, 34, 546, 290, 802, 162, 674, 418, 930,
+ 98, 610, 354, 866, 226, 738, 482, 994, 18, 530, 274, 786, 146, 658,
+ 402, 914, 82, 594, 338, 850, 210, 722, 466, 978, 50, 562, 306, 818,
+ 178, 690, 434, 946, 114, 626, 370, 882, 242, 754, 498, 1010, 10, 522,
+ 266, 778, 138, 650, 394, 906, 74, 586, 330, 842, 202, 714, 458, 970,
+ 42, 554, 298, 810, 170, 682, 426, 938, 106, 618, 362, 874, 234, 746,
+ 490, 1002, 26, 538, 282, 794, 154, 666, 410, 922, 90, 602, 346, 858,
+ 218, 730, 474, 986, 58, 570, 314, 826, 186, 698, 442, 954, 122, 634,
+ 378, 890, 250, 762, 506, 1018, 6, 518, 262, 774, 134, 646, 390, 902,
+ 70, 582, 326, 838, 198, 710, 454, 966, 38, 550, 294, 806, 166, 678,
+ 422, 934, 102, 614, 358, 870, 230, 742, 486, 998, 22, 534, 278, 790,
+ 150, 662, 406, 918, 86, 598, 342, 854, 214, 726, 470, 982, 54, 566,
+ 310, 822, 182, 694, 438, 950, 118, 630, 374, 886, 246, 758, 502, 1014,
+ 14, 526, 270, 782, 142, 654, 398, 910, 78, 590, 334, 846, 206, 718,
+ 462, 974, 46, 558, 302, 814, 174, 686, 430, 942, 110, 622, 366, 878,
+ 238, 750, 494, 1006, 30, 542, 286, 798, 158, 670, 414, 926, 94, 606,
+ 350, 862, 222, 734, 478, 990, 62, 574, 318, 830, 190, 702, 446, 958,
+ 126, 638, 382, 894, 254, 766, 510, 1022, 1, 513, 257, 769, 129, 641,
+ 385, 897, 65, 577, 321, 833, 193, 705, 449, 961, 33, 545, 289, 801,
+ 161, 673, 417, 929, 97, 609, 353, 865, 225, 737, 481, 993, 17, 529,
+ 273, 785, 145, 657, 401, 913, 81, 593, 337, 849, 209, 721, 465, 977,
+ 49, 561, 305, 817, 177, 689, 433, 945, 113, 625, 369, 881, 241, 753,
+ 497, 1009, 9, 521, 265, 777, 137, 649, 393, 905, 73, 585, 329, 841,
+ 201, 713, 457, 969, 41, 553, 297, 809, 169, 681, 425, 937, 105, 617,
+ 361, 873, 233, 745, 489, 1001, 25, 537, 281, 793, 153, 665, 409, 921,
+ 89, 601, 345, 857, 217, 729, 473, 985, 57, 569, 313, 825, 185, 697,
+ 441, 953, 121, 633, 377, 889, 249, 761, 505, 1017, 5, 517, 261, 773,
+ 133, 645, 389, 901, 69, 581, 325, 837, 197, 709, 453, 965, 37, 549,
+ 293, 805, 165, 677, 421, 933, 101, 613, 357, 869, 229, 741, 485, 997,
+ 21, 533, 277, 789, 149, 661, 405, 917, 85, 597, 341, 853, 213, 725,
+ 469, 981, 53, 565, 309, 821, 181, 693, 437, 949, 117, 629, 373, 885,
+ 245, 757, 501, 1013, 13, 525, 269, 781, 141, 653, 397, 909, 77, 589,
+ 333, 845, 205, 717, 461, 973, 45, 557, 301, 813, 173, 685, 429, 941,
+ 109, 621, 365, 877, 237, 749, 493, 1005, 29, 541, 285, 797, 157, 669,
+ 413, 925, 93, 605, 349, 861, 221, 733, 477, 989, 61, 573, 317, 829,
+ 189, 701, 445, 957, 125, 637, 381, 893, 253, 765, 509, 1021, 3, 515,
+ 259, 771, 131, 643, 387, 899, 67, 579, 323, 835, 195, 707, 451, 963,
+ 35, 547, 291, 803, 163, 675, 419, 931, 99, 611, 355, 867, 227, 739,
+ 483, 995, 19, 531, 275, 787, 147, 659, 403, 915, 83, 595, 339, 851,
+ 211, 723, 467, 979, 51, 563, 307, 819, 179, 691, 435, 947, 115, 627,
+ 371, 883, 243, 755, 499, 1011, 11, 523, 267, 779, 139, 651, 395, 907,
+ 75, 587, 331, 843, 203, 715, 459, 971, 43, 555, 299, 811, 171, 683,
+ 427, 939, 107, 619, 363, 875, 235, 747, 491, 1003, 27, 539, 283, 795,
+ 155, 667, 411, 923, 91, 603, 347, 859, 219, 731, 475, 987, 59, 571,
+ 315, 827, 187, 699, 443, 955, 123, 635, 379, 891, 251, 763, 507, 1019,
+ 7, 519, 263, 775, 135, 647, 391, 903, 71, 583, 327, 839, 199, 711,
+ 455, 967, 39, 551, 295, 807, 167, 679, 423, 935, 103, 615, 359, 871,
+ 231, 743, 487, 999, 23, 535, 279, 791, 151, 663, 407, 919, 87, 599,
+ 343, 855, 215, 727, 471, 983, 55, 567, 311, 823, 183, 695, 439, 951,
+ 119, 631, 375, 887, 247, 759, 503, 1015, 15, 527, 271, 783, 143, 655,
+ 399, 911, 79, 591, 335, 847, 207, 719, 463, 975, 47, 559, 303, 815,
+ 175, 687, 431, 943, 111, 623, 367, 879, 239, 751, 495, 1007, 31, 543,
+ 287, 799, 159, 671, 415, 927, 95, 607, 351, 863, 223, 735, 479, 991,
+ 63, 575, 319, 831, 191, 703, 447, 959, 127, 639, 383, 895, 255, 767,
+ 511, 1023};
+
+void newhope_bitrev_vector(uint16_t* poly) {
+ unsigned int i, r;
+ uint16_t tmp;
+
+ for (i = 0; i < PARAM_N; i++) {
+ r = bitrev_table[i];
+ if (i < r) {
+ tmp = poly[i];
+ poly[i] = poly[r];
+ poly[r] = tmp;
+ }
+ }
+}
+
+void newhope_mul_coefficients(uint16_t* poly, const uint16_t* factors) {
+ unsigned int i;
+
+ for (i = 0; i < PARAM_N; i++) {
+ poly[i] = newhope_montgomery_reduce((poly[i] * factors[i]));
+ }
+}
+
+/* GS_bo_to_no; omegas need to be in Montgomery domain */
+void newhope_ntt(uint16_t* a, const uint16_t* omega) {
+ int i, start, j, jTwiddle, distance;
+ uint16_t temp, W;
+
+ for (i = 0; i < 10; i += 2) {
+ /* Even level */
+ distance = (1 << i);
+ for (start = 0; start < distance; start++) {
+ jTwiddle = 0;
+ for (j = start; j < PARAM_N - 1; j += 2 * distance) {
+ W = omega[jTwiddle++];
+ temp = a[j];
+ a[j] = (temp + a[j + distance]); /* Omit reduction (be lazy) */
+ a[j + distance] = newhope_montgomery_reduce(
+ (W * ((uint32_t)temp + 3 * PARAM_Q - a[j + distance])));
+ }
+ }
+
+ /* Odd level */
+ distance <<= 1;
+ for (start = 0; start < distance; start++) {
+ jTwiddle = 0;
+ for (j = start; j < PARAM_N - 1; j += 2 * distance) {
+ W = omega[jTwiddle++];
+ temp = a[j];
+ a[j] = newhope_barrett_reduce((temp + a[j + distance]));
+ a[j + distance] = newhope_montgomery_reduce(
+ (W * ((uint32_t)temp + 3 * PARAM_Q - a[j + distance])));
+ }
+ }
+ }
+}
diff --git a/crypto/newhope/poly.c b/crypto/newhope/poly.c
new file mode 100644
index 00000000..44cd3839
--- /dev/null
+++ b/crypto/newhope/poly.c
@@ -0,0 +1,189 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/aes.h>
+#include <openssl/rand.h>
+
+#include "internal.h"
+
+
+extern uint16_t newhope_omegas_montgomery[];
+extern uint16_t newhope_omegas_inv_montgomery[];
+
+extern uint16_t newhope_psis_bitrev_montgomery[];
+extern uint16_t newhope_psis_inv_montgomery[];
+
+void NEWHOPE_POLY_frombytes(NEWHOPE_POLY* r, const uint8_t* a) {
+ int i;
+ for (i = 0; i < PARAM_N / 4; i++) {
+ r->coeffs[4 * i + 0] =
+ a[7 * i + 0] | (((uint16_t)a[7 * i + 1] & 0x3f) << 8);
+ r->coeffs[4 * i + 1] = (a[7 * i + 1] >> 6) |
+ (((uint16_t)a[7 * i + 2]) << 2) |
+ (((uint16_t)a[7 * i + 3] & 0x0f) << 10);
+ r->coeffs[4 * i + 2] = (a[7 * i + 3] >> 4) |
+ (((uint16_t)a[7 * i + 4]) << 4) |
+ (((uint16_t)a[7 * i + 5] & 0x03) << 12);
+ r->coeffs[4 * i + 3] =
+ (a[7 * i + 5] >> 2) | (((uint16_t)a[7 * i + 6]) << 6);
+ }
+}
+
+void NEWHOPE_POLY_tobytes(uint8_t* r, const NEWHOPE_POLY* p) {
+ int i;
+ uint16_t t0, t1, t2, t3, m;
+ int16_t c;
+ for (i = 0; i < PARAM_N / 4; i++) {
+ t0 = newhope_barrett_reduce(
+ p->coeffs[4 * i + 0]); /* Make sure that coefficients
+ have only 14 bits */
+ t1 = newhope_barrett_reduce(p->coeffs[4 * i + 1]);
+ t2 = newhope_barrett_reduce(p->coeffs[4 * i + 2]);
+ t3 = newhope_barrett_reduce(p->coeffs[4 * i + 3]);
+
+ m = t0 - PARAM_Q;
+ c = m;
+ c >>= 15;
+ t0 = m ^ ((t0 ^ m) & c); /* Make sure that coefficients are in [0,q] */
+
+ m = t1 - PARAM_Q;
+ c = m;
+ c >>= 15;
+ t1 = m ^ ((t1 ^ m) & c); /* <Make sure that coefficients are in [0,q] */
+
+ m = t2 - PARAM_Q;
+ c = m;
+ c >>= 15;
+ t2 = m ^ ((t2 ^ m) & c); /* <Make sure that coefficients are in [0,q] */
+
+ m = t3 - PARAM_Q;
+ c = m;
+ c >>= 15;
+ t3 = m ^ ((t3 ^ m) & c); /* Make sure that coefficients are in [0,q] */
+
+ r[7 * i + 0] = t0 & 0xff;
+ r[7 * i + 1] = (t0 >> 8) | (t1 << 6);
+ r[7 * i + 2] = (t1 >> 2);
+ r[7 * i + 3] = (t1 >> 10) | (t2 << 4);
+ r[7 * i + 4] = (t2 >> 4);
+ r[7 * i + 5] = (t2 >> 12) | (t3 << 2);
+ r[7 * i + 6] = (t3 >> 6);
+ }
+}
+
+void newhope_poly_uniform(NEWHOPE_POLY* a, const uint8_t* seed) {
+/* The reference implementation uses SHAKE-128 here; this implementation uses
+ * AES-CTR. Use half the seed for the initialization vector and half for the
+ * key. */
+#if SEED_LENGTH != 2 * AES_BLOCK_SIZE
+#error "2 * seed length != AES_BLOCK_SIZE"
+#endif
+ uint8_t ivec[AES_BLOCK_SIZE];
+ memcpy(ivec, &seed[SEED_LENGTH / 2], SEED_LENGTH / 2);
+ AES_KEY key;
+ AES_set_encrypt_key(seed, 8 * SEED_LENGTH / 2, &key);
+
+ /* AES state. */
+ uint8_t ecount[AES_BLOCK_SIZE];
+ memset(ecount, 0, AES_BLOCK_SIZE);
+
+ /* Encrypt a block of zeros just to get the random bytes. With luck, 2688
+ * bytes is enough. */
+ uint8_t buf[AES_BLOCK_SIZE * 168];
+ memset(buf, 0, sizeof(buf));
+
+ unsigned int block_num = 0;
+ AES_ctr128_encrypt(buf, buf, sizeof(buf), &key, ivec, ecount, &block_num);
+
+ size_t pos = 0, coeff_num = 0;
+ while (coeff_num < PARAM_N) {
+ /* Specialized for q = 12889 */
+ uint16_t val = (buf[pos] | ((uint16_t)buf[pos + 1] << 8)) & 0x3fff;
+ if (val < PARAM_Q) {
+ a->coeffs[coeff_num++] = val;
+ }
+
+ pos += 2;
+ if (pos > sizeof(buf) - 2) {
+ memset(buf, 0, sizeof(buf));
+ AES_ctr128_encrypt(buf, buf, sizeof(buf), &key, ivec, ecount, &block_num);
+ pos = 0;
+ }
+ }
+}
+
+void NEWHOPE_POLY_noise(NEWHOPE_POLY* r) {
+#if PARAM_K != 16
+#error "poly_getnoise in poly.c only supports k=16"
+#endif
+
+ uint32_t tp[PARAM_N];
+
+ /* The reference implementation calls ChaCha20 here. */
+ RAND_bytes((uint8_t *) tp, sizeof(tp));
+
+ size_t i;
+ for (i = 0; i < PARAM_N; i++) {
+ const uint32_t t = tp[i];
+
+ size_t j;
+ uint32_t d = 0;
+ for (j = 0; j < 8; j++) {
+ d += (t >> j) & 0x01010101;
+ }
+
+ const uint32_t a = ((d >> 8) & 0xff) + (d & 0xff);
+ const uint32_t b = (d >> 24) + ((d >> 16) & 0xff);
+ r->coeffs[i] = a + PARAM_Q - b;
+ }
+}
+
+void newhope_poly_pointwise(NEWHOPE_POLY* r, const NEWHOPE_POLY* a,
+ const NEWHOPE_POLY* b) {
+ size_t i;
+ for (i = 0; i < PARAM_N; i++) {
+ uint16_t t = newhope_montgomery_reduce(3186 * b->coeffs[i]);
+ /* t is now in Montgomery domain */
+ r->coeffs[i] = newhope_montgomery_reduce(a->coeffs[i] * t);
+ /* r->coeffs[i] is back in normal domain */
+ }
+}
+
+void newhope_poly_add(NEWHOPE_POLY* r, const NEWHOPE_POLY* a,
+ const NEWHOPE_POLY* b) {
+ size_t i;
+ for (i = 0; i < PARAM_N; i++) {
+ r->coeffs[i] = newhope_barrett_reduce(a->coeffs[i] + b->coeffs[i]);
+ }
+}
+
+void NEWHOPE_POLY_noise_ntt(NEWHOPE_POLY* r) {
+ NEWHOPE_POLY_noise(r);
+ /* Forward NTT transformation. Because we're operating on a noise polynomial,
+ * we can regard the bits as already reversed and skip the bit-reversal
+ * step:
+ *
+ * newhope_bitrev_vector(r->coeffs); */
+ newhope_mul_coefficients(r->coeffs, newhope_psis_bitrev_montgomery);
+ newhope_ntt((uint16_t *) r->coeffs, newhope_omegas_montgomery);
+}
+
+void newhope_poly_invntt(NEWHOPE_POLY* r) {
+ newhope_bitrev_vector(r->coeffs);
+ newhope_ntt((uint16_t *) r->coeffs, newhope_omegas_inv_montgomery);
+ newhope_mul_coefficients(r->coeffs, newhope_psis_inv_montgomery);
+}
diff --git a/crypto/newhope/precomp.c b/crypto/newhope/precomp.c
new file mode 100644
index 00000000..d0c478ee
--- /dev/null
+++ b/crypto/newhope/precomp.c
@@ -0,0 +1,306 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include "internal.h"
+
+
+uint16_t newhope_omegas_montgomery[PARAM_N / 2] = {
+ 4075, 6974, 7373, 7965, 3262, 5079, 522, 2169, 6364, 1018, 1041,
+ 8775, 2344, 11011, 5574, 1973, 4536, 1050, 6844, 3860, 3818, 6118,
+ 2683, 1190, 4789, 7822, 7540, 6752, 5456, 4449, 3789, 12142, 11973,
+ 382, 3988, 468, 6843, 5339, 6196, 3710, 11316, 1254, 5435, 10930,
+ 3998, 10256, 10367, 3879, 11889, 1728, 6137, 4948, 5862, 6136, 3643,
+ 6874, 8724, 654, 10302, 1702, 7083, 6760, 56, 3199, 9987, 605,
+ 11785, 8076, 5594, 9260, 6403, 4782, 6212, 4624, 9026, 8689, 4080,
+ 11868, 6221, 3602, 975, 8077, 8851, 9445, 5681, 3477, 1105, 142,
+ 241, 12231, 1003, 3532, 5009, 1956, 6008, 11404, 7377, 2049, 10968,
+ 12097, 7591, 5057, 3445, 4780, 2920, 7048, 3127, 8120, 11279, 6821,
+ 11502, 8807, 12138, 2127, 2839, 3957, 431, 1579, 6383, 9784, 5874,
+ 677, 3336, 6234, 2766, 1323, 9115, 12237, 2031, 6956, 6413, 2281,
+ 3969, 3991, 12133, 9522, 4737, 10996, 4774, 5429, 11871, 3772, 453,
+ 5908, 2882, 1805, 2051, 1954, 11713, 3963, 2447, 6142, 8174, 3030,
+ 1843, 2361, 12071, 2908, 3529, 3434, 3202, 7796, 2057, 5369, 11939,
+ 1512, 6906, 10474, 11026, 49, 10806, 5915, 1489, 9789, 5942, 10706,
+ 10431, 7535, 426, 8974, 3757, 10314, 9364, 347, 5868, 9551, 9634,
+ 6554, 10596, 9280, 11566, 174, 2948, 2503, 6507, 10723, 11606, 2459,
+ 64, 3656, 8455, 5257, 5919, 7856, 1747, 9166, 5486, 9235, 6065,
+ 835, 3570, 4240, 11580, 4046, 10970, 9139, 1058, 8210, 11848, 922,
+ 7967, 1958, 10211, 1112, 3728, 4049, 11130, 5990, 1404, 325, 948,
+ 11143, 6190, 295, 11637, 5766, 8212, 8273, 2919, 8527, 6119, 6992,
+ 8333, 1360, 2555, 6167, 1200, 7105, 7991, 3329, 9597, 12121, 5106,
+ 5961, 10695, 10327, 3051, 9923, 4896, 9326, 81, 3091, 1000, 7969,
+ 4611, 726, 1853, 12149, 4255, 11112, 2768, 10654, 1062, 2294, 3553,
+ 4805, 2747, 4846, 8577, 9154, 1170, 2319, 790, 11334, 9275, 9088,
+ 1326, 5086, 9094, 6429, 11077, 10643, 3504, 3542, 8668, 9744, 1479,
+ 1, 8246, 7143, 11567, 10984, 4134, 5736, 4978, 10938, 5777, 8961,
+ 4591, 5728, 6461, 5023, 9650, 7468, 949, 9664, 2975, 11726, 2744,
+ 9283, 10092, 5067, 12171, 2476, 3748, 11336, 6522, 827, 9452, 5374,
+ 12159, 7935, 3296, 3949, 9893, 4452, 10908, 2525, 3584, 8112, 8011,
+ 10616, 4989, 6958, 11809, 9447, 12280, 1022, 11950, 9821, 11745, 5791,
+ 5092, 2089, 9005, 2881, 3289, 2013, 9048, 729, 7901, 1260, 5755,
+ 4632, 11955, 2426, 10593, 1428, 4890, 5911, 3932, 9558, 8830, 3637,
+ 5542, 145, 5179, 8595, 3707, 10530, 355, 3382, 4231, 9741, 1207,
+ 9041, 7012, 1168, 10146, 11224, 4645, 11885, 10911, 10377, 435, 7952,
+ 4096, 493, 9908, 6845, 6039, 2422, 2187, 9723, 8643, 9852, 9302,
+ 6022, 7278, 1002, 4284, 5088, 1607, 7313, 875, 8509, 9430, 1045,
+ 2481, 5012, 7428, 354, 6591, 9377, 11847, 2401, 1067, 7188, 11516,
+ 390, 8511, 8456, 7270, 545, 8585, 9611, 12047, 1537, 4143, 4714,
+ 4885, 1017, 5084, 1632, 3066, 27, 1440, 8526, 9273, 12046, 11618,
+ 9289, 3400, 9890, 3136, 7098, 8758, 11813, 7384, 3985, 11869, 6730,
+ 10745, 10111, 2249, 4048, 2884, 11136, 2126, 1630, 9103, 5407, 2686,
+ 9042, 2969, 8311, 9424, 9919, 8779, 5332, 10626, 1777, 4654, 10863,
+ 7351, 3636, 9585, 5291, 8374, 2166, 4919, 12176, 9140, 12129, 7852,
+ 12286, 4895, 10805, 2780, 5195, 2305, 7247, 9644, 4053, 10600, 3364,
+ 3271, 4057, 4414, 9442, 7917, 2174};
+
+uint16_t newhope_omegas_inv_montgomery[PARAM_N / 2] = {
+ 4075, 5315, 4324, 4916, 10120, 11767, 7210, 9027, 10316, 6715, 1278,
+ 9945, 3514, 11248, 11271, 5925, 147, 8500, 7840, 6833, 5537, 4749,
+ 4467, 7500, 11099, 9606, 6171, 8471, 8429, 5445, 11239, 7753, 9090,
+ 12233, 5529, 5206, 10587, 1987, 11635, 3565, 5415, 8646, 6153, 6427,
+ 7341, 6152, 10561, 400, 8410, 1922, 2033, 8291, 1359, 6854, 11035,
+ 973, 8579, 6093, 6950, 5446, 11821, 8301, 11907, 316, 52, 3174,
+ 10966, 9523, 6055, 8953, 11612, 6415, 2505, 5906, 10710, 11858, 8332,
+ 9450, 10162, 151, 3482, 787, 5468, 1010, 4169, 9162, 5241, 9369,
+ 7509, 8844, 7232, 4698, 192, 1321, 10240, 4912, 885, 6281, 10333,
+ 7280, 8757, 11286, 58, 12048, 12147, 11184, 8812, 6608, 2844, 3438,
+ 4212, 11314, 8687, 6068, 421, 8209, 3600, 3263, 7665, 6077, 7507,
+ 5886, 3029, 6695, 4213, 504, 11684, 2302, 1962, 1594, 6328, 7183,
+ 168, 2692, 8960, 4298, 5184, 11089, 6122, 9734, 10929, 3956, 5297,
+ 6170, 3762, 9370, 4016, 4077, 6523, 652, 11994, 6099, 1146, 11341,
+ 11964, 10885, 6299, 1159, 8240, 8561, 11177, 2078, 10331, 4322, 11367,
+ 441, 4079, 11231, 3150, 1319, 8243, 709, 8049, 8719, 11454, 6224,
+ 3054, 6803, 3123, 10542, 4433, 6370, 7032, 3834, 8633, 12225, 9830,
+ 683, 1566, 5782, 9786, 9341, 12115, 723, 3009, 1693, 5735, 2655,
+ 2738, 6421, 11942, 2925, 1975, 8532, 3315, 11863, 4754, 1858, 1583,
+ 6347, 2500, 10800, 6374, 1483, 12240, 1263, 1815, 5383, 10777, 350,
+ 6920, 10232, 4493, 9087, 8855, 8760, 9381, 218, 9928, 10446, 9259,
+ 4115, 6147, 9842, 8326, 576, 10335, 10238, 10484, 9407, 6381, 11836,
+ 8517, 418, 6860, 7515, 1293, 7552, 2767, 156, 8298, 8320, 10008,
+ 5876, 5333, 10258, 10115, 4372, 2847, 7875, 8232, 9018, 8925, 1689,
+ 8236, 2645, 5042, 9984, 7094, 9509, 1484, 7394, 3, 4437, 160,
+ 3149, 113, 7370, 10123, 3915, 6998, 2704, 8653, 4938, 1426, 7635,
+ 10512, 1663, 6957, 3510, 2370, 2865, 3978, 9320, 3247, 9603, 6882,
+ 3186, 10659, 10163, 1153, 9405, 8241, 10040, 2178, 1544, 5559, 420,
+ 8304, 4905, 476, 3531, 5191, 9153, 2399, 8889, 3000, 671, 243,
+ 3016, 3763, 10849, 12262, 9223, 10657, 7205, 11272, 7404, 7575, 8146,
+ 10752, 242, 2678, 3704, 11744, 5019, 3833, 3778, 11899, 773, 5101,
+ 11222, 9888, 442, 2912, 5698, 11935, 4861, 7277, 9808, 11244, 2859,
+ 3780, 11414, 4976, 10682, 7201, 8005, 11287, 5011, 6267, 2987, 2437,
+ 3646, 2566, 10102, 9867, 6250, 5444, 2381, 11796, 8193, 4337, 11854,
+ 1912, 1378, 404, 7644, 1065, 2143, 11121, 5277, 3248, 11082, 2548,
+ 8058, 8907, 11934, 1759, 8582, 3694, 7110, 12144, 6747, 8652, 3459,
+ 2731, 8357, 6378, 7399, 10861, 1696, 9863, 334, 7657, 6534, 11029,
+ 4388, 11560, 3241, 10276, 9000, 9408, 3284, 10200, 7197, 6498, 544,
+ 2468, 339, 11267, 9, 2842, 480, 5331, 7300, 1673, 4278, 4177,
+ 8705, 9764, 1381, 7837, 2396, 8340, 8993, 4354, 130, 6915, 2837,
+ 11462, 5767, 953, 8541, 9813, 118, 7222, 2197, 3006, 9545, 563,
+ 9314, 2625, 11340, 4821, 2639, 7266, 5828, 6561, 7698, 3328, 6512,
+ 1351, 7311, 6553, 8155, 1305, 722, 5146, 4043, 12288, 10810, 2545,
+ 3621, 8747, 8785, 1646, 1212, 5860, 3195, 7203, 10963, 3201, 3014,
+ 955, 11499, 9970, 11119, 3135, 3712, 7443, 9542, 7484, 8736, 9995,
+ 11227, 1635, 9521, 1177, 8034, 140, 10436, 11563, 7678, 4320, 11289,
+ 9198, 12208, 2963, 7393, 2366, 9238};
+
+uint16_t newhope_psis_bitrev_montgomery[PARAM_N] = {
+ 4075, 6974, 7373, 7965, 3262, 5079, 522, 2169, 6364, 1018, 1041,
+ 8775, 2344, 11011, 5574, 1973, 4536, 1050, 6844, 3860, 3818, 6118,
+ 2683, 1190, 4789, 7822, 7540, 6752, 5456, 4449, 3789, 12142, 11973,
+ 382, 3988, 468, 6843, 5339, 6196, 3710, 11316, 1254, 5435, 10930,
+ 3998, 10256, 10367, 3879, 11889, 1728, 6137, 4948, 5862, 6136, 3643,
+ 6874, 8724, 654, 10302, 1702, 7083, 6760, 56, 3199, 9987, 605,
+ 11785, 8076, 5594, 9260, 6403, 4782, 6212, 4624, 9026, 8689, 4080,
+ 11868, 6221, 3602, 975, 8077, 8851, 9445, 5681, 3477, 1105, 142,
+ 241, 12231, 1003, 3532, 5009, 1956, 6008, 11404, 7377, 2049, 10968,
+ 12097, 7591, 5057, 3445, 4780, 2920, 7048, 3127, 8120, 11279, 6821,
+ 11502, 8807, 12138, 2127, 2839, 3957, 431, 1579, 6383, 9784, 5874,
+ 677, 3336, 6234, 2766, 1323, 9115, 12237, 2031, 6956, 6413, 2281,
+ 3969, 3991, 12133, 9522, 4737, 10996, 4774, 5429, 11871, 3772, 453,
+ 5908, 2882, 1805, 2051, 1954, 11713, 3963, 2447, 6142, 8174, 3030,
+ 1843, 2361, 12071, 2908, 3529, 3434, 3202, 7796, 2057, 5369, 11939,
+ 1512, 6906, 10474, 11026, 49, 10806, 5915, 1489, 9789, 5942, 10706,
+ 10431, 7535, 426, 8974, 3757, 10314, 9364, 347, 5868, 9551, 9634,
+ 6554, 10596, 9280, 11566, 174, 2948, 2503, 6507, 10723, 11606, 2459,
+ 64, 3656, 8455, 5257, 5919, 7856, 1747, 9166, 5486, 9235, 6065,
+ 835, 3570, 4240, 11580, 4046, 10970, 9139, 1058, 8210, 11848, 922,
+ 7967, 1958, 10211, 1112, 3728, 4049, 11130, 5990, 1404, 325, 948,
+ 11143, 6190, 295, 11637, 5766, 8212, 8273, 2919, 8527, 6119, 6992,
+ 8333, 1360, 2555, 6167, 1200, 7105, 7991, 3329, 9597, 12121, 5106,
+ 5961, 10695, 10327, 3051, 9923, 4896, 9326, 81, 3091, 1000, 7969,
+ 4611, 726, 1853, 12149, 4255, 11112, 2768, 10654, 1062, 2294, 3553,
+ 4805, 2747, 4846, 8577, 9154, 1170, 2319, 790, 11334, 9275, 9088,
+ 1326, 5086, 9094, 6429, 11077, 10643, 3504, 3542, 8668, 9744, 1479,
+ 1, 8246, 7143, 11567, 10984, 4134, 5736, 4978, 10938, 5777, 8961,
+ 4591, 5728, 6461, 5023, 9650, 7468, 949, 9664, 2975, 11726, 2744,
+ 9283, 10092, 5067, 12171, 2476, 3748, 11336, 6522, 827, 9452, 5374,
+ 12159, 7935, 3296, 3949, 9893, 4452, 10908, 2525, 3584, 8112, 8011,
+ 10616, 4989, 6958, 11809, 9447, 12280, 1022, 11950, 9821, 11745, 5791,
+ 5092, 2089, 9005, 2881, 3289, 2013, 9048, 729, 7901, 1260, 5755,
+ 4632, 11955, 2426, 10593, 1428, 4890, 5911, 3932, 9558, 8830, 3637,
+ 5542, 145, 5179, 8595, 3707, 10530, 355, 3382, 4231, 9741, 1207,
+ 9041, 7012, 1168, 10146, 11224, 4645, 11885, 10911, 10377, 435, 7952,
+ 4096, 493, 9908, 6845, 6039, 2422, 2187, 9723, 8643, 9852, 9302,
+ 6022, 7278, 1002, 4284, 5088, 1607, 7313, 875, 8509, 9430, 1045,
+ 2481, 5012, 7428, 354, 6591, 9377, 11847, 2401, 1067, 7188, 11516,
+ 390, 8511, 8456, 7270, 545, 8585, 9611, 12047, 1537, 4143, 4714,
+ 4885, 1017, 5084, 1632, 3066, 27, 1440, 8526, 9273, 12046, 11618,
+ 9289, 3400, 9890, 3136, 7098, 8758, 11813, 7384, 3985, 11869, 6730,
+ 10745, 10111, 2249, 4048, 2884, 11136, 2126, 1630, 9103, 5407, 2686,
+ 9042, 2969, 8311, 9424, 9919, 8779, 5332, 10626, 1777, 4654, 10863,
+ 7351, 3636, 9585, 5291, 8374, 2166, 4919, 12176, 9140, 12129, 7852,
+ 12286, 4895, 10805, 2780, 5195, 2305, 7247, 9644, 4053, 10600, 3364,
+ 3271, 4057, 4414, 9442, 7917, 2174, 3947, 11951, 2455, 6599, 10545,
+ 10975, 3654, 2894, 7681, 7126, 7287, 12269, 4119, 3343, 2151, 1522,
+ 7174, 7350, 11041, 2442, 2148, 5959, 6492, 8330, 8945, 5598, 3624,
+ 10397, 1325, 6565, 1945, 11260, 10077, 2674, 3338, 3276, 11034, 506,
+ 6505, 1392, 5478, 8778, 1178, 2776, 3408, 10347, 11124, 2575, 9489,
+ 12096, 6092, 10058, 4167, 6085, 923, 11251, 11912, 4578, 10669, 11914,
+ 425, 10453, 392, 10104, 8464, 4235, 8761, 7376, 2291, 3375, 7954,
+ 8896, 6617, 7790, 1737, 11667, 3982, 9342, 6680, 636, 6825, 7383,
+ 512, 4670, 2900, 12050, 7735, 994, 1687, 11883, 7021, 146, 10485,
+ 1403, 5189, 6094, 2483, 2054, 3042, 10945, 3981, 10821, 11826, 8882,
+ 8151, 180, 9600, 7684, 5219, 10880, 6780, 204, 11232, 2600, 7584,
+ 3121, 3017, 11053, 7814, 7043, 4251, 4739, 11063, 6771, 7073, 9261,
+ 2360, 11925, 1928, 11825, 8024, 3678, 3205, 3359, 11197, 5209, 8581,
+ 3238, 8840, 1136, 9363, 1826, 3171, 4489, 7885, 346, 2068, 1389,
+ 8257, 3163, 4840, 6127, 8062, 8921, 612, 4238, 10763, 8067, 125,
+ 11749, 10125, 5416, 2110, 716, 9839, 10584, 11475, 11873, 3448, 343,
+ 1908, 4538, 10423, 7078, 4727, 1208, 11572, 3589, 2982, 1373, 1721,
+ 10753, 4103, 2429, 4209, 5412, 5993, 9011, 438, 3515, 7228, 1218,
+ 8347, 5232, 8682, 1327, 7508, 4924, 448, 1014, 10029, 12221, 4566,
+ 5836, 12229, 2717, 1535, 3200, 5588, 5845, 412, 5102, 7326, 3744,
+ 3056, 2528, 7406, 8314, 9202, 6454, 6613, 1417, 10032, 7784, 1518,
+ 3765, 4176, 5063, 9828, 2275, 6636, 4267, 6463, 2065, 7725, 3495,
+ 8328, 8755, 8144, 10533, 5966, 12077, 9175, 9520, 5596, 6302, 8400,
+ 579, 6781, 11014, 5734, 11113, 11164, 4860, 1131, 10844, 9068, 8016,
+ 9694, 3837, 567, 9348, 7000, 6627, 7699, 5082, 682, 11309, 5207,
+ 4050, 7087, 844, 7434, 3769, 293, 9057, 6940, 9344, 10883, 2633,
+ 8190, 3944, 5530, 5604, 3480, 2171, 9282, 11024, 2213, 8136, 3805,
+ 767, 12239, 216, 11520, 6763, 10353, 7, 8566, 845, 7235, 3154,
+ 4360, 3285, 10268, 2832, 3572, 1282, 7559, 3229, 8360, 10583, 6105,
+ 3120, 6643, 6203, 8536, 8348, 6919, 3536, 9199, 10891, 11463, 5043,
+ 1658, 5618, 8787, 5789, 4719, 751, 11379, 6389, 10783, 3065, 7806,
+ 6586, 2622, 5386, 510, 7628, 6921, 578, 10345, 11839, 8929, 4684,
+ 12226, 7154, 9916, 7302, 8481, 3670, 11066, 2334, 1590, 7878, 10734,
+ 1802, 1891, 5103, 6151, 8820, 3418, 7846, 9951, 4693, 417, 9996,
+ 9652, 4510, 2946, 5461, 365, 881, 1927, 1015, 11675, 11009, 1371,
+ 12265, 2485, 11385, 5039, 6742, 8449, 1842, 12217, 8176, 9577, 4834,
+ 7937, 9461, 2643, 11194, 3045, 6508, 4094, 3451, 7911, 11048, 5406,
+ 4665, 3020, 6616, 11345, 7519, 3669, 5287, 1790, 7014, 5410, 11038,
+ 11249, 2035, 6125, 10407, 4565, 7315, 5078, 10506, 2840, 2478, 9270,
+ 4194, 9195, 4518, 7469, 1160, 6878, 2730, 10421, 10036, 1734, 3815,
+ 10939, 5832, 10595, 10759, 4423, 8420, 9617, 7119, 11010, 11424, 9173,
+ 189, 10080, 10526, 3466, 10588, 7592, 3578, 11511, 7785, 9663, 530,
+ 12150, 8957, 2532, 3317, 9349, 10243, 1481, 9332, 3454, 3758, 7899,
+ 4218, 2593, 11410, 2276, 982, 6513, 1849, 8494, 9021, 4523, 7988,
+ 8, 457, 648, 150, 8000, 2307, 2301, 874, 5650, 170, 9462,
+ 2873, 9855, 11498, 2535, 11169, 5808, 12268, 9687, 1901, 7171, 11787,
+ 3846, 1573, 6063, 3793, 466, 11259, 10608, 3821, 6320, 4649, 6263,
+ 2929};
+
+uint16_t newhope_psis_inv_montgomery[PARAM_N] = {
+ 256, 10570, 1510, 7238, 1034, 7170, 6291, 7921, 11665, 3422, 4000,
+ 2327, 2088, 5565, 795, 10647, 1521, 5484, 2539, 7385, 1055, 7173,
+ 8047, 11683, 1669, 1994, 3796, 5809, 4341, 9398, 11876, 12230, 10525,
+ 12037, 12253, 3506, 4012, 9351, 4847, 2448, 7372, 9831, 3160, 2207,
+ 5582, 2553, 7387, 6322, 9681, 1383, 10731, 1533, 219, 5298, 4268,
+ 7632, 6357, 9686, 8406, 4712, 9451, 10128, 4958, 5975, 11387, 8649,
+ 11769, 6948, 11526, 12180, 1740, 10782, 6807, 2728, 7412, 4570, 4164,
+ 4106, 11120, 12122, 8754, 11784, 3439, 5758, 11356, 6889, 9762, 11928,
+ 1704, 1999, 10819, 12079, 12259, 7018, 11536, 1648, 1991, 2040, 2047,
+ 2048, 10826, 12080, 8748, 8272, 8204, 1172, 1923, 7297, 2798, 7422,
+ 6327, 4415, 7653, 6360, 11442, 12168, 7005, 8023, 9924, 8440, 8228,
+ 2931, 7441, 1063, 3663, 5790, 9605, 10150, 1450, 8985, 11817, 10466,
+ 10273, 12001, 3470, 7518, 1074, 1909, 7295, 9820, 4914, 702, 5367,
+ 7789, 8135, 9940, 1420, 3714, 11064, 12114, 12264, 1752, 5517, 9566,
+ 11900, 1700, 3754, 5803, 829, 1874, 7290, 2797, 10933, 5073, 7747,
+ 8129, 6428, 6185, 11417, 1631, 233, 5300, 9535, 10140, 11982, 8734,
+ 8270, 2937, 10953, 8587, 8249, 2934, 9197, 4825, 5956, 4362, 9401,
+ 1343, 3703, 529, 10609, 12049, 6988, 6265, 895, 3639, 4031, 4087,
+ 4095, 585, 10617, 8539, 4731, 4187, 9376, 3095, 9220, 10095, 10220,
+ 1460, 10742, 12068, 1724, 5513, 11321, 6884, 2739, 5658, 6075, 4379,
+ 11159, 10372, 8504, 4726, 9453, 3106, 7466, 11600, 10435, 8513, 9994,
+ 8450, 9985, 3182, 10988, 8592, 2983, 9204, 4826, 2445, 5616, 6069,
+ 867, 3635, 5786, 11360, 5134, 2489, 10889, 12089, 1727, 7269, 2794,
+ 9177, 1311, 5454, 9557, 6632, 2703, 9164, 10087, 1441, 3717, 531,
+ 3587, 2268, 324, 5313, 759, 1864, 5533, 2546, 7386, 9833, 8427,
+ 4715, 11207, 1601, 7251, 4547, 11183, 12131, 1733, 10781, 10318, 1474,
+ 10744, 5046, 4232, 11138, 10369, 6748, 964, 7160, 4534, 7670, 8118,
+ 8182, 4680, 11202, 6867, 981, 8918, 1274, 182, 26, 7026, 8026,
+ 11680, 12202, 10521, 1503, 7237, 4545, 5916, 9623, 8397, 11733, 10454,
+ 3249, 9242, 6587, 941, 1890, 270, 10572, 6777, 9746, 6659, 6218,
+ 6155, 6146, 878, 1881, 7291, 11575, 12187, 1741, 7271, 8061, 11685,
+ 6936, 4502, 9421, 4857, 4205, 7623, 1089, 10689, 1527, 8996, 10063,
+ 11971, 10488, 6765, 2722, 3900, 9335, 11867, 6962, 11528, 5158, 4248,
+ 4118, 5855, 2592, 5637, 6072, 2623, 7397, 8079, 9932, 4930, 5971,
+ 853, 3633, 519, 8852, 11798, 3441, 11025, 1575, 225, 8810, 11792,
+ 12218, 3501, 9278, 3081, 9218, 4828, 7712, 8124, 11694, 12204, 3499,
+ 4011, 573, 3593, 5780, 7848, 9899, 10192, 1456, 208, 7052, 2763,
+ 7417, 11593, 10434, 12024, 8740, 11782, 10461, 3250, 5731, 7841, 9898,
+ 1414, 202, 3540, 7528, 2831, 2160, 10842, 5060, 4234, 4116, 588,
+ 84, 12, 7024, 2759, 9172, 6577, 11473, 1639, 9012, 3043, 7457,
+ 6332, 11438, 1634, 1989, 9062, 11828, 8712, 11778, 12216, 10523, 6770,
+ 9745, 10170, 4964, 9487, 6622, 946, 8913, 6540, 6201, 4397, 9406,
+ 8366, 9973, 8447, 8229, 11709, 8695, 10020, 3187, 5722, 2573, 10901,
+ 6824, 4486, 4152, 9371, 8361, 2950, 2177, 311, 1800, 9035, 8313,
+ 11721, 3430, 490, 70, 10, 1757, 251, 3547, 7529, 11609, 3414,
+ 7510, 4584, 4166, 9373, 1339, 5458, 7802, 11648, 1664, 7260, 9815,
+ 10180, 6721, 9738, 10169, 8475, 8233, 9954, 1422, 8981, 1283, 5450,
+ 11312, 1616, 3742, 11068, 10359, 4991, 713, 3613, 9294, 8350, 4704,
+ 672, 96, 7036, 9783, 11931, 3460, 5761, 823, 10651, 12055, 10500,
+ 1500, 5481, 783, 3623, 11051, 8601, 8251, 8201, 11705, 10450, 5004,
+ 4226, 7626, 2845, 2162, 3820, 7568, 9859, 3164, 452, 10598, 1514,
+ 5483, 6050, 6131, 4387, 7649, 8115, 6426, 918, 8909, 8295, 1185,
+ 5436, 11310, 8638, 1234, 5443, 11311, 5127, 2488, 2111, 10835, 5059,
+ 7745, 2862, 3920, 560, 80, 1767, 2008, 3798, 11076, 6849, 2734,
+ 10924, 12094, 8750, 1250, 10712, 6797, 971, 7161, 1023, 8924, 4786,
+ 7706, 4612, 4170, 7618, 6355, 4419, 5898, 11376, 10403, 10264, 6733,
+ 4473, 639, 5358, 2521, 9138, 3061, 5704, 4326, 618, 5355, 765,
+ 5376, 768, 7132, 4530, 9425, 3102, 9221, 6584, 11474, 10417, 10266,
+ 12000, 6981, 6264, 4406, 2385, 7363, 4563, 4163, 7617, 9866, 3165,
+ 9230, 11852, 10471, 5007, 5982, 11388, 5138, 734, 3616, 11050, 12112,
+ 6997, 11533, 12181, 10518, 12036, 3475, 2252, 7344, 9827, 4915, 9480,
+ 6621, 4457, 7659, 9872, 6677, 4465, 4149, 7615, 4599, 657, 3605,
+ 515, 10607, 6782, 4480, 640, 1847, 3775, 5806, 2585, 5636, 9583,
+ 1369, 10729, 8555, 10000, 11962, 5220, 7768, 8132, 8184, 9947, 1421,
+ 203, 29, 8782, 11788, 1684, 10774, 10317, 4985, 9490, 8378, 4708,
+ 11206, 5112, 5997, 7879, 11659, 12199, 8765, 10030, 4944, 5973, 6120,
+ 6141, 6144, 7900, 11662, 1666, 238, 34, 3516, 5769, 9602, 8394,
+ 9977, 6692, 956, 10670, 6791, 9748, 11926, 8726, 11780, 5194, 742,
+ 106, 8793, 10034, 3189, 10989, 5081, 4237, 5872, 4350, 2377, 10873,
+ 6820, 6241, 11425, 10410, 10265, 3222, 5727, 9596, 4882, 2453, 2106,
+ 3812, 11078, 12116, 5242, 4260, 11142, 8614, 11764, 12214, 5256, 4262,
+ 4120, 11122, 5100, 11262, 5120, 2487, 5622, 9581, 8391, 8221, 2930,
+ 10952, 12098, 6995, 6266, 9673, 4893, 699, 3611, 4027, 5842, 11368,
+ 1624, 232, 8811, 8281, 1183, 169, 8802, 3013, 2186, 5579, 797,
+ 3625, 4029, 11109, 1587, 7249, 11569, 8675, 6506, 2685, 10917, 12093,
+ 12261, 12285, 1755, 7273, 1039, 1904, 272, 3550, 9285, 3082, 5707,
+ 6082, 4380, 7648, 11626, 5172, 4250, 9385, 8363, 8217, 4685, 5936,
+ 848, 8899, 6538, 934, 1889, 3781, 9318, 10109, 10222, 6727, 961,
+ 5404, 772, 5377, 9546, 8386, 1198, 8949, 3034, 2189, 7335, 4559,
+ 5918, 2601, 10905, 5069, 9502, 3113, 7467, 8089, 11689, 5181, 9518,
+ 8382, 2953, 3933, 4073, 4093, 7607, 8109, 2914, 5683, 4323, 11151,
+ 1593, 10761, 6804, 972, 3650, 2277, 5592, 4310, 7638, 9869, 4921,
+ 703, 1856, 9043, 4803, 9464, 1352, 8971, 11815, 5199, 7765, 6376,
+ 4422, 7654, 2849, 407, 8836, 6529, 7955, 2892, 9191, 1313, 10721,
+ 12065, 12257, 1751, 9028, 8312, 2943, 2176, 3822, 546, 78, 8789,
+ 11789, 10462, 12028, 6985, 4509, 9422, 1346, 5459, 4291, 613, 10621,
+ 6784, 9747, 3148, 7472, 2823, 5670, 810, 7138, 8042, 4660, 7688,
+ 6365, 6176, 6149, 2634, 5643, 9584, 10147, 11983, 5223, 9524, 11894,
+ 10477, 8519, 1217, 3685, 2282, 326, 10580, 3267, 7489, 4581, 2410,
+ 5611, 11335, 6886, 8006, 8166, 11700, 3427, 11023, 8597, 10006, 3185,
+ 455, 65, 5276, 7776, 4622, 5927, 7869, 9902, 11948, 5218, 2501,
+ 5624, 2559, 10899, 1557, 1978, 10816, 10323, 8497, 4725, 675, 1852,
+ 10798, 12076, 10503, 3256, 9243, 3076, 2195, 10847, 12083, 10504, 12034,
+ 10497};
diff --git a/crypto/newhope/reduce.c b/crypto/newhope/reduce.c
new file mode 100644
index 00000000..e7f13649
--- /dev/null
+++ b/crypto/newhope/reduce.c
@@ -0,0 +1,42 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include "internal.h"
+
+
+/* Incomplete-reduction routines; for details on allowed input ranges
+ * and produced output ranges, see the description in the paper:
+ * https://cryptojedi.org/papers/#newhope */
+
+static const uint32_t kQInv = 12287; /* -inverse_mod(p,2^18) */
+static const uint32_t kRLog = 18;
+
+uint16_t newhope_montgomery_reduce(uint32_t a) {
+ uint32_t u;
+
+ u = (a * kQInv);
+ u &= ((1 << kRLog) - 1);
+ u *= PARAM_Q;
+ a = a + u;
+ return a >> 18;
+}
+
+uint16_t newhope_barrett_reduce(uint16_t a) {
+ uint32_t u;
+
+ u = ((uint32_t)a * 5) >> 16;
+ u *= PARAM_Q;
+ a -= u;
+ return a;
+}
diff --git a/crypto/obj/CMakeLists.txt b/crypto/obj/CMakeLists.txt
index b8a4ef37..46b7918d 100644
--- a/crypto/obj/CMakeLists.txt
+++ b/crypto/obj/CMakeLists.txt
@@ -8,3 +8,16 @@ add_library(
obj.c
obj_xref.c
)
+
+if(ENABLE_TESTS)
+add_executable(
+ obj_test
+
+ obj_test.cc
+
+ $<TARGET_OBJECTS:test_support>
+)
+
+target_link_libraries(obj_test crypto)
+add_dependencies(all_tests obj_test)
+endif() \ No newline at end of file
diff --git a/crypto/obj/README b/crypto/obj/README
index 8826e598..6199fb4b 100644
--- a/crypto/obj/README
+++ b/crypto/obj/README
@@ -1,17 +1,17 @@
OID information is generated via a series of perl scripts. In order, the full
list of commands to run are:
- perl objects.pl objects.txt obj_mac.num ../../include/openssl/obj_mac.h
- perl obj_dat.pl ../../include/openssl/obj_mac.h obj_dat.h
+ perl objects.pl objects.txt obj_mac.num ../../include/openssl/nid.h
+ perl obj_dat.pl ../../include/openssl/nid.h obj_dat.h
perl obj_xref.pl obj_mac.num obj_xref.txt > obj_xref.h
objects.txt contains the list of all built-in OIDs. It is processed by
-objects.pl to output obj_mac.num and obj_mac.h. obj_mac.num is the list of NID
+objects.pl to output obj_mac.num and nid.h. obj_mac.num is the list of NID
values for each OID. This is an input/output parameter so NID values are stable
-across regenerations. obj_mac.h is the header which defines macros for all the
+across regenerations. nid.h is the header which defines macros for all the
built-in OIDs in C.
-obj_mac.h is read by obj_dat.pl to generate obj_dat.h. obj_dat.h contains the
+nid.h is read by obj_dat.pl to generate obj_dat.h. obj_dat.h contains the
ASN1_OBJECTs corresponding to built-in OIDs themselves along with lookup tables
for search by short name, OID, etc.
@@ -28,7 +28,7 @@ Dependency graph:
[objects.pl] <--+
/ \ |
V V |
- obj_mac.h obj_mac.num obj_xref.txt
+ nid.h obj_mac.num obj_xref.txt
| \ /
V V V
[obj_dat.pl] [obj_xref.pl]
diff --git a/crypto/obj/obj.c b/crypto/obj/obj.c
index 94f739ce..16d964c5 100644
--- a/crypto/obj/obj.c
+++ b/crypto/obj/obj.c
@@ -87,7 +87,7 @@ static int obj_next_nid(void) {
CRYPTO_STATIC_MUTEX_lock_write(&global_next_nid_lock);
ret = global_next_nid++;
- CRYPTO_STATIC_MUTEX_unlock(&global_next_nid_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&global_next_nid_lock);
return ret;
}
@@ -200,11 +200,11 @@ int OBJ_obj2nid(const ASN1_OBJECT *obj) {
match = lh_ASN1_OBJECT_retrieve(global_added_by_data, obj);
if (match != NULL) {
- CRYPTO_STATIC_MUTEX_unlock(&global_added_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock);
return match->nid;
}
}
- CRYPTO_STATIC_MUTEX_unlock(&global_added_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock);
nid_ptr = bsearch(obj, kNIDsInOIDOrder, NUM_OBJ, sizeof(unsigned), obj_cmp);
if (nid_ptr == NULL) {
@@ -243,11 +243,11 @@ int OBJ_sn2nid(const char *short_name) {
template.sn = short_name;
match = lh_ASN1_OBJECT_retrieve(global_added_by_short_name, &template);
if (match != NULL) {
- CRYPTO_STATIC_MUTEX_unlock(&global_added_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock);
return match->nid;
}
}
- CRYPTO_STATIC_MUTEX_unlock(&global_added_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock);
nid_ptr = bsearch(short_name, kNIDsInShortNameOrder, NUM_SN, sizeof(unsigned), short_name_cmp);
if (nid_ptr == NULL) {
@@ -277,11 +277,11 @@ int OBJ_ln2nid(const char *long_name) {
template.ln = long_name;
match = lh_ASN1_OBJECT_retrieve(global_added_by_long_name, &template);
if (match != NULL) {
- CRYPTO_STATIC_MUTEX_unlock(&global_added_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock);
return match->nid;
}
}
- CRYPTO_STATIC_MUTEX_unlock(&global_added_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock);
nid_ptr = bsearch(long_name, kNIDsInLongNameOrder, NUM_LN, sizeof(unsigned), long_name_cmp);
if (nid_ptr == NULL) {
@@ -330,11 +330,11 @@ const ASN1_OBJECT *OBJ_nid2obj(int nid) {
template.nid = nid;
match = lh_ASN1_OBJECT_retrieve(global_added_by_nid, &template);
if (match != NULL) {
- CRYPTO_STATIC_MUTEX_unlock(&global_added_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock);
return match;
}
}
- CRYPTO_STATIC_MUTEX_unlock(&global_added_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock);
err:
OPENSSL_PUT_ERROR(OBJ, OBJ_R_UNKNOWN_NID);
@@ -618,7 +618,7 @@ static int obj_add_object(ASN1_OBJECT *obj) {
if (obj->ln != NULL) {
ok &= lh_ASN1_OBJECT_insert(global_added_by_long_name, &old_object, obj);
}
- CRYPTO_STATIC_MUTEX_unlock(&global_added_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&global_added_lock);
return ok;
}
diff --git a/crypto/obj/obj_dat.h b/crypto/obj/obj_dat.h
index bf44c6d9..1d779de6 100644
--- a/crypto/obj/obj_dat.h
+++ b/crypto/obj/obj_dat.h
@@ -1,6 +1,6 @@
/* THIS FILE IS GENERATED FROM objects.h by obj_dat.pl via the
* following command:
- * perl obj_dat.pl ../../include/openssl/obj_mac.h obj_dat.h */
+ * perl obj_dat.pl ../../include/openssl/nid.h obj_dat.h */
/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
* All rights reserved.
@@ -61,7 +61,7 @@
#define NUM_NID 949
#define NUM_SN 941
#define NUM_LN 941
-#define NUM_OBJ 882
+#define NUM_OBJ 876
static const unsigned char lvalues[6176]={
0x2A,0x86,0x48,0x86,0xF7,0x0D, /* [ 0] OBJ_rsadsi */
@@ -2482,7 +2482,7 @@ static const ASN1_OBJECT kObjects[NUM_NID]={
NID_dhSinglePass_cofactorDH_sha512kdf_scheme,6,&(lvalues[6169]),0},
{"dh-std-kdf","dh-std-kdf",NID_dh_std_kdf,0,NULL,0},
{"dh-cofactor-kdf","dh-cofactor-kdf",NID_dh_cofactor_kdf,0,NULL,0},
-{"X25519","x25519",NID_x25519,0,NULL,0},
+{"X25519","X25519",NID_X25519,0,NULL,0},
};
static const unsigned int kNIDsInShortNameOrder[NUM_SN]={
@@ -3538,6 +3538,7 @@ static const unsigned int kNIDsInLongNameOrder[NUM_LN]={
129, /* "TLS Web Server Authentication" */
133, /* "Time Stamping" */
375, /* "Trust Root" */
+948, /* "X25519" */
12, /* "X509" */
402, /* "X509v3 AC Targeting" */
746, /* "X509v3 Any Policy" */
@@ -4366,7 +4367,6 @@ static const unsigned int kNIDsInLongNameOrder[NUM_LN]={
742, /* "wap-wsg-idm-ecid-wtls9" */
804, /* "whirlpool" */
868, /* "x121Address" */
-948, /* "x25519" */
503, /* "x500UniqueIdentifier" */
158, /* "x509Certificate" */
160, /* "x509Crl" */
@@ -4374,12 +4374,6 @@ static const unsigned int kNIDsInLongNameOrder[NUM_LN]={
};
static const unsigned int kNIDsInOIDOrder[NUM_OBJ]={
- 0, /* OBJ_undef 0 */
-181, /* OBJ_iso 1 */
-393, /* OBJ_joint_iso_ccitt OBJ_joint_iso_itu_t */
-404, /* OBJ_ccitt OBJ_itu_t */
-645, /* OBJ_itu_t 0 */
-646, /* OBJ_joint_iso_itu_t 2 */
434, /* OBJ_data 0 9 */
182, /* OBJ_member_body 1 2 */
379, /* OBJ_org 1 3 */
diff --git a/crypto/obj/obj_dat.pl b/crypto/obj/obj_dat.pl
index 201ec722..036ded54 100644
--- a/crypto/obj/obj_dat.pl
+++ b/crypto/obj/obj_dat.pl
@@ -6,7 +6,7 @@ use integer;
if (scalar @ARGV != 2)
{
- print "Usage: perl obj_dat.pl ../../include/openssl/obj_mac.h obj_dat.h\n";
+ print "Usage: perl obj_dat.pl ../../include/openssl/nid.h obj_dat.h\n";
exit 1;
}
@@ -163,7 +163,7 @@ foreach (sort { $ln{$nid{$a}} cmp $ln{$nid{$b}} } @a)
push(@ln,sprintf("%2d,\t/* \"$ln{$nid{$_}}\" */\n",$_));
}
-@a=grep(defined($obj{$nid{$_}}),0 .. $n);
+@a=grep(defined($obj{$nid{$_}}) && $objd{$obj{$nid{$_}}} =~ /,/,0 .. $n);
foreach (sort obj_cmp @a)
{
$m=$obj{$nid{$_}};
@@ -176,7 +176,7 @@ foreach (sort obj_cmp @a)
print OUT <<'EOF';
/* THIS FILE IS GENERATED FROM objects.h by obj_dat.pl via the
* following command:
- * perl obj_dat.pl ../../include/openssl/obj_mac.h obj_dat.h */
+ * perl obj_dat.pl ../../include/openssl/nid.h obj_dat.h */
/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
* All rights reserved.
diff --git a/crypto/obj/obj_mac.num b/crypto/obj/obj_mac.num
index a0e09b80..3a7844cd 100644
--- a/crypto/obj/obj_mac.num
+++ b/crypto/obj/obj_mac.num
@@ -945,4 +945,5 @@ dhSinglePass_cofactorDH_sha384kdf_scheme 944
dhSinglePass_cofactorDH_sha512kdf_scheme 945
dh_std_kdf 946
dh_cofactor_kdf 947
-x25519 948
+X25519 948
+cecpq1 949
diff --git a/crypto/obj/obj_test.cc b/crypto/obj/obj_test.cc
new file mode 100644
index 00000000..2948941a
--- /dev/null
+++ b/crypto/obj/obj_test.cc
@@ -0,0 +1,106 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/crypto.h>
+#include <openssl/obj.h>
+
+
+static bool TestBasic() {
+ static const int kNID = NID_sha256WithRSAEncryption;
+ static const char kShortName[] = "RSA-SHA256";
+ static const char kLongName[] = "sha256WithRSAEncryption";
+ static const char kText[] = "1.2.840.113549.1.1.11";
+ static const uint8_t kDER[] = {
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+ };
+
+ CBS cbs;
+ CBS_init(&cbs, kDER, sizeof(kDER));
+ if (OBJ_cbs2nid(&cbs) != kNID ||
+ OBJ_sn2nid(kShortName) != kNID ||
+ OBJ_ln2nid(kLongName) != kNID ||
+ OBJ_txt2nid(kShortName) != kNID ||
+ OBJ_txt2nid(kLongName) != kNID ||
+ OBJ_txt2nid(kText) != kNID) {
+ return false;
+ }
+
+ if (strcmp(kShortName, OBJ_nid2sn(kNID)) != 0 ||
+ strcmp(kLongName, OBJ_nid2ln(kNID)) != 0) {
+ return false;
+ }
+
+ if (OBJ_sn2nid("this is not an OID") != NID_undef ||
+ OBJ_ln2nid("this is not an OID") != NID_undef ||
+ OBJ_txt2nid("this is not an OID") != NID_undef) {
+ return false;
+ }
+
+ CBS_init(&cbs, NULL, 0);
+ if (OBJ_cbs2nid(&cbs) != NID_undef) {
+ return false;
+ }
+
+ // 1.2.840.113554.4.1.72585.2 (https://davidben.net/oid).
+ static const uint8_t kUnknownDER[] = {
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09, 0x02,
+ };
+ CBS_init(&cbs, kUnknownDER, sizeof(kUnknownDER));
+ if (OBJ_cbs2nid(&cbs) != NID_undef) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestSignatureAlgorithms() {
+ int digest_nid, pkey_nid;
+ if (!OBJ_find_sigid_algs(NID_sha256WithRSAEncryption, &digest_nid,
+ &pkey_nid) ||
+ digest_nid != NID_sha256 || pkey_nid != NID_rsaEncryption) {
+ return false;
+ }
+
+ if (OBJ_find_sigid_algs(NID_sha256, &digest_nid, &pkey_nid)) {
+ return false;
+ }
+
+ int sign_nid;
+ if (!OBJ_find_sigid_by_algs(&sign_nid, NID_sha256, NID_rsaEncryption) ||
+ sign_nid != NID_sha256WithRSAEncryption) {
+ return false;
+ }
+
+ if (OBJ_find_sigid_by_algs(&sign_nid, NID_dsa, NID_rsaEncryption)) {
+ return false;
+ }
+
+ return true;
+}
+
+int main() {
+ CRYPTO_library_init();
+
+ if (!TestBasic() ||
+ !TestSignatureAlgorithms()) {
+ return 1;
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/obj/objects.pl b/crypto/obj/objects.pl
index 7073e855..165429b4 100644
--- a/crypto/obj/objects.pl
+++ b/crypto/obj/objects.pl
@@ -2,7 +2,7 @@
if (scalar @ARGV != 3)
{
- print "Usage: perl objects.pl objects.txt obj_mac.num ../../include/openssl/obj_mac.h\n";
+ print "Usage: perl objects.pl objects.txt obj_mac.num ../../include/openssl/nid.h\n";
exit 1;
}
@@ -127,7 +127,7 @@ open (OUT,">$ARGV[2]") || die "Can't open output file $ARGV[2]";
print OUT <<'EOF';
/* THIS FILE IS GENERATED FROM objects.txt by objects.pl via the
* following command:
- * perl objects.pl objects.txt obj_mac.num ../../include/openssl/obj_mac.h */
+ * perl objects.pl objects.txt obj_mac.num ../../include/openssl/nid.h */
/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
* All rights reserved.
@@ -186,23 +186,43 @@ print OUT <<'EOF';
* [including the GNU Public Licence.]
*/
-#define SN_undef "UNDEF"
-#define LN_undef "undefined"
-#define NID_undef 0
-#define OBJ_undef 0L
+#ifndef OPENSSL_HEADER_NID_H
+#define OPENSSL_HEADER_NID_H
+
+
+/* The nid library provides numbered values for ASN.1 object identifiers and
+ * other symbols. These values are used by other libraries to identify
+ * cryptographic primitives.
+ *
+ * A separate objects library, obj.h, provides functions for converting between
+ * nids and object identifiers. However it depends on large internal tables with
+ * the encodings of every nid defind. Consumers concerned with binary size
+ * should instead embed the encodings of the few consumed OIDs and compare
+ * against those.
+ *
+ * These values should not be used outside of a single process; they are not
+ * stable identifiers. */
+
+
+#define SN_undef "UNDEF"
+#define LN_undef "undefined"
+#define NID_undef 0
+#define OBJ_undef 0L
EOF
foreach (sort { $a <=> $b } keys %ordern)
{
$Cname=$ordern{$_};
- print OUT "#define SN_",$Cname,"\t\t\"",$sn{$Cname},"\"\n" if $sn{$Cname} ne "";
- print OUT "#define LN_",$Cname,"\t\t\"",$ln{$Cname},"\"\n" if $ln{$Cname} ne "";
- print OUT "#define NID_",$Cname,"\t\t",$nid{$Cname},"\n" if $nid{$Cname} ne "";
- print OUT "#define OBJ_",$Cname,"\t\t",$obj{$Cname},"\n" if $obj{$Cname} ne "";
+ print OUT "#define SN_",$Cname," \"",$sn{$Cname},"\"\n" if $sn{$Cname} ne "";
+ print OUT "#define LN_",$Cname," \"",$ln{$Cname},"\"\n" if $ln{$Cname} ne "";
+ print OUT "#define NID_",$Cname," ",$nid{$Cname},"\n" if $nid{$Cname} ne "";
+ print OUT "#define OBJ_",$Cname," ",$obj{$Cname},"\n" if $obj{$Cname} ne "";
print OUT "\n";
}
+print OUT "\n#endif /* OPENSSL_HEADER_NID_H */\n";
+
close OUT;
sub process_oid
diff --git a/crypto/obj/objects.txt b/crypto/obj/objects.txt
index 93cf53aa..75f2cbf9 100644
--- a/crypto/obj/objects.txt
+++ b/crypto/obj/objects.txt
@@ -1332,4 +1332,7 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme
: dh-cofactor-kdf
# NID for X25519 (no corresponding OID).
- : X25519 : x25519
+ : X25519
+
+# NID for CECPQ1 (no corresponding OID)
+ : cecpq1
diff --git a/crypto/pem/pem_lib.c b/crypto/pem/pem_lib.c
index deaf26ab..e53abf86 100644
--- a/crypto/pem/pem_lib.c
+++ b/crypto/pem/pem_lib.c
@@ -71,13 +71,10 @@
#include <openssl/rand.h>
#include <openssl/x509.h>
-#include "../evp/internal.h"
-
#define MIN_LENGTH 4
static int load_iv(char **fromp, unsigned char *to, int num);
static int check_pem(const char *nm, const char *name);
-int pem_check_suffix(const char *pem_str, const char *suffix);
void PEM_proc_type(char *buf, int type)
{
@@ -144,23 +141,11 @@ static int check_pem(const char *nm, const char *name)
/* Make PEM_STRING_EVP_PKEY match any private key */
if (!strcmp(name, PEM_STRING_EVP_PKEY)) {
- int slen;
- const EVP_PKEY_ASN1_METHOD *ameth;
- if (!strcmp(nm, PEM_STRING_PKCS8))
- return 1;
- if (!strcmp(nm, PEM_STRING_PKCS8INF))
- return 1;
- slen = pem_check_suffix(nm, "PRIVATE KEY");
- if (slen > 0) {
- /*
- * NB: ENGINE implementations wont contain a deprecated old
- * private key decode function so don't look for them.
- */
- ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen);
- if (ameth && ameth->old_priv_decode)
- return 1;
- }
- return 0;
+ return !strcmp(nm, PEM_STRING_PKCS8) ||
+ !strcmp(nm, PEM_STRING_PKCS8INF) ||
+ !strcmp(nm, PEM_STRING_RSA) ||
+ !strcmp(nm, PEM_STRING_EC) ||
+ !strcmp(nm, PEM_STRING_DSA);
}
/* Permit older strings */
@@ -277,7 +262,7 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
if (enc != NULL) {
objstr = OBJ_nid2sn(EVP_CIPHER_nid(enc));
- if (objstr == NULL) {
+ if (objstr == NULL || EVP_CIPHER_iv_length(enc) == 0) {
OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_CIPHER);
goto err;
}
@@ -779,28 +764,6 @@ int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,
return (0);
}
-/*
- * Check pem string and return prefix length. If for example the pem_str ==
- * "RSA PRIVATE KEY" and suffix = "PRIVATE KEY" the return value is 3 for the
- * string "RSA".
- */
-
-int pem_check_suffix(const char *pem_str, const char *suffix)
-{
- int pem_len = strlen(pem_str);
- int suffix_len = strlen(suffix);
- const char *p;
- if (suffix_len + 1 >= pem_len)
- return 0;
- p = pem_str + pem_len - suffix_len;
- if (strcmp(p, suffix))
- return 0;
- p--;
- if (*p != ' ')
- return 0;
- return p - pem_str;
-}
-
int PEM_def_callback(char *buf, int size, int rwflag, void *userdata)
{
if (!buf || !userdata) {
diff --git a/crypto/pem/pem_pkey.c b/crypto/pem/pem_pkey.c
index 4cac7c28..058c0311 100644
--- a/crypto/pem/pem_pkey.c
+++ b/crypto/pem/pem_pkey.c
@@ -69,10 +69,6 @@
#include <openssl/rand.h>
#include <openssl/x509.h>
-#include "../evp/internal.h"
-
-int pem_check_suffix(const char *pem_str, const char *suffix);
-
EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
void *u)
{
@@ -80,7 +76,6 @@ EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
const unsigned char *p = NULL;
unsigned char *data = NULL;
long len;
- int slen;
EVP_PKEY *ret = NULL;
if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_EVP_PKEY, bp, cb, u))
@@ -128,12 +123,15 @@ EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb,
*x = ret;
}
PKCS8_PRIV_KEY_INFO_free(p8inf);
- } else if ((slen = pem_check_suffix(nm, "PRIVATE KEY")) > 0) {
- const EVP_PKEY_ASN1_METHOD *ameth;
- ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen);
- if (!ameth || !ameth->old_priv_decode)
- goto p8err;
- ret = d2i_PrivateKey(ameth->pkey_id, x, &p, len);
+ } else if (strcmp(nm, PEM_STRING_RSA) == 0) {
+ /* TODO(davidben): d2i_PrivateKey parses PKCS#8 along with the
+ * standalone format. This and the cases below probably should not
+ * accept PKCS#8. */
+ ret = d2i_PrivateKey(EVP_PKEY_RSA, x, &p, len);
+ } else if (strcmp(nm, PEM_STRING_EC) == 0) {
+ ret = d2i_PrivateKey(EVP_PKEY_EC, x, &p, len);
+ } else if (strcmp(nm, PEM_STRING_DSA) == 0) {
+ ret = d2i_PrivateKey(EVP_PKEY_DSA, x, &p, len);
}
p8err:
if (ret == NULL)
@@ -150,14 +148,7 @@ int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
unsigned char *kstr, int klen,
pem_password_cb *cb, void *u)
{
- char pem_str[80];
- if (!x->ameth || x->ameth->priv_encode)
- return PEM_write_bio_PKCS8PrivateKey(bp, x, enc,
- (char *)kstr, klen, cb, u);
-
- BIO_snprintf(pem_str, 80, "%s PRIVATE KEY", x->ameth->pem_str);
- return PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey,
- pem_str, bp, x, enc, kstr, klen, cb, u);
+ return PEM_write_bio_PKCS8PrivateKey(bp, x, enc, (char *)kstr, klen, cb, u);
}
#ifndef OPENSSL_NO_FP_API
diff --git a/crypto/perlasm/x86_64-xlate.pl b/crypto/perlasm/x86_64-xlate.pl
index 3ebb0184..4965985d 100755
--- a/crypto/perlasm/x86_64-xlate.pl
+++ b/crypto/perlasm/x86_64-xlate.pl
@@ -190,14 +190,17 @@ my %globals;
sub out {
my $self = shift;
+ $self->{value} =~ s/\b(0b[0-1]+)/oct($1)/eig;
if ($gas) {
# Solaris /usr/ccs/bin/as can't handle multiplications
# in $self->{value}
- $self->{value} =~ s/(?<![\w\$\.])(0x?[0-9a-f]+)/oct($1)/egi;
- $self->{value} =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg;
+ my $value = $self->{value};
+ $value =~ s/(?<![\w\$\.])(0x?[0-9a-f]+)/oct($1)/egi;
+ if ($value =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg) {
+ $self->{value} = $value;
+ }
sprintf "\$%s",$self->{value};
} else {
- $self->{value} =~ s/(0b[0-1]+)/oct($1)/eig;
$self->{value} =~ s/0x([0-9a-f]+)/0$1h/ig if ($masm);
sprintf "%s",$self->{value};
}
diff --git a/crypto/perlasm/x86gas.pl b/crypto/perlasm/x86gas.pl
index 99d7c1bd..55d09d8b 100644
--- a/crypto/perlasm/x86gas.pl
+++ b/crypto/perlasm/x86gas.pl
@@ -17,7 +17,7 @@ sub opsize()
{ my $reg=shift;
if ($reg =~ m/^%e/o) { "l"; }
elsif ($reg =~ m/^%[a-d][hl]$/o) { "b"; }
- elsif ($reg =~ m/^%[xm]/o) { undef; }
+ elsif ($reg =~ m/^%[yxm]/o) { undef; }
else { "w"; }
}
diff --git a/crypto/pkcs8/CMakeLists.txt b/crypto/pkcs8/CMakeLists.txt
index 329e02b2..8f674f91 100644
--- a/crypto/pkcs8/CMakeLists.txt
+++ b/crypto/pkcs8/CMakeLists.txt
@@ -1,7 +1,7 @@
include_directories(../../include)
add_library(
- pkcs8
+ pkcs8_lib
OBJECT
diff --git a/crypto/pkcs8/p5_pbe.c b/crypto/pkcs8/p5_pbe.c
index 653cabf3..8e56d41b 100644
--- a/crypto/pkcs8/p5_pbe.c
+++ b/crypto/pkcs8/p5_pbe.c
@@ -57,6 +57,7 @@
#include <openssl/asn1t.h>
#include <openssl/err.h>
+#include <openssl/obj.h>
#include <openssl/pkcs8.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
diff --git a/crypto/pkcs8/p5_pbev2.c b/crypto/pkcs8/p5_pbev2.c
index fec0d86d..3799b39b 100644
--- a/crypto/pkcs8/p5_pbev2.c
+++ b/crypto/pkcs8/p5_pbev2.c
@@ -61,6 +61,7 @@
#include <openssl/cipher.h>
#include <openssl/err.h>
#include <openssl/mem.h>
+#include <openssl/obj.h>
#include <openssl/pkcs8.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
diff --git a/crypto/pkcs8/pkcs12_test.cc b/crypto/pkcs8/pkcs12_test.cc
index f1a1fcd2..17bcd273 100644
--- a/crypto/pkcs8/pkcs12_test.cc
+++ b/crypto/pkcs8/pkcs12_test.cc
@@ -708,7 +708,7 @@ static bool Test(const char *name, const uint8_t *der, size_t der_len) {
}
static bool TestCompat(const uint8_t *der, size_t der_len) {
- ScopedBIO bio(BIO_new_mem_buf((void*) der, der_len));
+ ScopedBIO bio(BIO_new_mem_buf(der, der_len));
if (!bio) {
return false;
}
diff --git a/crypto/pkcs8/pkcs8.c b/crypto/pkcs8/pkcs8.c
index 85af2063..0ca0f2ec 100644
--- a/crypto/pkcs8/pkcs8.c
+++ b/crypto/pkcs8/pkcs8.c
@@ -60,7 +60,6 @@
#include <string.h>
#include <openssl/asn1.h>
-#include <openssl/bn.h>
#include <openssl/buf.h>
#include <openssl/bytestring.h>
#include <openssl/cipher.h>
@@ -68,6 +67,7 @@
#include <openssl/err.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
+#include <openssl/obj.h>
#include <openssl/x509.h>
#include "internal.h"
@@ -112,112 +112,122 @@ static int ascii_to_ucs2(const char *ascii, size_t ascii_len,
static int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len,
const uint8_t *salt, size_t salt_len,
- int id, int iterations,
+ uint8_t id, int iterations,
size_t out_len, uint8_t *out,
- const EVP_MD *md_type) {
- uint8_t *B, *D, *I, *p, *Ai;
- int Slen, Plen, Ilen, Ijlen;
- int i, j, v;
- size_t u;
- int ret = 0;
- BIGNUM *Ij, *Bpl1; /* These hold Ij and B + 1 */
- EVP_MD_CTX ctx;
+ const EVP_MD *md) {
+ /* See https://tools.ietf.org/html/rfc7292#appendix-B. Quoted parts of the
+ * specification have errata applied and other typos fixed. */
- EVP_MD_CTX_init(&ctx);
- v = EVP_MD_block_size(md_type);
- u = EVP_MD_size(md_type);
- D = OPENSSL_malloc(v);
- Ai = OPENSSL_malloc(u);
- B = OPENSSL_malloc(v + 1);
- Slen = v * ((salt_len + v - 1) / v);
- if (pass_raw_len) {
- Plen = v * ((pass_raw_len + v - 1) / v);
- } else {
- Plen = 0;
+ if (iterations < 1) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT);
+ return 0;
}
- Ilen = Slen + Plen;
- I = OPENSSL_malloc(Ilen);
- Ij = BN_new();
- Bpl1 = BN_new();
- if (!D || !Ai || !B || !I || !Ij || !Bpl1) {
- goto err;
+
+ /* In the spec, |block_size| is called "v", but measured in bits. */
+ size_t block_size = EVP_MD_block_size(md);
+
+ /* 1. Construct a string, D (the "diversifier"), by concatenating v/8 copies
+ * of ID. */
+ uint8_t D[EVP_MAX_MD_BLOCK_SIZE];
+ memset(D, id, block_size);
+
+ /* 2. Concatenate copies of the salt together to create a string S of length
+ * v(ceiling(s/v)) bits (the final copy of the salt may be truncated to
+ * create S). Note that if the salt is the empty string, then so is S.
+ *
+ * 3. Concatenate copies of the password together to create a string P of
+ * length v(ceiling(p/v)) bits (the final copy of the password may be
+ * truncated to create P). Note that if the password is the empty string,
+ * then so is P.
+ *
+ * 4. Set I=S||P to be the concatenation of S and P. */
+ if (salt_len + block_size - 1 < salt_len ||
+ pass_raw_len + block_size - 1 < pass_raw_len) {
+ OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW);
+ return 0;
}
- for (i = 0; i < v; i++) {
- D[i] = id;
+ size_t S_len = block_size * ((salt_len + block_size - 1) / block_size);
+ size_t P_len = block_size * ((pass_raw_len + block_size - 1) / block_size);
+ size_t I_len = S_len + P_len;
+ if (I_len < S_len) {
+ OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW);
+ return 0;
}
- p = I;
- for (i = 0; i < Slen; i++) {
- *p++ = salt[i % salt_len];
+
+ uint8_t *I = OPENSSL_malloc(I_len);
+ if (I_len != 0 && I == NULL) {
+ OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
+ return 0;
}
- for (i = 0; i < Plen; i++) {
- *p++ = pass_raw[i % pass_raw_len];
+
+ size_t i;
+ for (i = 0; i < S_len; i++) {
+ I[i] = salt[i % salt_len];
}
- for (;;) {
- if (!EVP_DigestInit_ex(&ctx, md_type, NULL) ||
- !EVP_DigestUpdate(&ctx, D, v) ||
- !EVP_DigestUpdate(&ctx, I, Ilen) ||
- !EVP_DigestFinal_ex(&ctx, Ai, NULL)) {
+ for (i = 0; i < P_len; i++) {
+ I[i + S_len] = pass_raw[i % pass_raw_len];
+ }
+
+ int ret = 0;
+ EVP_MD_CTX ctx;
+ EVP_MD_CTX_init(&ctx);
+
+ while (out_len != 0) {
+ /* A. Set A_i=H^r(D||I). (i.e., the r-th hash of D||I,
+ * H(H(H(... H(D||I)))) */
+ uint8_t A[EVP_MAX_MD_SIZE];
+ unsigned A_len;
+ if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
+ !EVP_DigestUpdate(&ctx, D, block_size) ||
+ !EVP_DigestUpdate(&ctx, I, I_len) ||
+ !EVP_DigestFinal_ex(&ctx, A, &A_len)) {
goto err;
}
- for (j = 1; j < iterations; j++) {
- if (!EVP_DigestInit_ex(&ctx, md_type, NULL) ||
- !EVP_DigestUpdate(&ctx, Ai, u) ||
- !EVP_DigestFinal_ex(&ctx, Ai, NULL)) {
+ int iter;
+ for (iter = 1; iter < iterations; iter++) {
+ if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
+ !EVP_DigestUpdate(&ctx, A, A_len) ||
+ !EVP_DigestFinal_ex(&ctx, A, &A_len)) {
goto err;
}
}
- memcpy(out, Ai, out_len < u ? out_len : u);
- if (u >= out_len) {
- ret = 1;
- goto end;
- }
- out_len -= u;
- out += u;
- for (j = 0; j < v; j++) {
- B[j] = Ai[j % u];
+
+ size_t todo = out_len < A_len ? out_len : A_len;
+ memcpy(out, A, todo);
+ out += todo;
+ out_len -= todo;
+ if (out_len == 0) {
+ break;
}
- /* Work out B + 1 first then can use B as tmp space */
- if (!BN_bin2bn(B, v, Bpl1) ||
- !BN_add_word(Bpl1, 1)) {
- goto err;
+
+ /* B. Concatenate copies of A_i to create a string B of length v bits (the
+ * final copy of A_i may be truncated to create B). */
+ uint8_t B[EVP_MAX_MD_BLOCK_SIZE];
+ for (i = 0; i < block_size; i++) {
+ B[i] = A[i % A_len];
}
- for (j = 0; j < Ilen; j += v) {
- if (!BN_bin2bn(I + j, v, Ij) ||
- !BN_add(Ij, Ij, Bpl1) ||
- !BN_bn2bin(Ij, B)) {
- goto err;
- }
- Ijlen = BN_num_bytes(Ij);
- /* If more than 2^(v*8) - 1 cut off MSB */
- if (Ijlen > v) {
- if (!BN_bn2bin(Ij, B)) {
- goto err;
- }
- memcpy(I + j, B + 1, v);
- /* If less than v bytes pad with zeroes */
- } else if (Ijlen < v) {
- memset(I + j, 0, v - Ijlen);
- if (!BN_bn2bin(Ij, I + j + v - Ijlen)) {
- goto err;
- }
- } else if (!BN_bn2bin(Ij, I + j)) {
- goto err;
+
+ /* C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit blocks,
+ * where k=ceiling(s/v)+ceiling(p/v), modify I by setting I_j=(I_j+B+1) mod
+ * 2^v for each j. */
+ assert(I_len % block_size == 0);
+ for (i = 0; i < I_len; i += block_size) {
+ unsigned carry = 1;
+ size_t j;
+ for (j = block_size - 1; j < block_size; j--) {
+ carry += I[i + j] + B[j];
+ I[i + j] = (uint8_t)carry;
+ carry >>= 8;
}
}
}
-err:
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
+ ret = 1;
-end:
- OPENSSL_free(Ai);
- OPENSSL_free(B);
- OPENSSL_free(D);
+err:
+ OPENSSL_cleanse(I, I_len);
OPENSSL_free(I);
- BN_free(Ij);
- BN_free(Bpl1);
EVP_MD_CTX_cleanup(&ctx);
-
return ret;
}
diff --git a/crypto/poly1305/asm/poly1305-armv4.pl b/crypto/poly1305/asm/poly1305-armv4.pl
new file mode 100755
index 00000000..9b765cec
--- /dev/null
+++ b/crypto/poly1305/asm/poly1305-armv4.pl
@@ -0,0 +1,1216 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# IALU(*)/gcc-4.4 NEON
+#
+# ARM11xx(ARMv6) 7.78/+100% -
+# Cortex-A5 6.30/+130% 2.96
+# Cortex-A8 6.25/+115% 2.36
+# Cortex-A9 5.10/+95% 2.55
+# Cortex-A15 3.79/+85% 1.25(**)
+# Snapdragon S4 5.70/+100% 1.48(**)
+#
+# (*) this is for -march=armv6, i.e. with bunch of ldrb loading data;
+# (**) these are trade-off results, they can be improved by ~8% but at
+# the cost of 15/12% regression on Cortex-A5/A7, it's even possible
+# to improve Cortex-A9 result, but then A5/A7 loose more than 20%;
+
+$flavour = shift;
+if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
+else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} }
+
+if ($flavour && $flavour ne "void") {
+ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+ ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
+ ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
+ die "can't locate arm-xlate.pl";
+
+ open STDOUT,"| \"$^X\" $xlate $flavour $output";
+} else {
+ open STDOUT,">$output";
+}
+
+($ctx,$inp,$len,$padbit)=map("r$_",(0..3));
+
+$code.=<<___;
+#include <openssl/arm_arch.h>
+
+.text
+#if defined(__thumb2__)
+.syntax unified
+.thumb
+#else
+.code 32
+#endif
+
+.globl poly1305_emit
+.globl poly1305_blocks
+.globl poly1305_init
+.type poly1305_init,%function
+.align 5
+poly1305_init:
+.Lpoly1305_init:
+ stmdb sp!,{r4-r11}
+
+ eor r3,r3,r3
+ cmp $inp,#0
+ str r3,[$ctx,#0] @ zero hash value
+ str r3,[$ctx,#4]
+ str r3,[$ctx,#8]
+ str r3,[$ctx,#12]
+ str r3,[$ctx,#16]
+ str r3,[$ctx,#36] @ is_base2_26
+ add $ctx,$ctx,#20
+
+#ifdef __thumb2__
+ it eq
+#endif
+ moveq r0,#0
+ beq .Lno_key
+
+#if __ARM_MAX_ARCH__>=7
+ adr r11,.Lpoly1305_init
+ ldr r12,.LOPENSSL_armcap
+#endif
+ ldrb r4,[$inp,#0]
+ mov r10,#0x0fffffff
+ ldrb r5,[$inp,#1]
+ and r3,r10,#-4 @ 0x0ffffffc
+ ldrb r6,[$inp,#2]
+ ldrb r7,[$inp,#3]
+ orr r4,r4,r5,lsl#8
+ ldrb r5,[$inp,#4]
+ orr r4,r4,r6,lsl#16
+ ldrb r6,[$inp,#5]
+ orr r4,r4,r7,lsl#24
+ ldrb r7,[$inp,#6]
+ and r4,r4,r10
+
+#if __ARM_MAX_ARCH__>=7
+ ldr r12,[r11,r12] @ OPENSSL_armcap_P
+# ifdef __APPLE__
+ ldr r12,[r12]
+# endif
+#endif
+ ldrb r8,[$inp,#7]
+ orr r5,r5,r6,lsl#8
+ ldrb r6,[$inp,#8]
+ orr r5,r5,r7,lsl#16
+ ldrb r7,[$inp,#9]
+ orr r5,r5,r8,lsl#24
+ ldrb r8,[$inp,#10]
+ and r5,r5,r3
+
+#if __ARM_MAX_ARCH__>=7
+ tst r12,#ARMV7_NEON @ check for NEON
+# ifdef __APPLE__
+ adr r9,poly1305_blocks_neon
+ adr r11,poly1305_blocks
+# ifdef __thumb2__
+ it ne
+# endif
+ movne r11,r9
+ adr r12,poly1305_emit
+ adr r10,poly1305_emit_neon
+# ifdef __thumb2__
+ it ne
+# endif
+ movne r12,r10
+# else
+# ifdef __thumb2__
+ itete eq
+# endif
+ addeq r12,r11,#(poly1305_emit-.Lpoly1305_init)
+ addne r12,r11,#(poly1305_emit_neon-.Lpoly1305_init)
+ addeq r11,r11,#(poly1305_blocks-.Lpoly1305_init)
+ addne r11,r11,#(poly1305_blocks_neon-.Lpoly1305_init)
+# endif
+# ifdef __thumb2__
+ orr r12,r12,#1 @ thumb-ify address
+ orr r11,r11,#1
+# endif
+#endif
+ ldrb r9,[$inp,#11]
+ orr r6,r6,r7,lsl#8
+ ldrb r7,[$inp,#12]
+ orr r6,r6,r8,lsl#16
+ ldrb r8,[$inp,#13]
+ orr r6,r6,r9,lsl#24
+ ldrb r9,[$inp,#14]
+ and r6,r6,r3
+
+ ldrb r10,[$inp,#15]
+ orr r7,r7,r8,lsl#8
+ str r4,[$ctx,#0]
+ orr r7,r7,r9,lsl#16
+ str r5,[$ctx,#4]
+ orr r7,r7,r10,lsl#24
+ str r6,[$ctx,#8]
+ and r7,r7,r3
+ str r7,[$ctx,#12]
+#if __ARM_MAX_ARCH__>=7
+ stmia r2,{r11,r12} @ fill functions table
+ mov r0,#1
+#else
+ mov r0,#0
+#endif
+.Lno_key:
+ ldmia sp!,{r4-r11}
+#if __ARM_ARCH__>=5
+ ret @ bx lr
+#else
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+.size poly1305_init,.-poly1305_init
+___
+{
+my ($h0,$h1,$h2,$h3,$h4,$r0,$r1,$r2,$r3)=map("r$_",(4..12));
+my ($s1,$s2,$s3)=($r1,$r2,$r3);
+
+$code.=<<___;
+.type poly1305_blocks,%function
+.align 5
+poly1305_blocks:
+ stmdb sp!,{r3-r11,lr}
+
+ ands $len,$len,#-16
+ beq .Lno_data
+
+ cmp $padbit,#0
+ add $len,$len,$inp @ end pointer
+ sub sp,sp,#32
+
+ ldmia $ctx,{$h0-$r3} @ load context
+
+ str $ctx,[sp,#12] @ offload stuff
+ mov lr,$inp
+ str $len,[sp,#16]
+ str $r1,[sp,#20]
+ str $r2,[sp,#24]
+ str $r3,[sp,#28]
+ b .Loop
+
+.Loop:
+#if __ARM_ARCH__<7
+ ldrb r0,[lr],#16 @ load input
+# ifdef __thumb2__
+ it hi
+# endif
+ addhi $h4,$h4,#1 @ 1<<128
+ ldrb r1,[lr,#-15]
+ ldrb r2,[lr,#-14]
+ ldrb r3,[lr,#-13]
+ orr r1,r0,r1,lsl#8
+ ldrb r0,[lr,#-12]
+ orr r2,r1,r2,lsl#16
+ ldrb r1,[lr,#-11]
+ orr r3,r2,r3,lsl#24
+ ldrb r2,[lr,#-10]
+ adds $h0,$h0,r3 @ accumulate input
+
+ ldrb r3,[lr,#-9]
+ orr r1,r0,r1,lsl#8
+ ldrb r0,[lr,#-8]
+ orr r2,r1,r2,lsl#16
+ ldrb r1,[lr,#-7]
+ orr r3,r2,r3,lsl#24
+ ldrb r2,[lr,#-6]
+ adcs $h1,$h1,r3
+
+ ldrb r3,[lr,#-5]
+ orr r1,r0,r1,lsl#8
+ ldrb r0,[lr,#-4]
+ orr r2,r1,r2,lsl#16
+ ldrb r1,[lr,#-3]
+ orr r3,r2,r3,lsl#24
+ ldrb r2,[lr,#-2]
+ adcs $h2,$h2,r3
+
+ ldrb r3,[lr,#-1]
+ orr r1,r0,r1,lsl#8
+ str lr,[sp,#8] @ offload input pointer
+ orr r2,r1,r2,lsl#16
+ add $s1,$r1,$r1,lsr#2
+ orr r3,r2,r3,lsl#24
+#else
+ ldr r0,[lr],#16 @ load input
+# ifdef __thumb2__
+ it hi
+# endif
+ addhi $h4,$h4,#1 @ padbit
+ ldr r1,[lr,#-12]
+ ldr r2,[lr,#-8]
+ ldr r3,[lr,#-4]
+# ifdef __ARMEB__
+ rev r0,r0
+ rev r1,r1
+ rev r2,r2
+ rev r3,r3
+# endif
+ adds $h0,$h0,r0 @ accumulate input
+ str lr,[sp,#8] @ offload input pointer
+ adcs $h1,$h1,r1
+ add $s1,$r1,$r1,lsr#2
+ adcs $h2,$h2,r2
+#endif
+ add $s2,$r2,$r2,lsr#2
+ adcs $h3,$h3,r3
+ add $s3,$r3,$r3,lsr#2
+
+ umull r2,r3,$h1,$r0
+ adc $h4,$h4,#0
+ umull r0,r1,$h0,$r0
+ umlal r2,r3,$h4,$s1
+ umlal r0,r1,$h3,$s1
+ ldr $r1,[sp,#20] @ reload $r1
+ umlal r2,r3,$h2,$s3
+ umlal r0,r1,$h1,$s3
+ umlal r2,r3,$h3,$s2
+ umlal r0,r1,$h2,$s2
+ umlal r2,r3,$h0,$r1
+ str r0,[sp,#0] @ future $h0
+ mul r0,$s2,$h4
+ ldr $r2,[sp,#24] @ reload $r2
+ adds r2,r2,r1 @ d1+=d0>>32
+ eor r1,r1,r1
+ adc lr,r3,#0 @ future $h2
+ str r2,[sp,#4] @ future $h1
+
+ mul r2,$s3,$h4
+ eor r3,r3,r3
+ umlal r0,r1,$h3,$s3
+ ldr $r3,[sp,#28] @ reload $r3
+ umlal r2,r3,$h3,$r0
+ umlal r0,r1,$h2,$r0
+ umlal r2,r3,$h2,$r1
+ umlal r0,r1,$h1,$r1
+ umlal r2,r3,$h1,$r2
+ umlal r0,r1,$h0,$r2
+ umlal r2,r3,$h0,$r3
+ ldr $h0,[sp,#0]
+ mul $h4,$r0,$h4
+ ldr $h1,[sp,#4]
+
+ adds $h2,lr,r0 @ d2+=d1>>32
+ ldr lr,[sp,#8] @ reload input pointer
+ adc r1,r1,#0
+ adds $h3,r2,r1 @ d3+=d2>>32
+ ldr r0,[sp,#16] @ reload end pointer
+ adc r3,r3,#0
+ add $h4,$h4,r3 @ h4+=d3>>32
+
+ and r1,$h4,#-4
+ and $h4,$h4,#3
+ add r1,r1,r1,lsr#2 @ *=5
+ adds $h0,$h0,r1
+ adcs $h1,$h1,#0
+ adcs $h2,$h2,#0
+ adc $h3,$h3,#0
+
+ cmp r0,lr @ done yet?
+ bhi .Loop
+
+ ldr $ctx,[sp,#12]
+ add sp,sp,#32
+ stmia $ctx,{$h0-$h4} @ store the result
+
+.Lno_data:
+#if __ARM_ARCH__>=5
+ ldmia sp!,{r3-r11,pc}
+#else
+ ldmia sp!,{r3-r11,lr}
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+.size poly1305_blocks,.-poly1305_blocks
+___
+}
+{
+my ($ctx,$mac,$nonce)=map("r$_",(0..2));
+my ($h0,$h1,$h2,$h3,$h4,$g0,$g1,$g2,$g3)=map("r$_",(3..11));
+my $g4=$h4;
+
+$code.=<<___;
+.type poly1305_emit,%function
+.align 5
+poly1305_emit:
+ stmdb sp!,{r4-r11}
+.Lpoly1305_emit_enter:
+
+ ldmia $ctx,{$h0-$h4}
+ adds $g0,$h0,#5 @ compare to modulus
+ adcs $g1,$h1,#0
+ adcs $g2,$h2,#0
+ adcs $g3,$h3,#0
+ adc $g4,$h4,#0
+ tst $g4,#4 @ did it carry/borrow?
+
+#ifdef __thumb2__
+ it ne
+#endif
+ movne $h0,$g0
+ ldr $g0,[$nonce,#0]
+#ifdef __thumb2__
+ it ne
+#endif
+ movne $h1,$g1
+ ldr $g1,[$nonce,#4]
+#ifdef __thumb2__
+ it ne
+#endif
+ movne $h2,$g2
+ ldr $g2,[$nonce,#8]
+#ifdef __thumb2__
+ it ne
+#endif
+ movne $h3,$g3
+ ldr $g3,[$nonce,#12]
+
+ adds $h0,$h0,$g0
+ adcs $h1,$h1,$g1
+ adcs $h2,$h2,$g2
+ adc $h3,$h3,$g3
+
+#if __ARM_ARCH__>=7
+# ifdef __ARMEB__
+ rev $h0,$h0
+ rev $h1,$h1
+ rev $h2,$h2
+ rev $h3,$h3
+# endif
+ str $h0,[$mac,#0]
+ str $h1,[$mac,#4]
+ str $h2,[$mac,#8]
+ str $h3,[$mac,#12]
+#else
+ strb $h0,[$mac,#0]
+ mov $h0,$h0,lsr#8
+ strb $h1,[$mac,#4]
+ mov $h1,$h1,lsr#8
+ strb $h2,[$mac,#8]
+ mov $h2,$h2,lsr#8
+ strb $h3,[$mac,#12]
+ mov $h3,$h3,lsr#8
+
+ strb $h0,[$mac,#1]
+ mov $h0,$h0,lsr#8
+ strb $h1,[$mac,#5]
+ mov $h1,$h1,lsr#8
+ strb $h2,[$mac,#9]
+ mov $h2,$h2,lsr#8
+ strb $h3,[$mac,#13]
+ mov $h3,$h3,lsr#8
+
+ strb $h0,[$mac,#2]
+ mov $h0,$h0,lsr#8
+ strb $h1,[$mac,#6]
+ mov $h1,$h1,lsr#8
+ strb $h2,[$mac,#10]
+ mov $h2,$h2,lsr#8
+ strb $h3,[$mac,#14]
+ mov $h3,$h3,lsr#8
+
+ strb $h0,[$mac,#3]
+ strb $h1,[$mac,#7]
+ strb $h2,[$mac,#11]
+ strb $h3,[$mac,#15]
+#endif
+ ldmia sp!,{r4-r11}
+#if __ARM_ARCH__>=5
+ ret @ bx lr
+#else
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+.size poly1305_emit,.-poly1305_emit
+___
+{
+my ($R0,$R1,$S1,$R2,$S2,$R3,$S3,$R4,$S4) = map("d$_",(0..9));
+my ($D0,$D1,$D2,$D3,$D4, $H0,$H1,$H2,$H3,$H4) = map("q$_",(5..14));
+my ($T0,$T1,$MASK) = map("q$_",(15,4,0));
+
+my ($in2,$zeros,$tbl0,$tbl1) = map("r$_",(4..7));
+
+$code.=<<___;
+#if __ARM_MAX_ARCH__>=7
+.fpu neon
+
+.type poly1305_init_neon,%function
+.align 5
+poly1305_init_neon:
+ ldr r4,[$ctx,#20] @ load key base 2^32
+ ldr r5,[$ctx,#24]
+ ldr r6,[$ctx,#28]
+ ldr r7,[$ctx,#32]
+
+ and r2,r4,#0x03ffffff @ base 2^32 -> base 2^26
+ mov r3,r4,lsr#26
+ mov r4,r5,lsr#20
+ orr r3,r3,r5,lsl#6
+ mov r5,r6,lsr#14
+ orr r4,r4,r6,lsl#12
+ mov r6,r7,lsr#8
+ orr r5,r5,r7,lsl#18
+ and r3,r3,#0x03ffffff
+ and r4,r4,#0x03ffffff
+ and r5,r5,#0x03ffffff
+
+ vdup.32 $R0,r2 @ r^1 in both lanes
+ add r2,r3,r3,lsl#2 @ *5
+ vdup.32 $R1,r3
+ add r3,r4,r4,lsl#2
+ vdup.32 $S1,r2
+ vdup.32 $R2,r4
+ add r4,r5,r5,lsl#2
+ vdup.32 $S2,r3
+ vdup.32 $R3,r5
+ add r5,r6,r6,lsl#2
+ vdup.32 $S3,r4
+ vdup.32 $R4,r6
+ vdup.32 $S4,r5
+
+ mov $zeros,#2 @ counter
+
+.Lsquare_neon:
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
+ @ d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4
+ @ d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4
+ @ d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4
+ @ d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4
+
+ vmull.u32 $D0,$R0,${R0}[1]
+ vmull.u32 $D1,$R1,${R0}[1]
+ vmull.u32 $D2,$R2,${R0}[1]
+ vmull.u32 $D3,$R3,${R0}[1]
+ vmull.u32 $D4,$R4,${R0}[1]
+
+ vmlal.u32 $D0,$R4,${S1}[1]
+ vmlal.u32 $D1,$R0,${R1}[1]
+ vmlal.u32 $D2,$R1,${R1}[1]
+ vmlal.u32 $D3,$R2,${R1}[1]
+ vmlal.u32 $D4,$R3,${R1}[1]
+
+ vmlal.u32 $D0,$R3,${S2}[1]
+ vmlal.u32 $D1,$R4,${S2}[1]
+ vmlal.u32 $D3,$R1,${R2}[1]
+ vmlal.u32 $D2,$R0,${R2}[1]
+ vmlal.u32 $D4,$R2,${R2}[1]
+
+ vmlal.u32 $D0,$R2,${S3}[1]
+ vmlal.u32 $D3,$R0,${R3}[1]
+ vmlal.u32 $D1,$R3,${S3}[1]
+ vmlal.u32 $D2,$R4,${S3}[1]
+ vmlal.u32 $D4,$R1,${R3}[1]
+
+ vmlal.u32 $D3,$R4,${S4}[1]
+ vmlal.u32 $D0,$R1,${S4}[1]
+ vmlal.u32 $D1,$R2,${S4}[1]
+ vmlal.u32 $D2,$R3,${S4}[1]
+ vmlal.u32 $D4,$R0,${R4}[1]
+
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
+ @ and P. Schwabe
+
+ vshr.u64 $T0,$D3,#26
+ vmovn.i64 $D3#lo,$D3
+ vshr.u64 $T1,$D0,#26
+ vmovn.i64 $D0#lo,$D0
+ vadd.i64 $D4,$D4,$T0 @ h3 -> h4
+ vbic.i32 $D3#lo,#0xfc000000 @ &=0x03ffffff
+ vadd.i64 $D1,$D1,$T1 @ h0 -> h1
+ vbic.i32 $D0#lo,#0xfc000000
+
+ vshrn.u64 $T0#lo,$D4,#26
+ vmovn.i64 $D4#lo,$D4
+ vshr.u64 $T1,$D1,#26
+ vmovn.i64 $D1#lo,$D1
+ vadd.i64 $D2,$D2,$T1 @ h1 -> h2
+ vbic.i32 $D4#lo,#0xfc000000
+ vbic.i32 $D1#lo,#0xfc000000
+
+ vadd.i32 $D0#lo,$D0#lo,$T0#lo
+ vshl.u32 $T0#lo,$T0#lo,#2
+ vshrn.u64 $T1#lo,$D2,#26
+ vmovn.i64 $D2#lo,$D2
+ vadd.i32 $D0#lo,$D0#lo,$T0#lo @ h4 -> h0
+ vadd.i32 $D3#lo,$D3#lo,$T1#lo @ h2 -> h3
+ vbic.i32 $D2#lo,#0xfc000000
+
+ vshr.u32 $T0#lo,$D0#lo,#26
+ vbic.i32 $D0#lo,#0xfc000000
+ vshr.u32 $T1#lo,$D3#lo,#26
+ vbic.i32 $D3#lo,#0xfc000000
+ vadd.i32 $D1#lo,$D1#lo,$T0#lo @ h0 -> h1
+ vadd.i32 $D4#lo,$D4#lo,$T1#lo @ h3 -> h4
+
+ subs $zeros,$zeros,#1
+ beq .Lsquare_break_neon
+
+ add $tbl0,$ctx,#(48+0*9*4)
+ add $tbl1,$ctx,#(48+1*9*4)
+
+ vtrn.32 $R0,$D0#lo @ r^2:r^1
+ vtrn.32 $R2,$D2#lo
+ vtrn.32 $R3,$D3#lo
+ vtrn.32 $R1,$D1#lo
+ vtrn.32 $R4,$D4#lo
+
+ vshl.u32 $S2,$R2,#2 @ *5
+ vshl.u32 $S3,$R3,#2
+ vshl.u32 $S1,$R1,#2
+ vshl.u32 $S4,$R4,#2
+ vadd.i32 $S2,$S2,$R2
+ vadd.i32 $S1,$S1,$R1
+ vadd.i32 $S3,$S3,$R3
+ vadd.i32 $S4,$S4,$R4
+
+ vst4.32 {${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]!
+ vst4.32 {${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]!
+ vst4.32 {${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
+ vst4.32 {${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
+ vst1.32 {${S4}[0]},[$tbl0,:32]
+ vst1.32 {${S4}[1]},[$tbl1,:32]
+
+ b .Lsquare_neon
+
+.align 4
+.Lsquare_break_neon:
+ add $tbl0,$ctx,#(48+2*4*9)
+ add $tbl1,$ctx,#(48+3*4*9)
+
+ vmov $R0,$D0#lo @ r^4:r^3
+ vshl.u32 $S1,$D1#lo,#2 @ *5
+ vmov $R1,$D1#lo
+ vshl.u32 $S2,$D2#lo,#2
+ vmov $R2,$D2#lo
+ vshl.u32 $S3,$D3#lo,#2
+ vmov $R3,$D3#lo
+ vshl.u32 $S4,$D4#lo,#2
+ vmov $R4,$D4#lo
+ vadd.i32 $S1,$S1,$D1#lo
+ vadd.i32 $S2,$S2,$D2#lo
+ vadd.i32 $S3,$S3,$D3#lo
+ vadd.i32 $S4,$S4,$D4#lo
+
+ vst4.32 {${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]!
+ vst4.32 {${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]!
+ vst4.32 {${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
+ vst4.32 {${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
+ vst1.32 {${S4}[0]},[$tbl0]
+ vst1.32 {${S4}[1]},[$tbl1]
+
+ ret @ bx lr
+.size poly1305_init_neon,.-poly1305_init_neon
+
+.type poly1305_blocks_neon,%function
+.align 5
+poly1305_blocks_neon:
+ ldr ip,[$ctx,#36] @ is_base2_26
+ ands $len,$len,#-16
+ beq .Lno_data_neon
+
+ cmp $len,#64
+ bhs .Lenter_neon
+ tst ip,ip @ is_base2_26?
+ beq poly1305_blocks
+
+.Lenter_neon:
+ stmdb sp!,{r4-r7}
+ vstmdb sp!,{d8-d15} @ ABI specification says so
+
+ tst ip,ip @ is_base2_26?
+ bne .Lbase2_26_neon
+
+ stmdb sp!,{r1-r3,lr}
+ bl poly1305_init_neon
+
+ ldr r4,[$ctx,#0] @ load hash value base 2^32
+ ldr r5,[$ctx,#4]
+ ldr r6,[$ctx,#8]
+ ldr r7,[$ctx,#12]
+ ldr ip,[$ctx,#16]
+
+ and r2,r4,#0x03ffffff @ base 2^32 -> base 2^26
+ mov r3,r4,lsr#26
+ veor $D0#lo,$D0#lo,$D0#lo
+ mov r4,r5,lsr#20
+ orr r3,r3,r5,lsl#6
+ veor $D1#lo,$D1#lo,$D1#lo
+ mov r5,r6,lsr#14
+ orr r4,r4,r6,lsl#12
+ veor $D2#lo,$D2#lo,$D2#lo
+ mov r6,r7,lsr#8
+ orr r5,r5,r7,lsl#18
+ veor $D3#lo,$D3#lo,$D3#lo
+ and r3,r3,#0x03ffffff
+ orr r6,r6,ip,lsl#24
+ veor $D4#lo,$D4#lo,$D4#lo
+ and r4,r4,#0x03ffffff
+ mov r1,#1
+ and r5,r5,#0x03ffffff
+ str r1,[$ctx,#36] @ is_base2_26
+
+ vmov.32 $D0#lo[0],r2
+ vmov.32 $D1#lo[0],r3
+ vmov.32 $D2#lo[0],r4
+ vmov.32 $D3#lo[0],r5
+ vmov.32 $D4#lo[0],r6
+ adr $zeros,.Lzeros
+
+ ldmia sp!,{r1-r3,lr}
+ b .Lbase2_32_neon
+
+.align 4
+.Lbase2_26_neon:
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ load hash value
+
+ veor $D0#lo,$D0#lo,$D0#lo
+ veor $D1#lo,$D1#lo,$D1#lo
+ veor $D2#lo,$D2#lo,$D2#lo
+ veor $D3#lo,$D3#lo,$D3#lo
+ veor $D4#lo,$D4#lo,$D4#lo
+ vld4.32 {$D0#lo[0],$D1#lo[0],$D2#lo[0],$D3#lo[0]},[$ctx]!
+ adr $zeros,.Lzeros
+ vld1.32 {$D4#lo[0]},[$ctx]
+ sub $ctx,$ctx,#16 @ rewind
+
+.Lbase2_32_neon:
+ add $in2,$inp,#32
+ mov $padbit,$padbit,lsl#24
+ tst $len,#31
+ beq .Leven
+
+ vld4.32 {$H0#lo[0],$H1#lo[0],$H2#lo[0],$H3#lo[0]},[$inp]!
+ vmov.32 $H4#lo[0],$padbit
+ sub $len,$len,#16
+ add $in2,$inp,#32
+
+# ifdef __ARMEB__
+ vrev32.8 $H0,$H0
+ vrev32.8 $H3,$H3
+ vrev32.8 $H1,$H1
+ vrev32.8 $H2,$H2
+# endif
+ vsri.u32 $H4#lo,$H3#lo,#8 @ base 2^32 -> base 2^26
+ vshl.u32 $H3#lo,$H3#lo,#18
+
+ vsri.u32 $H3#lo,$H2#lo,#14
+ vshl.u32 $H2#lo,$H2#lo,#12
+ vadd.i32 $H4#hi,$H4#lo,$D4#lo @ add hash value and move to #hi
+
+ vbic.i32 $H3#lo,#0xfc000000
+ vsri.u32 $H2#lo,$H1#lo,#20
+ vshl.u32 $H1#lo,$H1#lo,#6
+
+ vbic.i32 $H2#lo,#0xfc000000
+ vsri.u32 $H1#lo,$H0#lo,#26
+ vadd.i32 $H3#hi,$H3#lo,$D3#lo
+
+ vbic.i32 $H0#lo,#0xfc000000
+ vbic.i32 $H1#lo,#0xfc000000
+ vadd.i32 $H2#hi,$H2#lo,$D2#lo
+
+ vadd.i32 $H0#hi,$H0#lo,$D0#lo
+ vadd.i32 $H1#hi,$H1#lo,$D1#lo
+
+ mov $tbl1,$zeros
+ add $tbl0,$ctx,#48
+
+ cmp $len,$len
+ b .Long_tail
+
+.align 4
+.Leven:
+ subs $len,$len,#64
+# ifdef __thumb2__
+ it lo
+# endif
+ movlo $in2,$zeros
+
+ vmov.i32 $H4,#1<<24 @ padbit, yes, always
+ vld4.32 {$H0#lo,$H1#lo,$H2#lo,$H3#lo},[$inp] @ inp[0:1]
+ add $inp,$inp,#64
+ vld4.32 {$H0#hi,$H1#hi,$H2#hi,$H3#hi},[$in2] @ inp[2:3] (or 0)
+ add $in2,$in2,#64
+# ifdef __thumb2__
+ itt hi
+# endif
+ addhi $tbl1,$ctx,#(48+1*9*4)
+ addhi $tbl0,$ctx,#(48+3*9*4)
+
+# ifdef __ARMEB__
+ vrev32.8 $H0,$H0
+ vrev32.8 $H3,$H3
+ vrev32.8 $H1,$H1
+ vrev32.8 $H2,$H2
+# endif
+ vsri.u32 $H4,$H3,#8 @ base 2^32 -> base 2^26
+ vshl.u32 $H3,$H3,#18
+
+ vsri.u32 $H3,$H2,#14
+ vshl.u32 $H2,$H2,#12
+
+ vbic.i32 $H3,#0xfc000000
+ vsri.u32 $H2,$H1,#20
+ vshl.u32 $H1,$H1,#6
+
+ vbic.i32 $H2,#0xfc000000
+ vsri.u32 $H1,$H0,#26
+
+ vbic.i32 $H0,#0xfc000000
+ vbic.i32 $H1,#0xfc000000
+
+ bls .Lskip_loop
+
+ vld4.32 {${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]! @ load r^2
+ vld4.32 {${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]! @ load r^4
+ vld4.32 {${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
+ vld4.32 {${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
+ b .Loop_neon
+
+.align 5
+.Loop_neon:
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
+ @ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
+ @ \___________________/
+ @ ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
+ @ ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
+ @ \___________________/ \____________________/
+ @
+ @ Note that we start with inp[2:3]*r^2. This is because it
+ @ doesn't depend on reduction in previous iteration.
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4
+ @ d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4
+ @ d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4
+ @ d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4
+ @ d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
+
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ inp[2:3]*r^2
+
+ vadd.i32 $H2#lo,$H2#lo,$D2#lo @ accumulate inp[0:1]
+ vmull.u32 $D2,$H2#hi,${R0}[1]
+ vadd.i32 $H0#lo,$H0#lo,$D0#lo
+ vmull.u32 $D0,$H0#hi,${R0}[1]
+ vadd.i32 $H3#lo,$H3#lo,$D3#lo
+ vmull.u32 $D3,$H3#hi,${R0}[1]
+ vmlal.u32 $D2,$H1#hi,${R1}[1]
+ vadd.i32 $H1#lo,$H1#lo,$D1#lo
+ vmull.u32 $D1,$H1#hi,${R0}[1]
+
+ vadd.i32 $H4#lo,$H4#lo,$D4#lo
+ vmull.u32 $D4,$H4#hi,${R0}[1]
+ subs $len,$len,#64
+ vmlal.u32 $D0,$H4#hi,${S1}[1]
+# ifdef __thumb2__
+ it lo
+# endif
+ movlo $in2,$zeros
+ vmlal.u32 $D3,$H2#hi,${R1}[1]
+ vld1.32 ${S4}[1],[$tbl1,:32]
+ vmlal.u32 $D1,$H0#hi,${R1}[1]
+ vmlal.u32 $D4,$H3#hi,${R1}[1]
+
+ vmlal.u32 $D0,$H3#hi,${S2}[1]
+ vmlal.u32 $D3,$H1#hi,${R2}[1]
+ vmlal.u32 $D4,$H2#hi,${R2}[1]
+ vmlal.u32 $D1,$H4#hi,${S2}[1]
+ vmlal.u32 $D2,$H0#hi,${R2}[1]
+
+ vmlal.u32 $D3,$H0#hi,${R3}[1]
+ vmlal.u32 $D0,$H2#hi,${S3}[1]
+ vmlal.u32 $D4,$H1#hi,${R3}[1]
+ vmlal.u32 $D1,$H3#hi,${S3}[1]
+ vmlal.u32 $D2,$H4#hi,${S3}[1]
+
+ vmlal.u32 $D3,$H4#hi,${S4}[1]
+ vmlal.u32 $D0,$H1#hi,${S4}[1]
+ vmlal.u32 $D4,$H0#hi,${R4}[1]
+ vmlal.u32 $D1,$H2#hi,${S4}[1]
+ vmlal.u32 $D2,$H3#hi,${S4}[1]
+
+ vld4.32 {$H0#hi,$H1#hi,$H2#hi,$H3#hi},[$in2] @ inp[2:3] (or 0)
+ add $in2,$in2,#64
+
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ (hash+inp[0:1])*r^4 and accumulate
+
+ vmlal.u32 $D3,$H3#lo,${R0}[0]
+ vmlal.u32 $D0,$H0#lo,${R0}[0]
+ vmlal.u32 $D4,$H4#lo,${R0}[0]
+ vmlal.u32 $D1,$H1#lo,${R0}[0]
+ vmlal.u32 $D2,$H2#lo,${R0}[0]
+ vld1.32 ${S4}[0],[$tbl0,:32]
+
+ vmlal.u32 $D3,$H2#lo,${R1}[0]
+ vmlal.u32 $D0,$H4#lo,${S1}[0]
+ vmlal.u32 $D4,$H3#lo,${R1}[0]
+ vmlal.u32 $D1,$H0#lo,${R1}[0]
+ vmlal.u32 $D2,$H1#lo,${R1}[0]
+
+ vmlal.u32 $D3,$H1#lo,${R2}[0]
+ vmlal.u32 $D0,$H3#lo,${S2}[0]
+ vmlal.u32 $D4,$H2#lo,${R2}[0]
+ vmlal.u32 $D1,$H4#lo,${S2}[0]
+ vmlal.u32 $D2,$H0#lo,${R2}[0]
+
+ vmlal.u32 $D3,$H0#lo,${R3}[0]
+ vmlal.u32 $D0,$H2#lo,${S3}[0]
+ vmlal.u32 $D4,$H1#lo,${R3}[0]
+ vmlal.u32 $D1,$H3#lo,${S3}[0]
+ vmlal.u32 $D3,$H4#lo,${S4}[0]
+
+ vmlal.u32 $D2,$H4#lo,${S3}[0]
+ vmlal.u32 $D0,$H1#lo,${S4}[0]
+ vmlal.u32 $D4,$H0#lo,${R4}[0]
+ vmov.i32 $H4,#1<<24 @ padbit, yes, always
+ vmlal.u32 $D1,$H2#lo,${S4}[0]
+ vmlal.u32 $D2,$H3#lo,${S4}[0]
+
+ vld4.32 {$H0#lo,$H1#lo,$H2#lo,$H3#lo},[$inp] @ inp[0:1]
+ add $inp,$inp,#64
+# ifdef __ARMEB__
+ vrev32.8 $H0,$H0
+ vrev32.8 $H1,$H1
+ vrev32.8 $H2,$H2
+ vrev32.8 $H3,$H3
+# endif
+
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ lazy reduction interleaved with base 2^32 -> base 2^26
+
+ vshr.u64 $T0,$D3,#26
+ vmovn.i64 $D3#lo,$D3
+ vshr.u64 $T1,$D0,#26
+ vmovn.i64 $D0#lo,$D0
+ vadd.i64 $D4,$D4,$T0 @ h3 -> h4
+ vbic.i32 $D3#lo,#0xfc000000
+ vsri.u32 $H4,$H3,#8 @ base 2^32 -> base 2^26
+ vadd.i64 $D1,$D1,$T1 @ h0 -> h1
+ vshl.u32 $H3,$H3,#18
+ vbic.i32 $D0#lo,#0xfc000000
+
+ vshrn.u64 $T0#lo,$D4,#26
+ vmovn.i64 $D4#lo,$D4
+ vshr.u64 $T1,$D1,#26
+ vmovn.i64 $D1#lo,$D1
+ vadd.i64 $D2,$D2,$T1 @ h1 -> h2
+ vsri.u32 $H3,$H2,#14
+ vbic.i32 $D4#lo,#0xfc000000
+ vshl.u32 $H2,$H2,#12
+ vbic.i32 $D1#lo,#0xfc000000
+
+ vadd.i32 $D0#lo,$D0#lo,$T0#lo
+ vshl.u32 $T0#lo,$T0#lo,#2
+ vbic.i32 $H3,#0xfc000000
+ vshrn.u64 $T1#lo,$D2,#26
+ vmovn.i64 $D2#lo,$D2
+ vadd.i32 $D0#lo,$D0#lo,$T0#lo @ h4 -> h0
+ vsri.u32 $H2,$H1,#20
+ vadd.i32 $D3#lo,$D3#lo,$T1#lo @ h2 -> h3
+ vshl.u32 $H1,$H1,#6
+ vbic.i32 $D2#lo,#0xfc000000
+ vbic.i32 $H2,#0xfc000000
+
+ vshr.u32 $T0#lo,$D0#lo,#26
+ vbic.i32 $D0#lo,#0xfc000000
+ vsri.u32 $H1,$H0,#26
+ vbic.i32 $H0,#0xfc000000
+ vshr.u32 $T1#lo,$D3#lo,#26
+ vbic.i32 $D3#lo,#0xfc000000
+ vadd.i32 $D1#lo,$D1#lo,$T0#lo @ h0 -> h1
+ vadd.i32 $D4#lo,$D4#lo,$T1#lo @ h3 -> h4
+ vbic.i32 $H1,#0xfc000000
+
+ bhi .Loop_neon
+
+.Lskip_loop:
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
+
+ add $tbl1,$ctx,#(48+0*9*4)
+ add $tbl0,$ctx,#(48+1*9*4)
+ adds $len,$len,#32
+# ifdef __thumb2__
+ it ne
+# endif
+ movne $len,#0
+ bne .Long_tail
+
+ vadd.i32 $H2#hi,$H2#lo,$D2#lo @ add hash value and move to #hi
+ vadd.i32 $H0#hi,$H0#lo,$D0#lo
+ vadd.i32 $H3#hi,$H3#lo,$D3#lo
+ vadd.i32 $H1#hi,$H1#lo,$D1#lo
+ vadd.i32 $H4#hi,$H4#lo,$D4#lo
+
+.Long_tail:
+ vld4.32 {${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]! @ load r^1
+ vld4.32 {${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]! @ load r^2
+
+ vadd.i32 $H2#lo,$H2#lo,$D2#lo @ can be redundant
+ vmull.u32 $D2,$H2#hi,$R0
+ vadd.i32 $H0#lo,$H0#lo,$D0#lo
+ vmull.u32 $D0,$H0#hi,$R0
+ vadd.i32 $H3#lo,$H3#lo,$D3#lo
+ vmull.u32 $D3,$H3#hi,$R0
+ vadd.i32 $H1#lo,$H1#lo,$D1#lo
+ vmull.u32 $D1,$H1#hi,$R0
+ vadd.i32 $H4#lo,$H4#lo,$D4#lo
+ vmull.u32 $D4,$H4#hi,$R0
+
+ vmlal.u32 $D0,$H4#hi,$S1
+ vld4.32 {${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
+ vmlal.u32 $D3,$H2#hi,$R1
+ vld4.32 {${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
+ vmlal.u32 $D1,$H0#hi,$R1
+ vmlal.u32 $D4,$H3#hi,$R1
+ vmlal.u32 $D2,$H1#hi,$R1
+
+ vmlal.u32 $D3,$H1#hi,$R2
+ vld1.32 ${S4}[1],[$tbl1,:32]
+ vmlal.u32 $D0,$H3#hi,$S2
+ vld1.32 ${S4}[0],[$tbl0,:32]
+ vmlal.u32 $D4,$H2#hi,$R2
+ vmlal.u32 $D1,$H4#hi,$S2
+ vmlal.u32 $D2,$H0#hi,$R2
+
+ vmlal.u32 $D3,$H0#hi,$R3
+# ifdef __thumb2__
+ it ne
+# endif
+ addne $tbl1,$ctx,#(48+2*9*4)
+ vmlal.u32 $D0,$H2#hi,$S3
+# ifdef __thumb2__
+ it ne
+# endif
+ addne $tbl0,$ctx,#(48+3*9*4)
+ vmlal.u32 $D4,$H1#hi,$R3
+ vmlal.u32 $D1,$H3#hi,$S3
+ vmlal.u32 $D2,$H4#hi,$S3
+
+ vmlal.u32 $D3,$H4#hi,$S4
+ vorn $MASK,$MASK,$MASK @ all-ones, can be redundant
+ vmlal.u32 $D0,$H1#hi,$S4
+ vshr.u64 $MASK,$MASK,#38
+ vmlal.u32 $D4,$H0#hi,$R4
+ vmlal.u32 $D1,$H2#hi,$S4
+ vmlal.u32 $D2,$H3#hi,$S4
+
+ beq .Lshort_tail
+
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ (hash+inp[0:1])*r^4:r^3 and accumulate
+
+ vld4.32 {${R0}[1],${R1}[1],${S1}[1],${R2}[1]},[$tbl1]! @ load r^3
+ vld4.32 {${R0}[0],${R1}[0],${S1}[0],${R2}[0]},[$tbl0]! @ load r^4
+
+ vmlal.u32 $D2,$H2#lo,$R0
+ vmlal.u32 $D0,$H0#lo,$R0
+ vmlal.u32 $D3,$H3#lo,$R0
+ vmlal.u32 $D1,$H1#lo,$R0
+ vmlal.u32 $D4,$H4#lo,$R0
+
+ vmlal.u32 $D0,$H4#lo,$S1
+ vld4.32 {${S2}[1],${R3}[1],${S3}[1],${R4}[1]},[$tbl1]!
+ vmlal.u32 $D3,$H2#lo,$R1
+ vld4.32 {${S2}[0],${R3}[0],${S3}[0],${R4}[0]},[$tbl0]!
+ vmlal.u32 $D1,$H0#lo,$R1
+ vmlal.u32 $D4,$H3#lo,$R1
+ vmlal.u32 $D2,$H1#lo,$R1
+
+ vmlal.u32 $D3,$H1#lo,$R2
+ vld1.32 ${S4}[1],[$tbl1,:32]
+ vmlal.u32 $D0,$H3#lo,$S2
+ vld1.32 ${S4}[0],[$tbl0,:32]
+ vmlal.u32 $D4,$H2#lo,$R2
+ vmlal.u32 $D1,$H4#lo,$S2
+ vmlal.u32 $D2,$H0#lo,$R2
+
+ vmlal.u32 $D3,$H0#lo,$R3
+ vmlal.u32 $D0,$H2#lo,$S3
+ vmlal.u32 $D4,$H1#lo,$R3
+ vmlal.u32 $D1,$H3#lo,$S3
+ vmlal.u32 $D2,$H4#lo,$S3
+
+ vmlal.u32 $D3,$H4#lo,$S4
+ vorn $MASK,$MASK,$MASK @ all-ones
+ vmlal.u32 $D0,$H1#lo,$S4
+ vshr.u64 $MASK,$MASK,#38
+ vmlal.u32 $D4,$H0#lo,$R4
+ vmlal.u32 $D1,$H2#lo,$S4
+ vmlal.u32 $D2,$H3#lo,$S4
+
+.Lshort_tail:
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ horizontal addition
+
+ vadd.i64 $D3#lo,$D3#lo,$D3#hi
+ vadd.i64 $D0#lo,$D0#lo,$D0#hi
+ vadd.i64 $D4#lo,$D4#lo,$D4#hi
+ vadd.i64 $D1#lo,$D1#lo,$D1#hi
+ vadd.i64 $D2#lo,$D2#lo,$D2#hi
+
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ lazy reduction, but without narrowing
+
+ vshr.u64 $T0,$D3,#26
+ vand.i64 $D3,$D3,$MASK
+ vshr.u64 $T1,$D0,#26
+ vand.i64 $D0,$D0,$MASK
+ vadd.i64 $D4,$D4,$T0 @ h3 -> h4
+ vadd.i64 $D1,$D1,$T1 @ h0 -> h1
+
+ vshr.u64 $T0,$D4,#26
+ vand.i64 $D4,$D4,$MASK
+ vshr.u64 $T1,$D1,#26
+ vand.i64 $D1,$D1,$MASK
+ vadd.i64 $D2,$D2,$T1 @ h1 -> h2
+
+ vadd.i64 $D0,$D0,$T0
+ vshl.u64 $T0,$T0,#2
+ vshr.u64 $T1,$D2,#26
+ vand.i64 $D2,$D2,$MASK
+ vadd.i64 $D0,$D0,$T0 @ h4 -> h0
+ vadd.i64 $D3,$D3,$T1 @ h2 -> h3
+
+ vshr.u64 $T0,$D0,#26
+ vand.i64 $D0,$D0,$MASK
+ vshr.u64 $T1,$D3,#26
+ vand.i64 $D3,$D3,$MASK
+ vadd.i64 $D1,$D1,$T0 @ h0 -> h1
+ vadd.i64 $D4,$D4,$T1 @ h3 -> h4
+
+ cmp $len,#0
+ bne .Leven
+
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ store hash value
+
+ vst4.32 {$D0#lo[0],$D1#lo[0],$D2#lo[0],$D3#lo[0]},[$ctx]!
+ vst1.32 {$D4#lo[0]},[$ctx]
+
+ vldmia sp!,{d8-d15} @ epilogue
+ ldmia sp!,{r4-r7}
+.Lno_data_neon:
+ ret @ bx lr
+.size poly1305_blocks_neon,.-poly1305_blocks_neon
+
+.type poly1305_emit_neon,%function
+.align 5
+poly1305_emit_neon:
+ ldr ip,[$ctx,#36] @ is_base2_26
+
+ stmdb sp!,{r4-r11}
+
+ tst ip,ip
+ beq .Lpoly1305_emit_enter
+
+ ldmia $ctx,{$h0-$h4}
+ eor $g0,$g0,$g0
+
+ adds $h0,$h0,$h1,lsl#26 @ base 2^26 -> base 2^32
+ mov $h1,$h1,lsr#6
+ adcs $h1,$h1,$h2,lsl#20
+ mov $h2,$h2,lsr#12
+ adcs $h2,$h2,$h3,lsl#14
+ mov $h3,$h3,lsr#18
+ adcs $h3,$h3,$h4,lsl#8
+ adc $h4,$g0,$h4,lsr#24 @ can be partially reduced ...
+
+ and $g0,$h4,#-4 @ ... so reduce
+ and $h4,$h3,#3
+ add $g0,$g0,$g0,lsr#2 @ *= 5
+ adds $h0,$h0,$g0
+ adcs $h1,$h1,#0
+ adcs $h2,$h2,#0
+ adc $h3,$h3,#0
+
+ adds $g0,$h0,#5 @ compare to modulus
+ adcs $g1,$h1,#0
+ adcs $g2,$h2,#0
+ adcs $g3,$h3,#0
+ adc $g4,$h4,#0
+ tst $g4,#4 @ did it carry/borrow?
+
+# ifdef __thumb2__
+ it ne
+# endif
+ movne $h0,$g0
+ ldr $g0,[$nonce,#0]
+# ifdef __thumb2__
+ it ne
+# endif
+ movne $h1,$g1
+ ldr $g1,[$nonce,#4]
+# ifdef __thumb2__
+ it ne
+# endif
+ movne $h2,$g2
+ ldr $g2,[$nonce,#8]
+# ifdef __thumb2__
+ it ne
+# endif
+ movne $h3,$g3
+ ldr $g3,[$nonce,#12]
+
+ adds $h0,$h0,$g0 @ accumulate nonce
+ adcs $h1,$h1,$g1
+ adcs $h2,$h2,$g2
+ adc $h3,$h3,$g3
+
+# ifdef __ARMEB__
+ rev $h0,$h0
+ rev $h1,$h1
+ rev $h2,$h2
+ rev $h3,$h3
+# endif
+ str $h0,[$mac,#0] @ store the result
+ str $h1,[$mac,#4]
+ str $h2,[$mac,#8]
+ str $h3,[$mac,#12]
+
+ ldmia sp!,{r4-r11}
+ ret @ bx lr
+.size poly1305_emit_neon,.-poly1305_emit_neon
+
+.align 5
+.Lzeros:
+.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.LOPENSSL_armcap:
+.word OPENSSL_armcap_P-.Lpoly1305_init
+#endif
+___
+} }
+$code.=<<___;
+.asciz "Poly1305 for ARMv4/NEON, CRYPTOGAMS by <appro\@openssl.org>"
+.align 2
+#if __ARM_MAX_ARCH__>=7
+.comm OPENSSL_armcap_P,4,4
+#endif
+___
+
+foreach (split("\n",$code)) {
+ s/\`([^\`]*)\`/eval $1/geo;
+
+ s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo or
+ s/\bret\b/bx lr/go or
+ s/\bbx\s+lr\b/.word\t0xe12fff1e/go; # make it possible to compile with -march=armv4
+
+ print $_,"\n";
+}
+close STDOUT; # enforce flush
diff --git a/crypto/poly1305/asm/poly1305-armv8.pl b/crypto/poly1305/asm/poly1305-armv8.pl
new file mode 100755
index 00000000..1d9a81b8
--- /dev/null
+++ b/crypto/poly1305/asm/poly1305-armv8.pl
@@ -0,0 +1,925 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# This module implements Poly1305 hash for ARMv8.
+#
+# June 2015
+#
+# Numbers are cycles per processed byte with poly1305_blocks alone.
+#
+# IALU/gcc-4.9 NEON
+#
+# Apple A7 1.86/+5% 0.72
+# Cortex-A53 2.63/+58% 1.47
+# Cortex-A57 2.70/+7% 1.14
+# Denver 1.39/+50% 1.18(*)
+# X-Gene 2.00/+68% 2.19
+#
+# (*) estimate based on resources availability is less than 1.0,
+# i.e. measured result is worse than expected, presumably binary
+# translator is not almighty;
+
+$flavour=shift;
+$output=shift;
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
+( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
+die "can't locate arm-xlate.pl";
+
+open OUT,"| \"$^X\" $xlate $flavour $output";
+*STDOUT=*OUT;
+
+my ($ctx,$inp,$len,$padbit) = map("x$_",(0..3));
+my ($mac,$nonce)=($inp,$len);
+
+my ($h0,$h1,$h2,$r0,$r1,$s1,$t0,$t1,$d0,$d1,$d2) = map("x$_",(4..14));
+
+$code.=<<___;
+#include <openssl/arm_arch.h>
+
+.text
+
+// forward "declarations" are required for Apple
+.extern OPENSSL_armcap_P
+.globl poly1305_blocks
+.globl poly1305_emit
+
+.globl poly1305_init
+.type poly1305_init,%function
+.align 5
+poly1305_init:
+ cmp $inp,xzr
+ stp xzr,xzr,[$ctx] // zero hash value
+ stp xzr,xzr,[$ctx,#16] // [along with is_base2_26]
+
+ csel x0,xzr,x0,eq
+ b.eq .Lno_key
+
+#ifdef __ILP32__
+ ldrsw $t1,.LOPENSSL_armcap_P
+#else
+ ldr $t1,.LOPENSSL_armcap_P
+#endif
+ adr $t0,.LOPENSSL_armcap_P
+
+ ldp $r0,$r1,[$inp] // load key
+ mov $s1,#0xfffffffc0fffffff
+ movk $s1,#0x0fff,lsl#48
+ ldr w17,[$t0,$t1]
+#ifdef __ARMEB__
+ rev $r0,$r0 // flip bytes
+ rev $r1,$r1
+#endif
+ and $r0,$r0,$s1 // &=0ffffffc0fffffff
+ and $s1,$s1,#-4
+ and $r1,$r1,$s1 // &=0ffffffc0ffffffc
+ stp $r0,$r1,[$ctx,#32] // save key value
+
+ tst w17,#ARMV7_NEON
+
+ adr $d0,poly1305_blocks
+ adr $r0,poly1305_blocks_neon
+ adr $d1,poly1305_emit
+ adr $r1,poly1305_emit_neon
+
+ csel $d0,$d0,$r0,eq
+ csel $d1,$d1,$r1,eq
+
+ stp $d0,$d1,[$len]
+
+ mov x0,#1
+.Lno_key:
+ ret
+.size poly1305_init,.-poly1305_init
+
+.type poly1305_blocks,%function
+.align 5
+poly1305_blocks:
+ ands $len,$len,#-16
+ b.eq .Lno_data
+
+ ldp $h0,$h1,[$ctx] // load hash value
+ ldp $r0,$r1,[$ctx,#32] // load key value
+ ldr $h2,[$ctx,#16]
+ add $s1,$r1,$r1,lsr#2 // s1 = r1 + (r1 >> 2)
+ b .Loop
+
+.align 5
+.Loop:
+ ldp $t0,$t1,[$inp],#16 // load input
+ sub $len,$len,#16
+#ifdef __ARMEB__
+ rev $t0,$t0
+ rev $t1,$t1
+#endif
+ adds $h0,$h0,$t0 // accumulate input
+ adcs $h1,$h1,$t1
+
+ mul $d0,$h0,$r0 // h0*r0
+ adc $h2,$h2,$padbit
+ umulh $d1,$h0,$r0
+
+ mul $t0,$h1,$s1 // h1*5*r1
+ umulh $t1,$h1,$s1
+
+ adds $d0,$d0,$t0
+ mul $t0,$h0,$r1 // h0*r1
+ adc $d1,$d1,$t1
+ umulh $d2,$h0,$r1
+
+ adds $d1,$d1,$t0
+ mul $t0,$h1,$r0 // h1*r0
+ adc $d2,$d2,xzr
+ umulh $t1,$h1,$r0
+
+ adds $d1,$d1,$t0
+ mul $t0,$h2,$s1 // h2*5*r1
+ adc $d2,$d2,$t1
+ mul $t1,$h2,$r0 // h2*r0
+
+ adds $d1,$d1,$t0
+ adc $d2,$d2,$t1
+
+ and $t0,$d2,#-4 // final reduction
+ and $h2,$d2,#3
+ add $t0,$t0,$d2,lsr#2
+ adds $h0,$d0,$t0
+ adc $h1,$d1,xzr
+
+ cbnz $len,.Loop
+
+ stp $h0,$h1,[$ctx] // store hash value
+ str $h2,[$ctx,#16]
+
+.Lno_data:
+ ret
+.size poly1305_blocks,.-poly1305_blocks
+
+.type poly1305_emit,%function
+.align 5
+poly1305_emit:
+ ldp $h0,$h1,[$ctx] // load hash base 2^64
+ ldr $h2,[$ctx,#16]
+ ldp $t0,$t1,[$nonce] // load nonce
+
+ adds $d0,$h0,#5 // compare to modulus
+ adcs $d1,$h1,xzr
+ adc $d2,$h2,xzr
+
+ tst $d2,#-4 // see if it's carried/borrowed
+
+ csel $h0,$h0,$d0,eq
+ csel $h1,$h1,$d1,eq
+
+#ifdef __ARMEB__
+ ror $t0,$t0,#32 // flip nonce words
+ ror $t1,$t1,#32
+#endif
+ adds $h0,$h0,$t0 // accumulate nonce
+ adc $h1,$h1,$t1
+#ifdef __ARMEB__
+ rev $h0,$h0 // flip output bytes
+ rev $h1,$h1
+#endif
+ stp $h0,$h1,[$mac] // write result
+
+ ret
+.size poly1305_emit,.-poly1305_emit
+___
+my ($R0,$R1,$S1,$R2,$S2,$R3,$S3,$R4,$S4) = map("v$_.4s",(0..8));
+my ($IN01_0,$IN01_1,$IN01_2,$IN01_3,$IN01_4) = map("v$_.2s",(9..13));
+my ($IN23_0,$IN23_1,$IN23_2,$IN23_3,$IN23_4) = map("v$_.2s",(14..18));
+my ($ACC0,$ACC1,$ACC2,$ACC3,$ACC4) = map("v$_.2d",(19..23));
+my ($H0,$H1,$H2,$H3,$H4) = map("v$_.2s",(24..28));
+my ($T0,$T1,$MASK) = map("v$_",(29..31));
+
+my ($in2,$zeros)=("x16","x17");
+my $is_base2_26 = $zeros; # borrow
+
+$code.=<<___;
+.type poly1305_mult,%function
+.align 5
+poly1305_mult:
+ mul $d0,$h0,$r0 // h0*r0
+ umulh $d1,$h0,$r0
+
+ mul $t0,$h1,$s1 // h1*5*r1
+ umulh $t1,$h1,$s1
+
+ adds $d0,$d0,$t0
+ mul $t0,$h0,$r1 // h0*r1
+ adc $d1,$d1,$t1
+ umulh $d2,$h0,$r1
+
+ adds $d1,$d1,$t0
+ mul $t0,$h1,$r0 // h1*r0
+ adc $d2,$d2,xzr
+ umulh $t1,$h1,$r0
+
+ adds $d1,$d1,$t0
+ mul $t0,$h2,$s1 // h2*5*r1
+ adc $d2,$d2,$t1
+ mul $t1,$h2,$r0 // h2*r0
+
+ adds $d1,$d1,$t0
+ adc $d2,$d2,$t1
+
+ and $t0,$d2,#-4 // final reduction
+ and $h2,$d2,#3
+ add $t0,$t0,$d2,lsr#2
+ adds $h0,$d0,$t0
+ adc $h1,$d1,xzr
+
+ ret
+.size poly1305_mult,.-poly1305_mult
+
+.type poly1305_splat,%function
+.align 5
+poly1305_splat:
+ and x12,$h0,#0x03ffffff // base 2^64 -> base 2^26
+ ubfx x13,$h0,#26,#26
+ extr x14,$h1,$h0,#52
+ and x14,x14,#0x03ffffff
+ ubfx x15,$h1,#14,#26
+ extr x16,$h2,$h1,#40
+
+ str w12,[$ctx,#16*0] // r0
+ add w12,w13,w13,lsl#2 // r1*5
+ str w13,[$ctx,#16*1] // r1
+ add w13,w14,w14,lsl#2 // r2*5
+ str w12,[$ctx,#16*2] // s1
+ str w14,[$ctx,#16*3] // r2
+ add w14,w15,w15,lsl#2 // r3*5
+ str w13,[$ctx,#16*4] // s2
+ str w15,[$ctx,#16*5] // r3
+ add w15,w16,w16,lsl#2 // r4*5
+ str w14,[$ctx,#16*6] // s3
+ str w16,[$ctx,#16*7] // r4
+ str w15,[$ctx,#16*8] // s4
+
+ ret
+.size poly1305_splat,.-poly1305_splat
+
+.type poly1305_blocks_neon,%function
+.align 5
+poly1305_blocks_neon:
+ ldr $is_base2_26,[$ctx,#24]
+ cmp $len,#128
+ b.hs .Lblocks_neon
+ cbz $is_base2_26,poly1305_blocks
+
+.Lblocks_neon:
+ stp x29,x30,[sp,#-80]!
+ add x29,sp,#0
+
+ ands $len,$len,#-16
+ b.eq .Lno_data_neon
+
+ cbz $is_base2_26,.Lbase2_64_neon
+
+ ldp w10,w11,[$ctx] // load hash value base 2^26
+ ldp w12,w13,[$ctx,#8]
+ ldr w14,[$ctx,#16]
+
+ tst $len,#31
+ b.eq .Leven_neon
+
+ ldp $r0,$r1,[$ctx,#32] // load key value
+
+ add $h0,x10,x11,lsl#26 // base 2^26 -> base 2^64
+ lsr $h1,x12,#12
+ adds $h0,$h0,x12,lsl#52
+ add $h1,$h1,x13,lsl#14
+ adc $h1,$h1,xzr
+ lsr $h2,x14,#24
+ adds $h1,$h1,x14,lsl#40
+ adc $d2,$h2,xzr // can be partially reduced...
+
+ ldp $d0,$d1,[$inp],#16 // load input
+ sub $len,$len,#16
+ add $s1,$r1,$r1,lsr#2 // s1 = r1 + (r1 >> 2)
+
+ and $t0,$d2,#-4 // ... so reduce
+ and $h2,$d2,#3
+ add $t0,$t0,$d2,lsr#2
+ adds $h0,$h0,$t0
+ adc $h1,$h1,xzr
+
+#ifdef __ARMEB__
+ rev $d0,$d0
+ rev $d1,$d1
+#endif
+ adds $h0,$h0,$d0 // accumulate input
+ adcs $h1,$h1,$d1
+ adc $h2,$h2,$padbit
+
+ bl poly1305_mult
+ ldr x30,[sp,#8]
+
+ cbz $padbit,.Lstore_base2_64_neon
+
+ and x10,$h0,#0x03ffffff // base 2^64 -> base 2^26
+ ubfx x11,$h0,#26,#26
+ extr x12,$h1,$h0,#52
+ and x12,x12,#0x03ffffff
+ ubfx x13,$h1,#14,#26
+ extr x14,$h2,$h1,#40
+
+ cbnz $len,.Leven_neon
+
+ stp w10,w11,[$ctx] // store hash value base 2^26
+ stp w12,w13,[$ctx,#8]
+ str w14,[$ctx,#16]
+ b .Lno_data_neon
+
+.align 4
+.Lstore_base2_64_neon:
+ stp $h0,$h1,[$ctx] // store hash value base 2^64
+ stp $h2,xzr,[$ctx,#16] // note that is_base2_26 is zeroed
+ b .Lno_data_neon
+
+.align 4
+.Lbase2_64_neon:
+ ldp $r0,$r1,[$ctx,#32] // load key value
+
+ ldp $h0,$h1,[$ctx] // load hash value base 2^64
+ ldr $h2,[$ctx,#16]
+
+ tst $len,#31
+ b.eq .Linit_neon
+
+ ldp $d0,$d1,[$inp],#16 // load input
+ sub $len,$len,#16
+ add $s1,$r1,$r1,lsr#2 // s1 = r1 + (r1 >> 2)
+#ifdef __ARMEB__
+ rev $d0,$d0
+ rev $d1,$d1
+#endif
+ adds $h0,$h0,$d0 // accumulate input
+ adcs $h1,$h1,$d1
+ adc $h2,$h2,$padbit
+
+ bl poly1305_mult
+
+.Linit_neon:
+ and x10,$h0,#0x03ffffff // base 2^64 -> base 2^26
+ ubfx x11,$h0,#26,#26
+ extr x12,$h1,$h0,#52
+ and x12,x12,#0x03ffffff
+ ubfx x13,$h1,#14,#26
+ extr x14,$h2,$h1,#40
+
+ stp d8,d9,[sp,#16] // meet ABI requirements
+ stp d10,d11,[sp,#32]
+ stp d12,d13,[sp,#48]
+ stp d14,d15,[sp,#64]
+
+ fmov ${H0},x10
+ fmov ${H1},x11
+ fmov ${H2},x12
+ fmov ${H3},x13
+ fmov ${H4},x14
+
+ ////////////////////////////////// initialize r^n table
+ mov $h0,$r0 // r^1
+ add $s1,$r1,$r1,lsr#2 // s1 = r1 + (r1 >> 2)
+ mov $h1,$r1
+ mov $h2,xzr
+ add $ctx,$ctx,#48+12
+ bl poly1305_splat
+
+ bl poly1305_mult // r^2
+ sub $ctx,$ctx,#4
+ bl poly1305_splat
+
+ bl poly1305_mult // r^3
+ sub $ctx,$ctx,#4
+ bl poly1305_splat
+
+ bl poly1305_mult // r^4
+ sub $ctx,$ctx,#4
+ bl poly1305_splat
+ ldr x30,[sp,#8]
+
+ add $in2,$inp,#32
+ adr $zeros,.Lzeros
+ subs $len,$len,#64
+ csel $in2,$zeros,$in2,lo
+
+ mov x4,#1
+ str x4,[$ctx,#-24] // set is_base2_26
+ sub $ctx,$ctx,#48 // restore original $ctx
+ b .Ldo_neon
+
+.align 4
+.Leven_neon:
+ add $in2,$inp,#32
+ adr $zeros,.Lzeros
+ subs $len,$len,#64
+ csel $in2,$zeros,$in2,lo
+
+ stp d8,d9,[sp,#16] // meet ABI requirements
+ stp d10,d11,[sp,#32]
+ stp d12,d13,[sp,#48]
+ stp d14,d15,[sp,#64]
+
+ fmov ${H0},x10
+ fmov ${H1},x11
+ fmov ${H2},x12
+ fmov ${H3},x13
+ fmov ${H4},x14
+
+.Ldo_neon:
+ ldp x8,x12,[$in2],#16 // inp[2:3] (or zero)
+ ldp x9,x13,[$in2],#48
+
+ lsl $padbit,$padbit,#24
+ add x15,$ctx,#48
+
+#ifdef __ARMEB__
+ rev x8,x8
+ rev x12,x12
+ rev x9,x9
+ rev x13,x13
+#endif
+ and x4,x8,#0x03ffffff // base 2^64 -> base 2^26
+ and x5,x9,#0x03ffffff
+ ubfx x6,x8,#26,#26
+ ubfx x7,x9,#26,#26
+ add x4,x4,x5,lsl#32 // bfi x4,x5,#32,#32
+ extr x8,x12,x8,#52
+ extr x9,x13,x9,#52
+ add x6,x6,x7,lsl#32 // bfi x6,x7,#32,#32
+ fmov $IN23_0,x4
+ and x8,x8,#0x03ffffff
+ and x9,x9,#0x03ffffff
+ ubfx x10,x12,#14,#26
+ ubfx x11,x13,#14,#26
+ add x12,$padbit,x12,lsr#40
+ add x13,$padbit,x13,lsr#40
+ add x8,x8,x9,lsl#32 // bfi x8,x9,#32,#32
+ fmov $IN23_1,x6
+ add x10,x10,x11,lsl#32 // bfi x10,x11,#32,#32
+ add x12,x12,x13,lsl#32 // bfi x12,x13,#32,#32
+ fmov $IN23_2,x8
+ fmov $IN23_3,x10
+ fmov $IN23_4,x12
+
+ ldp x8,x12,[$inp],#16 // inp[0:1]
+ ldp x9,x13,[$inp],#48
+
+ ld1 {$R0,$R1,$S1,$R2},[x15],#64
+ ld1 {$S2,$R3,$S3,$R4},[x15],#64
+ ld1 {$S4},[x15]
+
+#ifdef __ARMEB__
+ rev x8,x8
+ rev x12,x12
+ rev x9,x9
+ rev x13,x13
+#endif
+ and x4,x8,#0x03ffffff // base 2^64 -> base 2^26
+ and x5,x9,#0x03ffffff
+ ubfx x6,x8,#26,#26
+ ubfx x7,x9,#26,#26
+ add x4,x4,x5,lsl#32 // bfi x4,x5,#32,#32
+ extr x8,x12,x8,#52
+ extr x9,x13,x9,#52
+ add x6,x6,x7,lsl#32 // bfi x6,x7,#32,#32
+ fmov $IN01_0,x4
+ and x8,x8,#0x03ffffff
+ and x9,x9,#0x03ffffff
+ ubfx x10,x12,#14,#26
+ ubfx x11,x13,#14,#26
+ add x12,$padbit,x12,lsr#40
+ add x13,$padbit,x13,lsr#40
+ add x8,x8,x9,lsl#32 // bfi x8,x9,#32,#32
+ fmov $IN01_1,x6
+ add x10,x10,x11,lsl#32 // bfi x10,x11,#32,#32
+ add x12,x12,x13,lsl#32 // bfi x12,x13,#32,#32
+ fmov $IN01_2,x8
+ fmov $IN01_3,x10
+ fmov $IN01_4,x12
+
+ b.ls .Lskip_loop
+
+.align 4
+.Loop_neon:
+ ////////////////////////////////////////////////////////////////
+ // ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
+ // ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
+ // \___________________/
+ // ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
+ // ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
+ // \___________________/ \____________________/
+ //
+ // Note that we start with inp[2:3]*r^2. This is because it
+ // doesn't depend on reduction in previous iteration.
+ ////////////////////////////////////////////////////////////////
+ // d4 = h0*r4 + h1*r3 + h2*r2 + h3*r1 + h4*r0
+ // d3 = h0*r3 + h1*r2 + h2*r1 + h3*r0 + h4*5*r4
+ // d2 = h0*r2 + h1*r1 + h2*r0 + h3*5*r4 + h4*5*r3
+ // d1 = h0*r1 + h1*r0 + h2*5*r4 + h3*5*r3 + h4*5*r2
+ // d0 = h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1
+
+ subs $len,$len,#64
+ umull $ACC4,$IN23_0,${R4}[2]
+ csel $in2,$zeros,$in2,lo
+ umull $ACC3,$IN23_0,${R3}[2]
+ umull $ACC2,$IN23_0,${R2}[2]
+ ldp x8,x12,[$in2],#16 // inp[2:3] (or zero)
+ umull $ACC1,$IN23_0,${R1}[2]
+ ldp x9,x13,[$in2],#48
+ umull $ACC0,$IN23_0,${R0}[2]
+#ifdef __ARMEB__
+ rev x8,x8
+ rev x12,x12
+ rev x9,x9
+ rev x13,x13
+#endif
+
+ umlal $ACC4,$IN23_1,${R3}[2]
+ and x4,x8,#0x03ffffff // base 2^64 -> base 2^26
+ umlal $ACC3,$IN23_1,${R2}[2]
+ and x5,x9,#0x03ffffff
+ umlal $ACC2,$IN23_1,${R1}[2]
+ ubfx x6,x8,#26,#26
+ umlal $ACC1,$IN23_1,${R0}[2]
+ ubfx x7,x9,#26,#26
+ umlal $ACC0,$IN23_1,${S4}[2]
+ add x4,x4,x5,lsl#32 // bfi x4,x5,#32,#32
+
+ umlal $ACC4,$IN23_2,${R2}[2]
+ extr x8,x12,x8,#52
+ umlal $ACC3,$IN23_2,${R1}[2]
+ extr x9,x13,x9,#52
+ umlal $ACC2,$IN23_2,${R0}[2]
+ add x6,x6,x7,lsl#32 // bfi x6,x7,#32,#32
+ umlal $ACC1,$IN23_2,${S4}[2]
+ fmov $IN23_0,x4
+ umlal $ACC0,$IN23_2,${S3}[2]
+ and x8,x8,#0x03ffffff
+
+ umlal $ACC4,$IN23_3,${R1}[2]
+ and x9,x9,#0x03ffffff
+ umlal $ACC3,$IN23_3,${R0}[2]
+ ubfx x10,x12,#14,#26
+ umlal $ACC2,$IN23_3,${S4}[2]
+ ubfx x11,x13,#14,#26
+ umlal $ACC1,$IN23_3,${S3}[2]
+ add x8,x8,x9,lsl#32 // bfi x8,x9,#32,#32
+ umlal $ACC0,$IN23_3,${S2}[2]
+ fmov $IN23_1,x6
+
+ add $IN01_2,$IN01_2,$H2
+ add x12,$padbit,x12,lsr#40
+ umlal $ACC4,$IN23_4,${R0}[2]
+ add x13,$padbit,x13,lsr#40
+ umlal $ACC3,$IN23_4,${S4}[2]
+ add x10,x10,x11,lsl#32 // bfi x10,x11,#32,#32
+ umlal $ACC2,$IN23_4,${S3}[2]
+ add x12,x12,x13,lsl#32 // bfi x12,x13,#32,#32
+ umlal $ACC1,$IN23_4,${S2}[2]
+ fmov $IN23_2,x8
+ umlal $ACC0,$IN23_4,${S1}[2]
+ fmov $IN23_3,x10
+
+ ////////////////////////////////////////////////////////////////
+ // (hash+inp[0:1])*r^4 and accumulate
+
+ add $IN01_0,$IN01_0,$H0
+ fmov $IN23_4,x12
+ umlal $ACC3,$IN01_2,${R1}[0]
+ ldp x8,x12,[$inp],#16 // inp[0:1]
+ umlal $ACC0,$IN01_2,${S3}[0]
+ ldp x9,x13,[$inp],#48
+ umlal $ACC4,$IN01_2,${R2}[0]
+ umlal $ACC1,$IN01_2,${S4}[0]
+ umlal $ACC2,$IN01_2,${R0}[0]
+#ifdef __ARMEB__
+ rev x8,x8
+ rev x12,x12
+ rev x9,x9
+ rev x13,x13
+#endif
+
+ add $IN01_1,$IN01_1,$H1
+ umlal $ACC3,$IN01_0,${R3}[0]
+ umlal $ACC4,$IN01_0,${R4}[0]
+ and x4,x8,#0x03ffffff // base 2^64 -> base 2^26
+ umlal $ACC2,$IN01_0,${R2}[0]
+ and x5,x9,#0x03ffffff
+ umlal $ACC0,$IN01_0,${R0}[0]
+ ubfx x6,x8,#26,#26
+ umlal $ACC1,$IN01_0,${R1}[0]
+ ubfx x7,x9,#26,#26
+
+ add $IN01_3,$IN01_3,$H3
+ add x4,x4,x5,lsl#32 // bfi x4,x5,#32,#32
+ umlal $ACC3,$IN01_1,${R2}[0]
+ extr x8,x12,x8,#52
+ umlal $ACC4,$IN01_1,${R3}[0]
+ extr x9,x13,x9,#52
+ umlal $ACC0,$IN01_1,${S4}[0]
+ add x6,x6,x7,lsl#32 // bfi x6,x7,#32,#32
+ umlal $ACC2,$IN01_1,${R1}[0]
+ fmov $IN01_0,x4
+ umlal $ACC1,$IN01_1,${R0}[0]
+ and x8,x8,#0x03ffffff
+
+ add $IN01_4,$IN01_4,$H4
+ and x9,x9,#0x03ffffff
+ umlal $ACC3,$IN01_3,${R0}[0]
+ ubfx x10,x12,#14,#26
+ umlal $ACC0,$IN01_3,${S2}[0]
+ ubfx x11,x13,#14,#26
+ umlal $ACC4,$IN01_3,${R1}[0]
+ add x8,x8,x9,lsl#32 // bfi x8,x9,#32,#32
+ umlal $ACC1,$IN01_3,${S3}[0]
+ fmov $IN01_1,x6
+ umlal $ACC2,$IN01_3,${S4}[0]
+ add x12,$padbit,x12,lsr#40
+
+ umlal $ACC3,$IN01_4,${S4}[0]
+ add x13,$padbit,x13,lsr#40
+ umlal $ACC0,$IN01_4,${S1}[0]
+ add x10,x10,x11,lsl#32 // bfi x10,x11,#32,#32
+ umlal $ACC4,$IN01_4,${R0}[0]
+ add x12,x12,x13,lsl#32 // bfi x12,x13,#32,#32
+ umlal $ACC1,$IN01_4,${S2}[0]
+ fmov $IN01_2,x8
+ umlal $ACC2,$IN01_4,${S3}[0]
+ fmov $IN01_3,x10
+
+ /////////////////////////////////////////////////////////////////
+ // lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
+ // and P. Schwabe
+
+ ushr $T0.2d,$ACC3,#26
+ fmov $IN01_4,x12
+ xtn $H3,$ACC3
+ ushr $T1.2d,$ACC0,#26
+ xtn $H0,$ACC0
+ add $ACC4,$ACC4,$T0.2d // h3 -> h4
+ bic $H3,#0xfc,lsl#24 // &=0x03ffffff
+ add $ACC1,$ACC1,$T1.2d // h0 -> h1
+ bic $H0,#0xfc,lsl#24
+
+ shrn $T0.2s,$ACC4,#26
+ xtn $H4,$ACC4
+ ushr $T1.2d,$ACC1,#26
+ xtn $H1,$ACC1
+ add $ACC2,$ACC2,$T1.2d // h1 -> h2
+ bic $H4,#0xfc,lsl#24
+ bic $H1,#0xfc,lsl#24
+
+ add $H0,$H0,$T0.2s
+ shl $T0.2s,$T0.2s,#2
+ shrn $T1.2s,$ACC2,#26
+ xtn $H2,$ACC2
+ add $H0,$H0,$T0.2s // h4 -> h0
+ add $H3,$H3,$T1.2s // h2 -> h3
+ bic $H2,#0xfc,lsl#24
+
+ ushr $T0.2s,$H0,#26
+ bic $H0,#0xfc,lsl#24
+ ushr $T1.2s,$H3,#26
+ bic $H3,#0xfc,lsl#24
+ add $H1,$H1,$T0.2s // h0 -> h1
+ add $H4,$H4,$T1.2s // h3 -> h4
+
+ b.hi .Loop_neon
+
+.Lskip_loop:
+ dup $IN23_2,${IN23_2}[0]
+ movi $MASK.2d,#-1
+ add $IN01_2,$IN01_2,$H2
+ ushr $MASK.2d,$MASK.2d,#38
+
+ ////////////////////////////////////////////////////////////////
+ // multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
+
+ adds $len,$len,#32
+ b.ne .Long_tail
+
+ dup $IN23_2,${IN01_2}[0]
+ add $IN23_0,$IN01_0,$H0
+ add $IN23_3,$IN01_3,$H3
+ add $IN23_1,$IN01_1,$H1
+ add $IN23_4,$IN01_4,$H4
+
+.Long_tail:
+ dup $IN23_0,${IN23_0}[0]
+ umull2 $ACC0,$IN23_2,${S3}
+ umull2 $ACC3,$IN23_2,${R1}
+ umull2 $ACC4,$IN23_2,${R2}
+ umull2 $ACC2,$IN23_2,${R0}
+ umull2 $ACC1,$IN23_2,${S4}
+
+ dup $IN23_1,${IN23_1}[0]
+ umlal2 $ACC0,$IN23_0,${R0}
+ umlal2 $ACC2,$IN23_0,${R2}
+ umlal2 $ACC3,$IN23_0,${R3}
+ umlal2 $ACC4,$IN23_0,${R4}
+ umlal2 $ACC1,$IN23_0,${R1}
+
+ dup $IN23_3,${IN23_3}[0]
+ umlal2 $ACC0,$IN23_1,${S4}
+ umlal2 $ACC3,$IN23_1,${R2}
+ umlal2 $ACC2,$IN23_1,${R1}
+ umlal2 $ACC4,$IN23_1,${R3}
+ umlal2 $ACC1,$IN23_1,${R0}
+
+ dup $IN23_4,${IN23_4}[0]
+ umlal2 $ACC3,$IN23_3,${R0}
+ umlal2 $ACC4,$IN23_3,${R1}
+ umlal2 $ACC0,$IN23_3,${S2}
+ umlal2 $ACC1,$IN23_3,${S3}
+ umlal2 $ACC2,$IN23_3,${S4}
+
+ umlal2 $ACC3,$IN23_4,${S4}
+ umlal2 $ACC0,$IN23_4,${S1}
+ umlal2 $ACC4,$IN23_4,${R0}
+ umlal2 $ACC1,$IN23_4,${S2}
+ umlal2 $ACC2,$IN23_4,${S3}
+
+ b.eq .Lshort_tail
+
+ ////////////////////////////////////////////////////////////////
+ // (hash+inp[0:1])*r^4:r^3 and accumulate
+
+ add $IN01_0,$IN01_0,$H0
+ umlal $ACC3,$IN01_2,${R1}
+ umlal $ACC0,$IN01_2,${S3}
+ umlal $ACC4,$IN01_2,${R2}
+ umlal $ACC1,$IN01_2,${S4}
+ umlal $ACC2,$IN01_2,${R0}
+
+ add $IN01_1,$IN01_1,$H1
+ umlal $ACC3,$IN01_0,${R3}
+ umlal $ACC0,$IN01_0,${R0}
+ umlal $ACC4,$IN01_0,${R4}
+ umlal $ACC1,$IN01_0,${R1}
+ umlal $ACC2,$IN01_0,${R2}
+
+ add $IN01_3,$IN01_3,$H3
+ umlal $ACC3,$IN01_1,${R2}
+ umlal $ACC0,$IN01_1,${S4}
+ umlal $ACC4,$IN01_1,${R3}
+ umlal $ACC1,$IN01_1,${R0}
+ umlal $ACC2,$IN01_1,${R1}
+
+ add $IN01_4,$IN01_4,$H4
+ umlal $ACC3,$IN01_3,${R0}
+ umlal $ACC0,$IN01_3,${S2}
+ umlal $ACC4,$IN01_3,${R1}
+ umlal $ACC1,$IN01_3,${S3}
+ umlal $ACC2,$IN01_3,${S4}
+
+ umlal $ACC3,$IN01_4,${S4}
+ umlal $ACC0,$IN01_4,${S1}
+ umlal $ACC4,$IN01_4,${R0}
+ umlal $ACC1,$IN01_4,${S2}
+ umlal $ACC2,$IN01_4,${S3}
+
+.Lshort_tail:
+ ////////////////////////////////////////////////////////////////
+ // horizontal add
+
+ addp $ACC3,$ACC3,$ACC3
+ ldp d8,d9,[sp,#16] // meet ABI requirements
+ addp $ACC0,$ACC0,$ACC0
+ ldp d10,d11,[sp,#32]
+ addp $ACC4,$ACC4,$ACC4
+ ldp d12,d13,[sp,#48]
+ addp $ACC1,$ACC1,$ACC1
+ ldp d14,d15,[sp,#64]
+ addp $ACC2,$ACC2,$ACC2
+
+ ////////////////////////////////////////////////////////////////
+ // lazy reduction, but without narrowing
+
+ ushr $T0.2d,$ACC3,#26
+ and $ACC3,$ACC3,$MASK.2d
+ ushr $T1.2d,$ACC0,#26
+ and $ACC0,$ACC0,$MASK.2d
+
+ add $ACC4,$ACC4,$T0.2d // h3 -> h4
+ add $ACC1,$ACC1,$T1.2d // h0 -> h1
+
+ ushr $T0.2d,$ACC4,#26
+ and $ACC4,$ACC4,$MASK.2d
+ ushr $T1.2d,$ACC1,#26
+ and $ACC1,$ACC1,$MASK.2d
+ add $ACC2,$ACC2,$T1.2d // h1 -> h2
+
+ add $ACC0,$ACC0,$T0.2d
+ shl $T0.2d,$T0.2d,#2
+ ushr $T1.2d,$ACC2,#26
+ and $ACC2,$ACC2,$MASK.2d
+ add $ACC0,$ACC0,$T0.2d // h4 -> h0
+ add $ACC3,$ACC3,$T1.2d // h2 -> h3
+
+ ushr $T0.2d,$ACC0,#26
+ and $ACC0,$ACC0,$MASK.2d
+ ushr $T1.2d,$ACC3,#26
+ and $ACC3,$ACC3,$MASK.2d
+ add $ACC1,$ACC1,$T0.2d // h0 -> h1
+ add $ACC4,$ACC4,$T1.2d // h3 -> h4
+
+ ////////////////////////////////////////////////////////////////
+ // write the result, can be partially reduced
+
+ st4 {$ACC0,$ACC1,$ACC2,$ACC3}[0],[$ctx],#16
+ st1 {$ACC4}[0],[$ctx]
+
+.Lno_data_neon:
+ ldr x29,[sp],#80
+ ret
+.size poly1305_blocks_neon,.-poly1305_blocks_neon
+
+.type poly1305_emit_neon,%function
+.align 5
+poly1305_emit_neon:
+ ldr $is_base2_26,[$ctx,#24]
+ cbz $is_base2_26,poly1305_emit
+
+ ldp w10,w11,[$ctx] // load hash value base 2^26
+ ldp w12,w13,[$ctx,#8]
+ ldr w14,[$ctx,#16]
+
+ add $h0,x10,x11,lsl#26 // base 2^26 -> base 2^64
+ lsr $h1,x12,#12
+ adds $h0,$h0,x12,lsl#52
+ add $h1,$h1,x13,lsl#14
+ adc $h1,$h1,xzr
+ lsr $h2,x14,#24
+ adds $h1,$h1,x14,lsl#40
+ adc $h2,$h2,xzr // can be partially reduced...
+
+ ldp $t0,$t1,[$nonce] // load nonce
+
+ and $d0,$h2,#-4 // ... so reduce
+ add $d0,$d0,$h2,lsr#2
+ and $h2,$h2,#3
+ adds $h0,$h0,$d0
+ adc $h1,$h1,xzr
+
+ adds $d0,$h0,#5 // compare to modulus
+ adcs $d1,$h1,xzr
+ adc $d2,$h2,xzr
+
+ tst $d2,#-4 // see if it's carried/borrowed
+
+ csel $h0,$h0,$d0,eq
+ csel $h1,$h1,$d1,eq
+
+#ifdef __ARMEB__
+ ror $t0,$t0,#32 // flip nonce words
+ ror $t1,$t1,#32
+#endif
+ adds $h0,$h0,$t0 // accumulate nonce
+ adc $h1,$h1,$t1
+#ifdef __ARMEB__
+ rev $h0,$h0 // flip output bytes
+ rev $h1,$h1
+#endif
+ stp $h0,$h1,[$mac] // write result
+
+ ret
+.size poly1305_emit_neon,.-poly1305_emit_neon
+
+.align 5
+.Lzeros:
+.long 0,0,0,0,0,0,0,0
+.LOPENSSL_armcap_P:
+#ifdef __ILP32__
+.long OPENSSL_armcap_P-.
+#else
+.quad OPENSSL_armcap_P-.
+#endif
+.asciz "Poly1305 for ARMv8, CRYPTOGAMS by <appro\@openssl.org>"
+.align 2
+___
+
+foreach (split("\n",$code)) {
+ s/\b(shrn\s+v[0-9]+)\.[24]d/$1.2s/ or
+ s/\b(fmov\s+)v([0-9]+)[^,]*,\s*x([0-9]+)/$1d$2,x$3/ or
+ (m/\bdup\b/ and (s/\.[24]s/.2d/g or 1)) or
+ (m/\b(eor|and)/ and (s/\.[248][sdh]/.16b/g or 1)) or
+ (m/\bum(ul|la)l\b/ and (s/\.4s/.2s/g or 1)) or
+ (m/\bum(ul|la)l2\b/ and (s/\.2s/.4s/g or 1)) or
+ (m/\bst[1-4]\s+{[^}]+}\[/ and (s/\.[24]d/.s/g or 1));
+
+ s/\.[124]([sd])\[/.$1\[/;
+
+ print $_,"\n";
+}
+close STDOUT;
diff --git a/crypto/poly1305/asm/poly1305-x86.pl b/crypto/poly1305/asm/poly1305-x86.pl
new file mode 100755
index 00000000..4ad2289e
--- /dev/null
+++ b/crypto/poly1305/asm/poly1305-x86.pl
@@ -0,0 +1,1788 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# This module implements Poly1305 hash for x86.
+#
+# April 2015
+#
+# Numbers are cycles per processed byte with poly1305_blocks alone,
+# measured with rdtsc at fixed clock frequency.
+#
+# IALU/gcc-3.4(*) SSE2(**) AVX2
+# Pentium 15.7/+80% -
+# PIII 6.21/+90% -
+# P4 19.8/+40% 3.24
+# Core 2 4.85/+90% 1.80
+# Westmere 4.58/+100% 1.43
+# Sandy Bridge 3.90/+100% 1.36
+# Haswell 3.88/+70% 1.18 0.72
+# Silvermont 11.0/+40% 4.80
+# VIA Nano 6.71/+90% 2.47
+# Sledgehammer 3.51/+180% 4.27
+# Bulldozer 4.53/+140% 1.31
+#
+# (*) gcc 4.8 for some reason generated worse code;
+# (**) besides SSE2 there are floating-point and AVX options; FP
+# is deemed unnecessary, because pre-SSE2 processor are too
+# old to care about, while it's not the fastest option on
+# SSE2-capable ones; AVX is omitted, because it doesn't give
+# a lot of improvement, 5-10% depending on processor;
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],"poly1305-x86.pl",$ARGV[$#ARGV] eq "386");
+
+$sse2=$avx=0;
+for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
+
+if ($sse2) {
+ &static_label("const_sse2");
+ &static_label("enter_blocks");
+ &static_label("enter_emit");
+ &external_label("OPENSSL_ia32cap_P");
+
+ # This may be set to 2, but valgrind can't do AVX2 on 32-bit. Without a
+ # way to verify test coverage, keep it disabled.
+ $avx = 0;
+}
+
+########################################################################
+# Layout of opaque area is following.
+#
+# unsigned __int32 h[5]; # current hash value base 2^32
+# unsigned __int32 pad; # is_base2_26 in vector context
+# unsigned __int32 r[4]; # key value base 2^32
+
+&align(64);
+&function_begin("poly1305_init");
+ &mov ("edi",&wparam(0)); # context
+ &mov ("esi",&wparam(1)); # key
+ &mov ("ebp",&wparam(2)); # function table
+
+ &xor ("eax","eax");
+ &mov (&DWP(4*0,"edi"),"eax"); # zero hash value
+ &mov (&DWP(4*1,"edi"),"eax");
+ &mov (&DWP(4*2,"edi"),"eax");
+ &mov (&DWP(4*3,"edi"),"eax");
+ &mov (&DWP(4*4,"edi"),"eax");
+ &mov (&DWP(4*5,"edi"),"eax"); # is_base2_26
+
+ &cmp ("esi",0);
+ &je (&label("nokey"));
+
+ if ($sse2) {
+ &call (&label("pic_point"));
+ &set_label("pic_point");
+ &blindpop("ebx");
+
+ &lea ("eax",&DWP("poly1305_blocks-".&label("pic_point"),"ebx"));
+ &lea ("edx",&DWP("poly1305_emit-".&label("pic_point"),"ebx"));
+
+ &picmeup("edi","OPENSSL_ia32cap_P","ebx",&label("pic_point"));
+ &mov ("ecx",&DWP(0,"edi"));
+ &and ("ecx",1<<26|1<<24);
+ &cmp ("ecx",1<<26|1<<24); # SSE2 and XMM?
+ &jne (&label("no_sse2"));
+
+ &lea ("eax",&DWP("_poly1305_blocks_sse2-".&label("pic_point"),"ebx"));
+ &lea ("edx",&DWP("_poly1305_emit_sse2-".&label("pic_point"),"ebx"));
+
+ if ($avx>1) {
+ &mov ("ecx",&DWP(8,"edi"));
+ &test ("ecx",1<<5); # AVX2?
+ &jz (&label("no_sse2"));
+
+ &lea ("eax",&DWP("_poly1305_blocks_avx2-".&label("pic_point"),"ebx"));
+ }
+ &set_label("no_sse2");
+ &mov ("edi",&wparam(0)); # reload context
+ &mov (&DWP(0,"ebp"),"eax"); # fill function table
+ &mov (&DWP(4,"ebp"),"edx");
+ }
+
+ &mov ("eax",&DWP(4*0,"esi")); # load input key
+ &mov ("ebx",&DWP(4*1,"esi"));
+ &mov ("ecx",&DWP(4*2,"esi"));
+ &mov ("edx",&DWP(4*3,"esi"));
+ &and ("eax",0x0fffffff);
+ &and ("ebx",0x0ffffffc);
+ &and ("ecx",0x0ffffffc);
+ &and ("edx",0x0ffffffc);
+ &mov (&DWP(4*6,"edi"),"eax");
+ &mov (&DWP(4*7,"edi"),"ebx");
+ &mov (&DWP(4*8,"edi"),"ecx");
+ &mov (&DWP(4*9,"edi"),"edx");
+
+ &mov ("eax",$sse2);
+&set_label("nokey");
+&function_end("poly1305_init");
+
+($h0,$h1,$h2,$h3,$h4,
+ $d0,$d1,$d2,$d3,
+ $r0,$r1,$r2,$r3,
+ $s1,$s2,$s3)=map(4*$_,(0..15));
+
+&function_begin("poly1305_blocks");
+ &mov ("edi",&wparam(0)); # ctx
+ &mov ("esi",&wparam(1)); # inp
+ &mov ("ecx",&wparam(2)); # len
+&set_label("enter_blocks");
+ &and ("ecx",-15);
+ &jz (&label("nodata"));
+
+ &stack_push(16);
+ &mov ("eax",&DWP(4*6,"edi")); # r0
+ &mov ("ebx",&DWP(4*7,"edi")); # r1
+ &lea ("ebp",&DWP(0,"esi","ecx")); # end of input
+ &mov ("ecx",&DWP(4*8,"edi")); # r2
+ &mov ("edx",&DWP(4*9,"edi")); # r3
+
+ &mov (&wparam(2),"ebp");
+ &mov ("ebp","esi");
+
+ &mov (&DWP($r0,"esp"),"eax"); # r0
+ &mov ("eax","ebx");
+ &shr ("eax",2);
+ &mov (&DWP($r1,"esp"),"ebx"); # r1
+ &add ("eax","ebx"); # s1
+ &mov ("ebx","ecx");
+ &shr ("ebx",2);
+ &mov (&DWP($r2,"esp"),"ecx"); # r2
+ &add ("ebx","ecx"); # s2
+ &mov ("ecx","edx");
+ &shr ("ecx",2);
+ &mov (&DWP($r3,"esp"),"edx"); # r3
+ &add ("ecx","edx"); # s3
+ &mov (&DWP($s1,"esp"),"eax"); # s1
+ &mov (&DWP($s2,"esp"),"ebx"); # s2
+ &mov (&DWP($s3,"esp"),"ecx"); # s3
+
+ &mov ("eax",&DWP(4*0,"edi")); # load hash value
+ &mov ("ebx",&DWP(4*1,"edi"));
+ &mov ("ecx",&DWP(4*2,"edi"));
+ &mov ("esi",&DWP(4*3,"edi"));
+ &mov ("edi",&DWP(4*4,"edi"));
+ &jmp (&label("loop"));
+
+&set_label("loop",32);
+ &add ("eax",&DWP(4*0,"ebp")); # accumulate input
+ &adc ("ebx",&DWP(4*1,"ebp"));
+ &adc ("ecx",&DWP(4*2,"ebp"));
+ &adc ("esi",&DWP(4*3,"ebp"));
+ &lea ("ebp",&DWP(4*4,"ebp"));
+ &adc ("edi",&wparam(3)); # padbit
+
+ &mov (&DWP($h0,"esp"),"eax"); # put aside hash[+inp]
+ &mov (&DWP($h3,"esp"),"esi");
+
+ &mul (&DWP($r0,"esp")); # h0*r0
+ &mov (&DWP($h4,"esp"),"edi");
+ &mov ("edi","eax");
+ &mov ("eax","ebx"); # h1
+ &mov ("esi","edx");
+ &mul (&DWP($s3,"esp")); # h1*s3
+ &add ("edi","eax");
+ &mov ("eax","ecx"); # h2
+ &adc ("esi","edx");
+ &mul (&DWP($s2,"esp")); # h2*s2
+ &add ("edi","eax");
+ &mov ("eax",&DWP($h3,"esp"));
+ &adc ("esi","edx");
+ &mul (&DWP($s1,"esp")); # h3*s1
+ &add ("edi","eax");
+ &mov ("eax",&DWP($h0,"esp"));
+ &adc ("esi","edx");
+
+ &mul (&DWP($r1,"esp")); # h0*r1
+ &mov (&DWP($d0,"esp"),"edi");
+ &xor ("edi","edi");
+ &add ("esi","eax");
+ &mov ("eax","ebx"); # h1
+ &adc ("edi","edx");
+ &mul (&DWP($r0,"esp")); # h1*r0
+ &add ("esi","eax");
+ &mov ("eax","ecx"); # h2
+ &adc ("edi","edx");
+ &mul (&DWP($s3,"esp")); # h2*s3
+ &add ("esi","eax");
+ &mov ("eax",&DWP($h3,"esp"));
+ &adc ("edi","edx");
+ &mul (&DWP($s2,"esp")); # h3*s2
+ &add ("esi","eax");
+ &mov ("eax",&DWP($h4,"esp"));
+ &adc ("edi","edx");
+ &imul ("eax",&DWP($s1,"esp")); # h4*s1
+ &add ("esi","eax");
+ &mov ("eax",&DWP($h0,"esp"));
+ &adc ("edi",0);
+
+ &mul (&DWP($r2,"esp")); # h0*r2
+ &mov (&DWP($d1,"esp"),"esi");
+ &xor ("esi","esi");
+ &add ("edi","eax");
+ &mov ("eax","ebx"); # h1
+ &adc ("esi","edx");
+ &mul (&DWP($r1,"esp")); # h1*r1
+ &add ("edi","eax");
+ &mov ("eax","ecx"); # h2
+ &adc ("esi","edx");
+ &mul (&DWP($r0,"esp")); # h2*r0
+ &add ("edi","eax");
+ &mov ("eax",&DWP($h3,"esp"));
+ &adc ("esi","edx");
+ &mul (&DWP($s3,"esp")); # h3*s3
+ &add ("edi","eax");
+ &mov ("eax",&DWP($h4,"esp"));
+ &adc ("esi","edx");
+ &imul ("eax",&DWP($s2,"esp")); # h4*s2
+ &add ("edi","eax");
+ &mov ("eax",&DWP($h0,"esp"));
+ &adc ("esi",0);
+
+ &mul (&DWP($r3,"esp")); # h0*r3
+ &mov (&DWP($d2,"esp"),"edi");
+ &xor ("edi","edi");
+ &add ("esi","eax");
+ &mov ("eax","ebx"); # h1
+ &adc ("edi","edx");
+ &mul (&DWP($r2,"esp")); # h1*r2
+ &add ("esi","eax");
+ &mov ("eax","ecx"); # h2
+ &adc ("edi","edx");
+ &mul (&DWP($r1,"esp")); # h2*r1
+ &add ("esi","eax");
+ &mov ("eax",&DWP($h3,"esp"));
+ &adc ("edi","edx");
+ &mul (&DWP($r0,"esp")); # h3*r0
+ &add ("esi","eax");
+ &mov ("ecx",&DWP($h4,"esp"));
+ &adc ("edi","edx");
+
+ &mov ("edx","ecx");
+ &imul ("ecx",&DWP($s3,"esp")); # h4*s3
+ &add ("esi","ecx");
+ &mov ("eax",&DWP($d0,"esp"));
+ &adc ("edi",0);
+
+ &imul ("edx",&DWP($r0,"esp")); # h4*r0
+ &add ("edx","edi");
+
+ &mov ("ebx",&DWP($d1,"esp"));
+ &mov ("ecx",&DWP($d2,"esp"));
+
+ &mov ("edi","edx"); # last reduction step
+ &shr ("edx",2);
+ &and ("edi",3);
+ &lea ("edx",&DWP(0,"edx","edx",4)); # *5
+ &add ("eax","edx");
+ &adc ("ebx",0);
+ &adc ("ecx",0);
+ &adc ("esi",0);
+
+ &cmp ("ebp",&wparam(2)); # done yet?
+ &jne (&label("loop"));
+
+ &mov ("edx",&wparam(0)); # ctx
+ &stack_pop(16);
+ &mov (&DWP(4*0,"edx"),"eax"); # store hash value
+ &mov (&DWP(4*1,"edx"),"ebx");
+ &mov (&DWP(4*2,"edx"),"ecx");
+ &mov (&DWP(4*3,"edx"),"esi");
+ &mov (&DWP(4*4,"edx"),"edi");
+&set_label("nodata");
+&function_end("poly1305_blocks");
+
+&function_begin("poly1305_emit");
+ &mov ("ebp",&wparam(0)); # context
+&set_label("enter_emit");
+ &mov ("edi",&wparam(1)); # output
+ &mov ("eax",&DWP(4*0,"ebp")); # load hash value
+ &mov ("ebx",&DWP(4*1,"ebp"));
+ &mov ("ecx",&DWP(4*2,"ebp"));
+ &mov ("edx",&DWP(4*3,"ebp"));
+ &mov ("esi",&DWP(4*4,"ebp"));
+
+ &add ("eax",5); # compare to modulus
+ &adc ("ebx",0);
+ &adc ("ecx",0);
+ &adc ("edx",0);
+ &adc ("esi",0);
+ &shr ("esi",2); # did it carry/borrow?
+ &neg ("esi"); # do we choose hash-modulus?
+
+ &and ("eax","esi");
+ &and ("ebx","esi");
+ &and ("ecx","esi");
+ &and ("edx","esi");
+ &mov (&DWP(4*0,"edi"),"eax");
+ &mov (&DWP(4*1,"edi"),"ebx");
+ &mov (&DWP(4*2,"edi"),"ecx");
+ &mov (&DWP(4*3,"edi"),"edx");
+
+ &not ("esi"); # or original hash value?
+ &mov ("eax",&DWP(4*0,"ebp"));
+ &mov ("ebx",&DWP(4*1,"ebp"));
+ &mov ("ecx",&DWP(4*2,"ebp"));
+ &mov ("edx",&DWP(4*3,"ebp"));
+ &mov ("ebp",&wparam(2));
+ &and ("eax","esi");
+ &and ("ebx","esi");
+ &and ("ecx","esi");
+ &and ("edx","esi");
+ &or ("eax",&DWP(4*0,"edi"));
+ &or ("ebx",&DWP(4*1,"edi"));
+ &or ("ecx",&DWP(4*2,"edi"));
+ &or ("edx",&DWP(4*3,"edi"));
+
+ &add ("eax",&DWP(4*0,"ebp")); # accumulate key
+ &adc ("ebx",&DWP(4*1,"ebp"));
+ &adc ("ecx",&DWP(4*2,"ebp"));
+ &adc ("edx",&DWP(4*3,"ebp"));
+
+ &mov (&DWP(4*0,"edi"),"eax");
+ &mov (&DWP(4*1,"edi"),"ebx");
+ &mov (&DWP(4*2,"edi"),"ecx");
+ &mov (&DWP(4*3,"edi"),"edx");
+&function_end("poly1305_emit");
+
+if ($sse2) {
+########################################################################
+# Layout of opaque area is following.
+#
+# unsigned __int32 h[5]; # current hash value base 2^26
+# unsigned __int32 is_base2_26;
+# unsigned __int32 r[4]; # key value base 2^32
+# unsigned __int32 pad[2];
+# struct { unsigned __int32 r^4, r^3, r^2, r^1; } r[9];
+#
+# where r^n are base 2^26 digits of degrees of multiplier key. There are
+# 5 digits, but last four are interleaved with multiples of 5, totalling
+# in 9 elements: r0, r1, 5*r1, r2, 5*r2, r3, 5*r3, r4, 5*r4.
+
+my ($D0,$D1,$D2,$D3,$D4,$T0,$T1,$T2)=map("xmm$_",(0..7));
+my $MASK=$T2; # borrow and keep in mind
+
+&align (32);
+&function_begin_B("_poly1305_init_sse2");
+ &movdqu ($D4,&QWP(4*6,"edi")); # key base 2^32
+ &lea ("edi",&DWP(16*3,"edi")); # size optimization
+ &mov ("ebp","esp");
+ &sub ("esp",16*(9+5));
+ &and ("esp",-16);
+
+ #&pand ($D4,&QWP(96,"ebx")); # magic mask
+ &movq ($MASK,&QWP(64,"ebx"));
+
+ &movdqa ($D0,$D4);
+ &movdqa ($D1,$D4);
+ &movdqa ($D2,$D4);
+
+ &pand ($D0,$MASK); # -> base 2^26
+ &psrlq ($D1,26);
+ &psrldq ($D2,6);
+ &pand ($D1,$MASK);
+ &movdqa ($D3,$D2);
+ &psrlq ($D2,4)
+ &psrlq ($D3,30);
+ &pand ($D2,$MASK);
+ &pand ($D3,$MASK);
+ &psrldq ($D4,13);
+
+ &lea ("edx",&DWP(16*9,"esp")); # size optimization
+ &mov ("ecx",2);
+&set_label("square");
+ &movdqa (&QWP(16*0,"esp"),$D0);
+ &movdqa (&QWP(16*1,"esp"),$D1);
+ &movdqa (&QWP(16*2,"esp"),$D2);
+ &movdqa (&QWP(16*3,"esp"),$D3);
+ &movdqa (&QWP(16*4,"esp"),$D4);
+
+ &movdqa ($T1,$D1);
+ &movdqa ($T0,$D2);
+ &pslld ($T1,2);
+ &pslld ($T0,2);
+ &paddd ($T1,$D1); # *5
+ &paddd ($T0,$D2); # *5
+ &movdqa (&QWP(16*5,"esp"),$T1);
+ &movdqa (&QWP(16*6,"esp"),$T0);
+ &movdqa ($T1,$D3);
+ &movdqa ($T0,$D4);
+ &pslld ($T1,2);
+ &pslld ($T0,2);
+ &paddd ($T1,$D3); # *5
+ &paddd ($T0,$D4); # *5
+ &movdqa (&QWP(16*7,"esp"),$T1);
+ &movdqa (&QWP(16*8,"esp"),$T0);
+
+ &pshufd ($T1,$D0,0b01000100);
+ &movdqa ($T0,$D1);
+ &pshufd ($D1,$D1,0b01000100);
+ &pshufd ($D2,$D2,0b01000100);
+ &pshufd ($D3,$D3,0b01000100);
+ &pshufd ($D4,$D4,0b01000100);
+ &movdqa (&QWP(16*0,"edx"),$T1);
+ &movdqa (&QWP(16*1,"edx"),$D1);
+ &movdqa (&QWP(16*2,"edx"),$D2);
+ &movdqa (&QWP(16*3,"edx"),$D3);
+ &movdqa (&QWP(16*4,"edx"),$D4);
+
+ ################################################################
+ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4
+ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4
+ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4
+ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4
+ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
+
+ &pmuludq ($D4,$D0); # h4*r0
+ &pmuludq ($D3,$D0); # h3*r0
+ &pmuludq ($D2,$D0); # h2*r0
+ &pmuludq ($D1,$D0); # h1*r0
+ &pmuludq ($D0,$T1); # h0*r0
+
+sub pmuladd {
+my $load = shift;
+my $base = shift; $base = "esp" if (!defined($base));
+
+ ################################################################
+ # As for choice to "rotate" $T0-$T2 in order to move paddq
+ # past next multiplication. While it makes code harder to read
+ # and doesn't have significant effect on most processors, it
+ # makes a lot of difference on Atom, up to 30% improvement.
+
+ &movdqa ($T1,$T0);
+ &pmuludq ($T0,&QWP(16*3,$base)); # r1*h3
+ &movdqa ($T2,$T1);
+ &pmuludq ($T1,&QWP(16*2,$base)); # r1*h2
+ &paddq ($D4,$T0);
+ &movdqa ($T0,$T2);
+ &pmuludq ($T2,&QWP(16*1,$base)); # r1*h1
+ &paddq ($D3,$T1);
+ &$load ($T1,5); # s1
+ &pmuludq ($T0,&QWP(16*0,$base)); # r1*h0
+ &paddq ($D2,$T2);
+ &pmuludq ($T1,&QWP(16*4,$base)); # s1*h4
+ &$load ($T2,2); # r2^n
+ &paddq ($D1,$T0);
+
+ &movdqa ($T0,$T2);
+ &pmuludq ($T2,&QWP(16*2,$base)); # r2*h2
+ &paddq ($D0,$T1);
+ &movdqa ($T1,$T0);
+ &pmuludq ($T0,&QWP(16*1,$base)); # r2*h1
+ &paddq ($D4,$T2);
+ &$load ($T2,6); # s2^n
+ &pmuludq ($T1,&QWP(16*0,$base)); # r2*h0
+ &paddq ($D3,$T0);
+ &movdqa ($T0,$T2);
+ &pmuludq ($T2,&QWP(16*4,$base)); # s2*h4
+ &paddq ($D2,$T1);
+ &pmuludq ($T0,&QWP(16*3,$base)); # s2*h3
+ &$load ($T1,3); # r3^n
+ &paddq ($D1,$T2);
+
+ &movdqa ($T2,$T1);
+ &pmuludq ($T1,&QWP(16*1,$base)); # r3*h1
+ &paddq ($D0,$T0);
+ &$load ($T0,7); # s3^n
+ &pmuludq ($T2,&QWP(16*0,$base)); # r3*h0
+ &paddq ($D4,$T1);
+ &movdqa ($T1,$T0);
+ &pmuludq ($T0,&QWP(16*4,$base)); # s3*h4
+ &paddq ($D3,$T2);
+ &movdqa ($T2,$T1);
+ &pmuludq ($T1,&QWP(16*3,$base)); # s3*h3
+ &paddq ($D2,$T0);
+ &pmuludq ($T2,&QWP(16*2,$base)); # s3*h2
+ &$load ($T0,4); # r4^n
+ &paddq ($D1,$T1);
+
+ &$load ($T1,8); # s4^n
+ &pmuludq ($T0,&QWP(16*0,$base)); # r4*h0
+ &paddq ($D0,$T2);
+ &movdqa ($T2,$T1);
+ &pmuludq ($T1,&QWP(16*4,$base)); # s4*h4
+ &paddq ($D4,$T0);
+ &movdqa ($T0,$T2);
+ &pmuludq ($T2,&QWP(16*1,$base)); # s4*h1
+ &paddq ($D3,$T1);
+ &movdqa ($T1,$T0);
+ &pmuludq ($T0,&QWP(16*2,$base)); # s4*h2
+ &paddq ($D0,$T2);
+ &pmuludq ($T1,&QWP(16*3,$base)); # s4*h3
+ &movdqa ($MASK,&QWP(64,"ebx"));
+ &paddq ($D1,$T0);
+ &paddq ($D2,$T1);
+}
+ &pmuladd (sub { my ($reg,$i)=@_;
+ &movdqa ($reg,&QWP(16*$i,"esp"));
+ },"edx");
+
+sub lazy_reduction {
+my $extra = shift;
+my $paddx = defined($extra) ? paddq : paddd;
+
+ ################################################################
+ # lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
+ # and P. Schwabe
+
+ &movdqa ($T0,$D3);
+ &pand ($D3,$MASK);
+ &psrlq ($T0,26);
+ &$extra () if (defined($extra));
+ &paddq ($T0,$D4); # h3 -> h4
+ &movdqa ($T1,$D0);
+ &pand ($D0,$MASK);
+ &psrlq ($T1,26);
+ &movdqa ($D4,$T0);
+ &paddq ($T1,$D1); # h0 -> h1
+ &psrlq ($T0,26);
+ &pand ($D4,$MASK);
+ &movdqa ($D1,$T1);
+ &psrlq ($T1,26);
+ &paddd ($D0,$T0); # favour paddd when
+ # possible, because
+ # paddq is "broken"
+ # on Atom
+ &psllq ($T0,2);
+ &paddq ($T1,$D2); # h1 -> h2
+ &$paddx ($T0,$D0); # h4 -> h0
+ &pand ($D1,$MASK);
+ &movdqa ($D2,$T1);
+ &psrlq ($T1,26);
+ &pand ($D2,$MASK);
+ &paddd ($T1,$D3); # h2 -> h3
+ &movdqa ($D0,$T0);
+ &psrlq ($T0,26);
+ &movdqa ($D3,$T1);
+ &psrlq ($T1,26);
+ &pand ($D0,$MASK);
+ &paddd ($D1,$T0); # h0 -> h1
+ &pand ($D3,$MASK);
+ &paddd ($D4,$T1); # h3 -> h4
+}
+ &lazy_reduction ();
+
+ &dec ("ecx");
+ &jz (&label("square_break"));
+
+ &punpcklqdq ($D0,&QWP(16*0,"esp")); # 0:r^1:0:r^2
+ &punpcklqdq ($D1,&QWP(16*1,"esp"));
+ &punpcklqdq ($D2,&QWP(16*2,"esp"));
+ &punpcklqdq ($D3,&QWP(16*3,"esp"));
+ &punpcklqdq ($D4,&QWP(16*4,"esp"));
+ &jmp (&label("square"));
+
+&set_label("square_break");
+ &psllq ($D0,32); # -> r^3:0:r^4:0
+ &psllq ($D1,32);
+ &psllq ($D2,32);
+ &psllq ($D3,32);
+ &psllq ($D4,32);
+ &por ($D0,&QWP(16*0,"esp")); # r^3:r^1:r^4:r^2
+ &por ($D1,&QWP(16*1,"esp"));
+ &por ($D2,&QWP(16*2,"esp"));
+ &por ($D3,&QWP(16*3,"esp"));
+ &por ($D4,&QWP(16*4,"esp"));
+
+ &pshufd ($D0,$D0,0b10001101); # -> r^1:r^2:r^3:r^4
+ &pshufd ($D1,$D1,0b10001101);
+ &pshufd ($D2,$D2,0b10001101);
+ &pshufd ($D3,$D3,0b10001101);
+ &pshufd ($D4,$D4,0b10001101);
+
+ &movdqu (&QWP(16*0,"edi"),$D0); # save the table
+ &movdqu (&QWP(16*1,"edi"),$D1);
+ &movdqu (&QWP(16*2,"edi"),$D2);
+ &movdqu (&QWP(16*3,"edi"),$D3);
+ &movdqu (&QWP(16*4,"edi"),$D4);
+
+ &movdqa ($T1,$D1);
+ &movdqa ($T0,$D2);
+ &pslld ($T1,2);
+ &pslld ($T0,2);
+ &paddd ($T1,$D1); # *5
+ &paddd ($T0,$D2); # *5
+ &movdqu (&QWP(16*5,"edi"),$T1);
+ &movdqu (&QWP(16*6,"edi"),$T0);
+ &movdqa ($T1,$D3);
+ &movdqa ($T0,$D4);
+ &pslld ($T1,2);
+ &pslld ($T0,2);
+ &paddd ($T1,$D3); # *5
+ &paddd ($T0,$D4); # *5
+ &movdqu (&QWP(16*7,"edi"),$T1);
+ &movdqu (&QWP(16*8,"edi"),$T0);
+
+ &mov ("esp","ebp");
+ &lea ("edi",&DWP(-16*3,"edi")); # size de-optimization
+ &ret ();
+&function_end_B("_poly1305_init_sse2");
+
+&align (32);
+&function_begin("_poly1305_blocks_sse2");
+ &mov ("edi",&wparam(0)); # ctx
+ &mov ("esi",&wparam(1)); # inp
+ &mov ("ecx",&wparam(2)); # len
+
+ &mov ("eax",&DWP(4*5,"edi")); # is_base2_26
+ &and ("ecx",-16);
+ &jz (&label("nodata"));
+ &cmp ("ecx",64);
+ &jae (&label("enter_sse2"));
+ &test ("eax","eax"); # is_base2_26?
+ &jz (&label("enter_blocks"));
+
+&set_label("enter_sse2",16);
+ &call (&label("pic_point"));
+&set_label("pic_point");
+ &blindpop("ebx");
+ &lea ("ebx",&DWP(&label("const_sse2")."-".&label("pic_point"),"ebx"));
+
+ &test ("eax","eax"); # is_base2_26?
+ &jnz (&label("base2_26"));
+
+ &call ("_poly1305_init_sse2");
+
+ ################################################# base 2^32 -> base 2^26
+ &mov ("eax",&DWP(0,"edi"));
+ &mov ("ecx",&DWP(3,"edi"));
+ &mov ("edx",&DWP(6,"edi"));
+ &mov ("esi",&DWP(9,"edi"));
+ &mov ("ebp",&DWP(13,"edi"));
+ &mov (&DWP(4*5,"edi"),1); # is_base2_26
+
+ &shr ("ecx",2);
+ &and ("eax",0x3ffffff);
+ &shr ("edx",4);
+ &and ("ecx",0x3ffffff);
+ &shr ("esi",6);
+ &and ("edx",0x3ffffff);
+
+ &movd ($D0,"eax");
+ &movd ($D1,"ecx");
+ &movd ($D2,"edx");
+ &movd ($D3,"esi");
+ &movd ($D4,"ebp");
+
+ &mov ("esi",&wparam(1)); # [reload] inp
+ &mov ("ecx",&wparam(2)); # [reload] len
+ &jmp (&label("base2_32"));
+
+&set_label("base2_26",16);
+ &movd ($D0,&DWP(4*0,"edi")); # load hash value
+ &movd ($D1,&DWP(4*1,"edi"));
+ &movd ($D2,&DWP(4*2,"edi"));
+ &movd ($D3,&DWP(4*3,"edi"));
+ &movd ($D4,&DWP(4*4,"edi"));
+ &movdqa ($MASK,&QWP(64,"ebx"));
+
+&set_label("base2_32");
+ &mov ("eax",&wparam(3)); # padbit
+ &mov ("ebp","esp");
+
+ &sub ("esp",16*(5+5+5+9+9));
+ &and ("esp",-16);
+
+ &lea ("edi",&DWP(16*3,"edi")); # size optimization
+ &shl ("eax",24); # padbit
+
+ &test ("ecx",31);
+ &jz (&label("even"));
+
+ ################################################################
+ # process single block, with SSE2, because it's still faster
+ # even though half of result is discarded
+
+ &movdqu ($T1,&QWP(0,"esi")); # input
+ &lea ("esi",&DWP(16,"esi"));
+
+ &movdqa ($T0,$T1); # -> base 2^26 ...
+ &pand ($T1,$MASK);
+ &paddd ($D0,$T1); # ... and accumuate
+
+ &movdqa ($T1,$T0);
+ &psrlq ($T0,26);
+ &psrldq ($T1,6);
+ &pand ($T0,$MASK);
+ &paddd ($D1,$T0);
+
+ &movdqa ($T0,$T1);
+ &psrlq ($T1,4);
+ &pand ($T1,$MASK);
+ &paddd ($D2,$T1);
+
+ &movdqa ($T1,$T0);
+ &psrlq ($T0,30);
+ &pand ($T0,$MASK);
+ &psrldq ($T1,7);
+ &paddd ($D3,$T0);
+
+ &movd ($T0,"eax"); # padbit
+ &paddd ($D4,$T1);
+ &movd ($T1,&DWP(16*0+12,"edi")); # r0
+ &paddd ($D4,$T0);
+
+ &movdqa (&QWP(16*0,"esp"),$D0);
+ &movdqa (&QWP(16*1,"esp"),$D1);
+ &movdqa (&QWP(16*2,"esp"),$D2);
+ &movdqa (&QWP(16*3,"esp"),$D3);
+ &movdqa (&QWP(16*4,"esp"),$D4);
+
+ ################################################################
+ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4
+ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4
+ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4
+ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4
+ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
+
+ &pmuludq ($D0,$T1); # h4*r0
+ &pmuludq ($D1,$T1); # h3*r0
+ &pmuludq ($D2,$T1); # h2*r0
+ &movd ($T0,&DWP(16*1+12,"edi")); # r1
+ &pmuludq ($D3,$T1); # h1*r0
+ &pmuludq ($D4,$T1); # h0*r0
+
+ &pmuladd (sub { my ($reg,$i)=@_;
+ &movd ($reg,&DWP(16*$i+12,"edi"));
+ });
+
+ &lazy_reduction ();
+
+ &sub ("ecx",16);
+ &jz (&label("done"));
+
+&set_label("even");
+ &lea ("edx",&DWP(16*(5+5+5+9),"esp"));# size optimization
+ &lea ("eax",&DWP(-16*2,"esi"));
+ &sub ("ecx",64);
+
+ ################################################################
+ # expand and copy pre-calculated table to stack
+
+ &movdqu ($T0,&QWP(16*0,"edi")); # r^1:r^2:r^3:r^4
+ &pshufd ($T1,$T0,0b01000100); # duplicate r^3:r^4
+ &cmovb ("esi","eax");
+ &pshufd ($T0,$T0,0b11101110); # duplicate r^1:r^2
+ &movdqa (&QWP(16*0,"edx"),$T1);
+ &lea ("eax",&DWP(16*10,"esp"));
+ &movdqu ($T1,&QWP(16*1,"edi"));
+ &movdqa (&QWP(16*(0-9),"edx"),$T0);
+ &pshufd ($T0,$T1,0b01000100);
+ &pshufd ($T1,$T1,0b11101110);
+ &movdqa (&QWP(16*1,"edx"),$T0);
+ &movdqu ($T0,&QWP(16*2,"edi"));
+ &movdqa (&QWP(16*(1-9),"edx"),$T1);
+ &pshufd ($T1,$T0,0b01000100);
+ &pshufd ($T0,$T0,0b11101110);
+ &movdqa (&QWP(16*2,"edx"),$T1);
+ &movdqu ($T1,&QWP(16*3,"edi"));
+ &movdqa (&QWP(16*(2-9),"edx"),$T0);
+ &pshufd ($T0,$T1,0b01000100);
+ &pshufd ($T1,$T1,0b11101110);
+ &movdqa (&QWP(16*3,"edx"),$T0);
+ &movdqu ($T0,&QWP(16*4,"edi"));
+ &movdqa (&QWP(16*(3-9),"edx"),$T1);
+ &pshufd ($T1,$T0,0b01000100);
+ &pshufd ($T0,$T0,0b11101110);
+ &movdqa (&QWP(16*4,"edx"),$T1);
+ &movdqu ($T1,&QWP(16*5,"edi"));
+ &movdqa (&QWP(16*(4-9),"edx"),$T0);
+ &pshufd ($T0,$T1,0b01000100);
+ &pshufd ($T1,$T1,0b11101110);
+ &movdqa (&QWP(16*5,"edx"),$T0);
+ &movdqu ($T0,&QWP(16*6,"edi"));
+ &movdqa (&QWP(16*(5-9),"edx"),$T1);
+ &pshufd ($T1,$T0,0b01000100);
+ &pshufd ($T0,$T0,0b11101110);
+ &movdqa (&QWP(16*6,"edx"),$T1);
+ &movdqu ($T1,&QWP(16*7,"edi"));
+ &movdqa (&QWP(16*(6-9),"edx"),$T0);
+ &pshufd ($T0,$T1,0b01000100);
+ &pshufd ($T1,$T1,0b11101110);
+ &movdqa (&QWP(16*7,"edx"),$T0);
+ &movdqu ($T0,&QWP(16*8,"edi"));
+ &movdqa (&QWP(16*(7-9),"edx"),$T1);
+ &pshufd ($T1,$T0,0b01000100);
+ &pshufd ($T0,$T0,0b11101110);
+ &movdqa (&QWP(16*8,"edx"),$T1);
+ &movdqa (&QWP(16*(8-9),"edx"),$T0);
+
+sub load_input {
+my ($inpbase,$offbase)=@_;
+
+ &movdqu ($T0,&QWP($inpbase+0,"esi")); # load input
+ &movdqu ($T1,&QWP($inpbase+16,"esi"));
+ &lea ("esi",&DWP(16*2,"esi"));
+
+ &movdqa (&QWP($offbase+16*2,"esp"),$D2);
+ &movdqa (&QWP($offbase+16*3,"esp"),$D3);
+ &movdqa (&QWP($offbase+16*4,"esp"),$D4);
+
+ &movdqa ($D2,$T0); # splat input
+ &movdqa ($D3,$T1);
+ &psrldq ($D2,6);
+ &psrldq ($D3,6);
+ &movdqa ($D4,$T0);
+ &punpcklqdq ($D2,$D3); # 2:3
+ &punpckhqdq ($D4,$T1); # 4
+ &punpcklqdq ($T0,$T1); # 0:1
+
+ &movdqa ($D3,$D2);
+ &psrlq ($D2,4);
+ &psrlq ($D3,30);
+ &movdqa ($T1,$T0);
+ &psrlq ($D4,40); # 4
+ &psrlq ($T1,26);
+ &pand ($T0,$MASK); # 0
+ &pand ($T1,$MASK); # 1
+ &pand ($D2,$MASK); # 2
+ &pand ($D3,$MASK); # 3
+ &por ($D4,&QWP(0,"ebx")); # padbit, yes, always
+
+ &movdqa (&QWP($offbase+16*0,"esp"),$D0) if ($offbase);
+ &movdqa (&QWP($offbase+16*1,"esp"),$D1) if ($offbase);
+}
+ &load_input (16*2,16*5);
+
+ &jbe (&label("skip_loop"));
+ &jmp (&label("loop"));
+
+&set_label("loop",32);
+ ################################################################
+ # ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
+ # ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
+ # \___________________/
+ # ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
+ # ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
+ # \___________________/ \____________________/
+ ################################################################
+
+ &movdqa ($T2,&QWP(16*(0-9),"edx")); # r0^2
+ &movdqa (&QWP(16*1,"eax"),$T1);
+ &movdqa (&QWP(16*2,"eax"),$D2);
+ &movdqa (&QWP(16*3,"eax"),$D3);
+ &movdqa (&QWP(16*4,"eax"),$D4);
+
+ ################################################################
+ # d4 = h4*r0 + h0*r4 + h1*r3 + h2*r2 + h3*r1
+ # d3 = h3*r0 + h0*r3 + h1*r2 + h2*r1 + h4*5*r4
+ # d2 = h2*r0 + h0*r2 + h1*r1 + h3*5*r4 + h4*5*r3
+ # d1 = h1*r0 + h0*r1 + h2*5*r4 + h3*5*r3 + h4*5*r2
+ # d0 = h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1
+
+ &movdqa ($D1,$T0);
+ &pmuludq ($T0,$T2); # h0*r0
+ &movdqa ($D0,$T1);
+ &pmuludq ($T1,$T2); # h1*r0
+ &pmuludq ($D2,$T2); # h2*r0
+ &pmuludq ($D3,$T2); # h3*r0
+ &pmuludq ($D4,$T2); # h4*r0
+
+sub pmuladd_alt {
+my $addr = shift;
+
+ &pmuludq ($D0,&$addr(8)); # h1*s4
+ &movdqa ($T2,$D1);
+ &pmuludq ($D1,&$addr(1)); # h0*r1
+ &paddq ($D0,$T0);
+ &movdqa ($T0,$T2);
+ &pmuludq ($T2,&$addr(2)); # h0*r2
+ &paddq ($D1,$T1);
+ &movdqa ($T1,$T0);
+ &pmuludq ($T0,&$addr(3)); # h0*r3
+ &paddq ($D2,$T2);
+ &movdqa ($T2,&QWP(16*1,"eax")); # pull h1
+ &pmuludq ($T1,&$addr(4)); # h0*r4
+ &paddq ($D3,$T0);
+
+ &movdqa ($T0,$T2);
+ &pmuludq ($T2,&$addr(1)); # h1*r1
+ &paddq ($D4,$T1);
+ &movdqa ($T1,$T0);
+ &pmuludq ($T0,&$addr(2)); # h1*r2
+ &paddq ($D2,$T2);
+ &movdqa ($T2,&QWP(16*2,"eax")); # pull h2
+ &pmuludq ($T1,&$addr(3)); # h1*r3
+ &paddq ($D3,$T0);
+ &movdqa ($T0,$T2);
+ &pmuludq ($T2,&$addr(7)); # h2*s3
+ &paddq ($D4,$T1);
+ &movdqa ($T1,$T0);
+ &pmuludq ($T0,&$addr(8)); # h2*s4
+ &paddq ($D0,$T2);
+
+ &movdqa ($T2,$T1);
+ &pmuludq ($T1,&$addr(1)); # h2*r1
+ &paddq ($D1,$T0);
+ &movdqa ($T0,&QWP(16*3,"eax")); # pull h3
+ &pmuludq ($T2,&$addr(2)); # h2*r2
+ &paddq ($D3,$T1);
+ &movdqa ($T1,$T0);
+ &pmuludq ($T0,&$addr(6)); # h3*s2
+ &paddq ($D4,$T2);
+ &movdqa ($T2,$T1);
+ &pmuludq ($T1,&$addr(7)); # h3*s3
+ &paddq ($D0,$T0);
+ &movdqa ($T0,$T2);
+ &pmuludq ($T2,&$addr(8)); # h3*s4
+ &paddq ($D1,$T1);
+
+ &movdqa ($T1,&QWP(16*4,"eax")); # pull h4
+ &pmuludq ($T0,&$addr(1)); # h3*r1
+ &paddq ($D2,$T2);
+ &movdqa ($T2,$T1);
+ &pmuludq ($T1,&$addr(8)); # h4*s4
+ &paddq ($D4,$T0);
+ &movdqa ($T0,$T2);
+ &pmuludq ($T2,&$addr(5)); # h4*s1
+ &paddq ($D3,$T1);
+ &movdqa ($T1,$T0);
+ &pmuludq ($T0,&$addr(6)); # h4*s2
+ &paddq ($D0,$T2);
+ &movdqa ($MASK,&QWP(64,"ebx"));
+ &pmuludq ($T1,&$addr(7)); # h4*s3
+ &paddq ($D1,$T0);
+ &paddq ($D2,$T1);
+}
+ &pmuladd_alt (sub { my $i=shift; &QWP(16*($i-9),"edx"); });
+
+ &load_input (-16*2,0);
+ &lea ("eax",&DWP(-16*2,"esi"));
+ &sub ("ecx",64);
+
+ &paddd ($T0,&QWP(16*(5+0),"esp")); # add hash value
+ &paddd ($T1,&QWP(16*(5+1),"esp"));
+ &paddd ($D2,&QWP(16*(5+2),"esp"));
+ &paddd ($D3,&QWP(16*(5+3),"esp"));
+ &paddd ($D4,&QWP(16*(5+4),"esp"));
+
+ &cmovb ("esi","eax");
+ &lea ("eax",&DWP(16*10,"esp"));
+
+ &movdqa ($T2,&QWP(16*0,"edx")); # r0^4
+ &movdqa (&QWP(16*1,"esp"),$D1);
+ &movdqa (&QWP(16*1,"eax"),$T1);
+ &movdqa (&QWP(16*2,"eax"),$D2);
+ &movdqa (&QWP(16*3,"eax"),$D3);
+ &movdqa (&QWP(16*4,"eax"),$D4);
+
+ ################################################################
+ # d4 += h4*r0 + h0*r4 + h1*r3 + h2*r2 + h3*r1
+ # d3 += h3*r0 + h0*r3 + h1*r2 + h2*r1 + h4*5*r4
+ # d2 += h2*r0 + h0*r2 + h1*r1 + h3*5*r4 + h4*5*r3
+ # d1 += h1*r0 + h0*r1 + h2*5*r4 + h3*5*r3 + h4*5*r2
+ # d0 += h0*r0 + h1*5*r4 + h2*5*r3 + h3*5*r2 + h4*5*r1
+
+ &movdqa ($D1,$T0);
+ &pmuludq ($T0,$T2); # h0*r0
+ &paddq ($T0,$D0);
+ &movdqa ($D0,$T1);
+ &pmuludq ($T1,$T2); # h1*r0
+ &pmuludq ($D2,$T2); # h2*r0
+ &pmuludq ($D3,$T2); # h3*r0
+ &pmuludq ($D4,$T2); # h4*r0
+
+ &paddq ($T1,&QWP(16*1,"esp"));
+ &paddq ($D2,&QWP(16*2,"esp"));
+ &paddq ($D3,&QWP(16*3,"esp"));
+ &paddq ($D4,&QWP(16*4,"esp"));
+
+ &pmuladd_alt (sub { my $i=shift; &QWP(16*$i,"edx"); });
+
+ &lazy_reduction ();
+
+ &load_input (16*2,16*5);
+
+ &ja (&label("loop"));
+
+&set_label("skip_loop");
+ ################################################################
+ # multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
+
+ &pshufd ($T2,&QWP(16*(0-9),"edx"),0x10);# r0^n
+ &add ("ecx",32);
+ &jnz (&label("long_tail"));
+
+ &paddd ($T0,$D0); # add hash value
+ &paddd ($T1,$D1);
+ &paddd ($D2,&QWP(16*7,"esp"));
+ &paddd ($D3,&QWP(16*8,"esp"));
+ &paddd ($D4,&QWP(16*9,"esp"));
+
+&set_label("long_tail");
+
+ &movdqa (&QWP(16*0,"eax"),$T0);
+ &movdqa (&QWP(16*1,"eax"),$T1);
+ &movdqa (&QWP(16*2,"eax"),$D2);
+ &movdqa (&QWP(16*3,"eax"),$D3);
+ &movdqa (&QWP(16*4,"eax"),$D4);
+
+ ################################################################
+ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4
+ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4
+ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4
+ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4
+ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
+
+ &pmuludq ($T0,$T2); # h0*r0
+ &pmuludq ($T1,$T2); # h1*r0
+ &pmuludq ($D2,$T2); # h2*r0
+ &movdqa ($D0,$T0);
+ &pshufd ($T0,&QWP(16*(1-9),"edx"),0x10);# r1^n
+ &pmuludq ($D3,$T2); # h3*r0
+ &movdqa ($D1,$T1);
+ &pmuludq ($D4,$T2); # h4*r0
+
+ &pmuladd (sub { my ($reg,$i)=@_;
+ &pshufd ($reg,&QWP(16*($i-9),"edx"),0x10);
+ },"eax");
+
+ &jz (&label("short_tail"));
+
+ &load_input (-16*2,0);
+
+ &pshufd ($T2,&QWP(16*0,"edx"),0x10); # r0^n
+ &paddd ($T0,&QWP(16*5,"esp")); # add hash value
+ &paddd ($T1,&QWP(16*6,"esp"));
+ &paddd ($D2,&QWP(16*7,"esp"));
+ &paddd ($D3,&QWP(16*8,"esp"));
+ &paddd ($D4,&QWP(16*9,"esp"));
+
+ ################################################################
+ # multiply inp[0:1] by r^4:r^3 and accumulate
+
+ &movdqa (&QWP(16*0,"esp"),$T0);
+ &pmuludq ($T0,$T2); # h0*r0
+ &movdqa (&QWP(16*1,"esp"),$T1);
+ &pmuludq ($T1,$T2); # h1*r0
+ &paddq ($D0,$T0);
+ &movdqa ($T0,$D2);
+ &pmuludq ($D2,$T2); # h2*r0
+ &paddq ($D1,$T1);
+ &movdqa ($T1,$D3);
+ &pmuludq ($D3,$T2); # h3*r0
+ &paddq ($D2,&QWP(16*2,"esp"));
+ &movdqa (&QWP(16*2,"esp"),$T0);
+ &pshufd ($T0,&QWP(16*1,"edx"),0x10); # r1^n
+ &paddq ($D3,&QWP(16*3,"esp"));
+ &movdqa (&QWP(16*3,"esp"),$T1);
+ &movdqa ($T1,$D4);
+ &pmuludq ($D4,$T2); # h4*r0
+ &paddq ($D4,&QWP(16*4,"esp"));
+ &movdqa (&QWP(16*4,"esp"),$T1);
+
+ &pmuladd (sub { my ($reg,$i)=@_;
+ &pshufd ($reg,&QWP(16*$i,"edx"),0x10);
+ });
+
+&set_label("short_tail");
+
+ ################################################################
+ # horizontal addition
+
+ &pshufd ($T1,$D4,0b01001110);
+ &pshufd ($T0,$D3,0b01001110);
+ &paddq ($D4,$T1);
+ &paddq ($D3,$T0);
+ &pshufd ($T1,$D0,0b01001110);
+ &pshufd ($T0,$D1,0b01001110);
+ &paddq ($D0,$T1);
+ &paddq ($D1,$T0);
+ &pshufd ($T1,$D2,0b01001110);
+ #&paddq ($D2,$T1);
+
+ &lazy_reduction (sub { &paddq ($D2,$T1) });
+
+&set_label("done");
+ &movd (&DWP(-16*3+4*0,"edi"),$D0); # store hash value
+ &movd (&DWP(-16*3+4*1,"edi"),$D1);
+ &movd (&DWP(-16*3+4*2,"edi"),$D2);
+ &movd (&DWP(-16*3+4*3,"edi"),$D3);
+ &movd (&DWP(-16*3+4*4,"edi"),$D4);
+ &mov ("esp","ebp");
+&set_label("nodata");
+&function_end("_poly1305_blocks_sse2");
+
+&align (32);
+&function_begin("_poly1305_emit_sse2");
+ &mov ("ebp",&wparam(0)); # context
+
+ &cmp (&DWP(4*5,"ebp"),0); # is_base2_26?
+ &je (&label("enter_emit"));
+
+ &mov ("eax",&DWP(4*0,"ebp")); # load hash value
+ &mov ("edi",&DWP(4*1,"ebp"));
+ &mov ("ecx",&DWP(4*2,"ebp"));
+ &mov ("edx",&DWP(4*3,"ebp"));
+ &mov ("esi",&DWP(4*4,"ebp"));
+
+ &mov ("ebx","edi"); # base 2^26 -> base 2^32
+ &shl ("edi",26);
+ &shr ("ebx",6);
+ &add ("eax","edi");
+ &mov ("edi","ecx");
+ &adc ("ebx",0);
+
+ &shl ("edi",20);
+ &shr ("ecx",12);
+ &add ("ebx","edi");
+ &mov ("edi","edx");
+ &adc ("ecx",0);
+
+ &shl ("edi",14);
+ &shr ("edx",18);
+ &add ("ecx","edi");
+ &mov ("edi","esi");
+ &adc ("edx",0);
+
+ &shl ("edi",8);
+ &shr ("esi",24);
+ &add ("edx","edi");
+ &adc ("esi",0); # can be partially reduced
+
+ &mov ("edi","esi"); # final reduction
+ &and ("esi",3);
+ &shr ("edi",2);
+ &lea ("ebp",&DWP(0,"edi","edi",4)); # *5
+ &mov ("edi",&wparam(1)); # output
+ add ("eax","ebp");
+ &mov ("ebp",&wparam(2)); # key
+ adc ("ebx",0);
+ adc ("ecx",0);
+ adc ("edx",0);
+
+ &movd ($D0,"eax"); # offload original hash value
+ &add ("eax",5); # compare to modulus
+ &movd ($D1,"ebx");
+ &adc ("ebx",0);
+ &movd ($D2,"ecx");
+ &adc ("ecx",0);
+ &movd ($D3,"edx");
+ &adc ("edx",0);
+ &adc ("esi",0);
+ &shr ("esi",2); # did it carry/borrow?
+
+ &neg ("esi"); # do we choose (hash-modulus) ...
+ &and ("eax","esi");
+ &and ("ebx","esi");
+ &and ("ecx","esi");
+ &and ("edx","esi");
+ &mov (&DWP(4*0,"edi"),"eax");
+ &movd ("eax",$D0);
+ &mov (&DWP(4*1,"edi"),"ebx");
+ &movd ("ebx",$D1);
+ &mov (&DWP(4*2,"edi"),"ecx");
+ &movd ("ecx",$D2);
+ &mov (&DWP(4*3,"edi"),"edx");
+ &movd ("edx",$D3);
+
+ &not ("esi"); # ... or original hash value?
+ &and ("eax","esi");
+ &and ("ebx","esi");
+ &or ("eax",&DWP(4*0,"edi"));
+ &and ("ecx","esi");
+ &or ("ebx",&DWP(4*1,"edi"));
+ &and ("edx","esi");
+ &or ("ecx",&DWP(4*2,"edi"));
+ &or ("edx",&DWP(4*3,"edi"));
+
+ &add ("eax",&DWP(4*0,"ebp")); # accumulate key
+ &adc ("ebx",&DWP(4*1,"ebp"));
+ &mov (&DWP(4*0,"edi"),"eax");
+ &adc ("ecx",&DWP(4*2,"ebp"));
+ &mov (&DWP(4*1,"edi"),"ebx");
+ &adc ("edx",&DWP(4*3,"ebp"));
+ &mov (&DWP(4*2,"edi"),"ecx");
+ &mov (&DWP(4*3,"edi"),"edx");
+&function_end("_poly1305_emit_sse2");
+
+if ($avx>1) {
+########################################################################
+# Note that poly1305_init_avx2 operates on %xmm, I could have used
+# poly1305_init_sse2...
+
+&align (32);
+&function_begin_B("_poly1305_init_avx2");
+ &vmovdqu ($D4,&QWP(4*6,"edi")); # key base 2^32
+ &lea ("edi",&DWP(16*3,"edi")); # size optimization
+ &mov ("ebp","esp");
+ &sub ("esp",16*(9+5));
+ &and ("esp",-16);
+
+ #&vpand ($D4,$D4,&QWP(96,"ebx")); # magic mask
+ &vmovdqa ($MASK,&QWP(64,"ebx"));
+
+ &vpand ($D0,$D4,$MASK); # -> base 2^26
+ &vpsrlq ($D1,$D4,26);
+ &vpsrldq ($D3,$D4,6);
+ &vpand ($D1,$D1,$MASK);
+ &vpsrlq ($D2,$D3,4)
+ &vpsrlq ($D3,$D3,30);
+ &vpand ($D2,$D2,$MASK);
+ &vpand ($D3,$D3,$MASK);
+ &vpsrldq ($D4,$D4,13);
+
+ &lea ("edx",&DWP(16*9,"esp")); # size optimization
+ &mov ("ecx",2);
+&set_label("square");
+ &vmovdqa (&QWP(16*0,"esp"),$D0);
+ &vmovdqa (&QWP(16*1,"esp"),$D1);
+ &vmovdqa (&QWP(16*2,"esp"),$D2);
+ &vmovdqa (&QWP(16*3,"esp"),$D3);
+ &vmovdqa (&QWP(16*4,"esp"),$D4);
+
+ &vpslld ($T1,$D1,2);
+ &vpslld ($T0,$D2,2);
+ &vpaddd ($T1,$T1,$D1); # *5
+ &vpaddd ($T0,$T0,$D2); # *5
+ &vmovdqa (&QWP(16*5,"esp"),$T1);
+ &vmovdqa (&QWP(16*6,"esp"),$T0);
+ &vpslld ($T1,$D3,2);
+ &vpslld ($T0,$D4,2);
+ &vpaddd ($T1,$T1,$D3); # *5
+ &vpaddd ($T0,$T0,$D4); # *5
+ &vmovdqa (&QWP(16*7,"esp"),$T1);
+ &vmovdqa (&QWP(16*8,"esp"),$T0);
+
+ &vpshufd ($T0,$D0,0b01000100);
+ &vmovdqa ($T1,$D1);
+ &vpshufd ($D1,$D1,0b01000100);
+ &vpshufd ($D2,$D2,0b01000100);
+ &vpshufd ($D3,$D3,0b01000100);
+ &vpshufd ($D4,$D4,0b01000100);
+ &vmovdqa (&QWP(16*0,"edx"),$T0);
+ &vmovdqa (&QWP(16*1,"edx"),$D1);
+ &vmovdqa (&QWP(16*2,"edx"),$D2);
+ &vmovdqa (&QWP(16*3,"edx"),$D3);
+ &vmovdqa (&QWP(16*4,"edx"),$D4);
+
+ ################################################################
+ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4
+ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4
+ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4
+ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4
+ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
+
+ &vpmuludq ($D4,$D4,$D0); # h4*r0
+ &vpmuludq ($D3,$D3,$D0); # h3*r0
+ &vpmuludq ($D2,$D2,$D0); # h2*r0
+ &vpmuludq ($D1,$D1,$D0); # h1*r0
+ &vpmuludq ($D0,$T0,$D0); # h0*r0
+
+ &vpmuludq ($T0,$T1,&QWP(16*3,"edx")); # r1*h3
+ &vpaddq ($D4,$D4,$T0);
+ &vpmuludq ($T2,$T1,&QWP(16*2,"edx")); # r1*h2
+ &vpaddq ($D3,$D3,$T2);
+ &vpmuludq ($T0,$T1,&QWP(16*1,"edx")); # r1*h1
+ &vpaddq ($D2,$D2,$T0);
+ &vmovdqa ($T2,&QWP(16*5,"esp")); # s1
+ &vpmuludq ($T1,$T1,&QWP(16*0,"edx")); # r1*h0
+ &vpaddq ($D1,$D1,$T1);
+ &vmovdqa ($T0,&QWP(16*2,"esp")); # r2
+ &vpmuludq ($T2,$T2,&QWP(16*4,"edx")); # s1*h4
+ &vpaddq ($D0,$D0,$T2);
+
+ &vpmuludq ($T1,$T0,&QWP(16*2,"edx")); # r2*h2
+ &vpaddq ($D4,$D4,$T1);
+ &vpmuludq ($T2,$T0,&QWP(16*1,"edx")); # r2*h1
+ &vpaddq ($D3,$D3,$T2);
+ &vmovdqa ($T1,&QWP(16*6,"esp")); # s2
+ &vpmuludq ($T0,$T0,&QWP(16*0,"edx")); # r2*h0
+ &vpaddq ($D2,$D2,$T0);
+ &vpmuludq ($T2,$T1,&QWP(16*4,"edx")); # s2*h4
+ &vpaddq ($D1,$D1,$T2);
+ &vmovdqa ($T0,&QWP(16*3,"esp")); # r3
+ &vpmuludq ($T1,$T1,&QWP(16*3,"edx")); # s2*h3
+ &vpaddq ($D0,$D0,$T1);
+
+ &vpmuludq ($T2,$T0,&QWP(16*1,"edx")); # r3*h1
+ &vpaddq ($D4,$D4,$T2);
+ &vmovdqa ($T1,&QWP(16*7,"esp")); # s3
+ &vpmuludq ($T0,$T0,&QWP(16*0,"edx")); # r3*h0
+ &vpaddq ($D3,$D3,$T0);
+ &vpmuludq ($T2,$T1,&QWP(16*4,"edx")); # s3*h4
+ &vpaddq ($D2,$D2,$T2);
+ &vpmuludq ($T0,$T1,&QWP(16*3,"edx")); # s3*h3
+ &vpaddq ($D1,$D1,$T0);
+ &vmovdqa ($T2,&QWP(16*4,"esp")); # r4
+ &vpmuludq ($T1,$T1,&QWP(16*2,"edx")); # s3*h2
+ &vpaddq ($D0,$D0,$T1);
+
+ &vmovdqa ($T0,&QWP(16*8,"esp")); # s4
+ &vpmuludq ($T2,$T2,&QWP(16*0,"edx")); # r4*h0
+ &vpaddq ($D4,$D4,$T2);
+ &vpmuludq ($T1,$T0,&QWP(16*4,"edx")); # s4*h4
+ &vpaddq ($D3,$D3,$T1);
+ &vpmuludq ($T2,$T0,&QWP(16*1,"edx")); # s4*h1
+ &vpaddq ($D0,$D0,$T2);
+ &vpmuludq ($T1,$T0,&QWP(16*2,"edx")); # s4*h2
+ &vpaddq ($D1,$D1,$T1);
+ &vmovdqa ($MASK,&QWP(64,"ebx"));
+ &vpmuludq ($T0,$T0,&QWP(16*3,"edx")); # s4*h3
+ &vpaddq ($D2,$D2,$T0);
+
+ ################################################################
+ # lazy reduction
+ &vpsrlq ($T0,$D3,26);
+ &vpand ($D3,$D3,$MASK);
+ &vpsrlq ($T1,$D0,26);
+ &vpand ($D0,$D0,$MASK);
+ &vpaddq ($D4,$D4,$T0); # h3 -> h4
+ &vpaddq ($D1,$D1,$T1); # h0 -> h1
+ &vpsrlq ($T0,$D4,26);
+ &vpand ($D4,$D4,$MASK);
+ &vpsrlq ($T1,$D1,26);
+ &vpand ($D1,$D1,$MASK);
+ &vpaddq ($D2,$D2,$T1); # h1 -> h2
+ &vpaddd ($D0,$D0,$T0);
+ &vpsllq ($T0,$T0,2);
+ &vpsrlq ($T1,$D2,26);
+ &vpand ($D2,$D2,$MASK);
+ &vpaddd ($D0,$D0,$T0); # h4 -> h0
+ &vpaddd ($D3,$D3,$T1); # h2 -> h3
+ &vpsrlq ($T1,$D3,26);
+ &vpsrlq ($T0,$D0,26);
+ &vpand ($D0,$D0,$MASK);
+ &vpand ($D3,$D3,$MASK);
+ &vpaddd ($D1,$D1,$T0); # h0 -> h1
+ &vpaddd ($D4,$D4,$T1); # h3 -> h4
+
+ &dec ("ecx");
+ &jz (&label("square_break"));
+
+ &vpunpcklqdq ($D0,$D0,&QWP(16*0,"esp")); # 0:r^1:0:r^2
+ &vpunpcklqdq ($D1,$D1,&QWP(16*1,"esp"));
+ &vpunpcklqdq ($D2,$D2,&QWP(16*2,"esp"));
+ &vpunpcklqdq ($D3,$D3,&QWP(16*3,"esp"));
+ &vpunpcklqdq ($D4,$D4,&QWP(16*4,"esp"));
+ &jmp (&label("square"));
+
+&set_label("square_break");
+ &vpsllq ($D0,$D0,32); # -> r^3:0:r^4:0
+ &vpsllq ($D1,$D1,32);
+ &vpsllq ($D2,$D2,32);
+ &vpsllq ($D3,$D3,32);
+ &vpsllq ($D4,$D4,32);
+ &vpor ($D0,$D0,&QWP(16*0,"esp")); # r^3:r^1:r^4:r^2
+ &vpor ($D1,$D1,&QWP(16*1,"esp"));
+ &vpor ($D2,$D2,&QWP(16*2,"esp"));
+ &vpor ($D3,$D3,&QWP(16*3,"esp"));
+ &vpor ($D4,$D4,&QWP(16*4,"esp"));
+
+ &vpshufd ($D0,$D0,0b10001101); # -> r^1:r^2:r^3:r^4
+ &vpshufd ($D1,$D1,0b10001101);
+ &vpshufd ($D2,$D2,0b10001101);
+ &vpshufd ($D3,$D3,0b10001101);
+ &vpshufd ($D4,$D4,0b10001101);
+
+ &vmovdqu (&QWP(16*0,"edi"),$D0); # save the table
+ &vmovdqu (&QWP(16*1,"edi"),$D1);
+ &vmovdqu (&QWP(16*2,"edi"),$D2);
+ &vmovdqu (&QWP(16*3,"edi"),$D3);
+ &vmovdqu (&QWP(16*4,"edi"),$D4);
+
+ &vpslld ($T1,$D1,2);
+ &vpslld ($T0,$D2,2);
+ &vpaddd ($T1,$T1,$D1); # *5
+ &vpaddd ($T0,$T0,$D2); # *5
+ &vmovdqu (&QWP(16*5,"edi"),$T1);
+ &vmovdqu (&QWP(16*6,"edi"),$T0);
+ &vpslld ($T1,$D3,2);
+ &vpslld ($T0,$D4,2);
+ &vpaddd ($T1,$T1,$D3); # *5
+ &vpaddd ($T0,$T0,$D4); # *5
+ &vmovdqu (&QWP(16*7,"edi"),$T1);
+ &vmovdqu (&QWP(16*8,"edi"),$T0);
+
+ &mov ("esp","ebp");
+ &lea ("edi",&DWP(-16*3,"edi")); # size de-optimization
+ &ret ();
+&function_end_B("_poly1305_init_avx2");
+
+########################################################################
+# now it's time to switch to %ymm
+
+my ($D0,$D1,$D2,$D3,$D4,$T0,$T1,$T2)=map("ymm$_",(0..7));
+my $MASK=$T2;
+
+sub X { my $reg=shift; $reg=~s/^ymm/xmm/; $reg; }
+
+&align (32);
+&function_begin("_poly1305_blocks_avx2");
+ &mov ("edi",&wparam(0)); # ctx
+ &mov ("esi",&wparam(1)); # inp
+ &mov ("ecx",&wparam(2)); # len
+
+ &mov ("eax",&DWP(4*5,"edi")); # is_base2_26
+ &and ("ecx",-16);
+ &jz (&label("nodata"));
+ &cmp ("ecx",64);
+ &jae (&label("enter_avx2"));
+ &test ("eax","eax"); # is_base2_26?
+ &jz (&label("enter_blocks"));
+
+&set_label("enter_avx2");
+ &vzeroupper ();
+
+ &call (&label("pic_point"));
+&set_label("pic_point");
+ &blindpop("ebx");
+ &lea ("ebx",&DWP(&label("const_sse2")."-".&label("pic_point"),"ebx"));
+
+ &test ("eax","eax"); # is_base2_26?
+ &jnz (&label("base2_26"));
+
+ &call ("_poly1305_init_avx2");
+
+ ################################################# base 2^32 -> base 2^26
+ &mov ("eax",&DWP(0,"edi"));
+ &mov ("ecx",&DWP(3,"edi"));
+ &mov ("edx",&DWP(6,"edi"));
+ &mov ("esi",&DWP(9,"edi"));
+ &mov ("ebp",&DWP(13,"edi"));
+
+ &shr ("ecx",2);
+ &and ("eax",0x3ffffff);
+ &shr ("edx",4);
+ &and ("ecx",0x3ffffff);
+ &shr ("esi",6);
+ &and ("edx",0x3ffffff);
+
+ &mov (&DWP(4*0,"edi"),"eax");
+ &mov (&DWP(4*1,"edi"),"ecx");
+ &mov (&DWP(4*2,"edi"),"edx");
+ &mov (&DWP(4*3,"edi"),"esi");
+ &mov (&DWP(4*4,"edi"),"ebp");
+ &mov (&DWP(4*5,"edi"),1); # is_base2_26
+
+ &mov ("esi",&wparam(1)); # [reload] inp
+ &mov ("ecx",&wparam(2)); # [reload] len
+
+&set_label("base2_26");
+ &mov ("eax",&wparam(3)); # padbit
+ &mov ("ebp","esp");
+
+ &sub ("esp",32*(5+9));
+ &and ("esp",-512); # ensure that frame
+ # doesn't cross page
+ # boundary, which is
+ # essential for
+ # misaligned 32-byte
+ # loads
+
+ ################################################################
+ # expand and copy pre-calculated table to stack
+
+ &vmovdqu (&X($D0),&QWP(16*(3+0),"edi"));
+ &lea ("edx",&DWP(32*5+128,"esp")); # +128 size optimization
+ &vmovdqu (&X($D1),&QWP(16*(3+1),"edi"));
+ &vmovdqu (&X($D2),&QWP(16*(3+2),"edi"));
+ &vmovdqu (&X($D3),&QWP(16*(3+3),"edi"));
+ &vmovdqu (&X($D4),&QWP(16*(3+4),"edi"));
+ &lea ("edi",&DWP(16*3,"edi")); # size optimization
+ &vpermq ($D0,$D0,0b01000000); # 00001234 -> 12343434
+ &vpermq ($D1,$D1,0b01000000);
+ &vpermq ($D2,$D2,0b01000000);
+ &vpermq ($D3,$D3,0b01000000);
+ &vpermq ($D4,$D4,0b01000000);
+ &vpshufd ($D0,$D0,0b11001000); # 12343434 -> 14243444
+ &vpshufd ($D1,$D1,0b11001000);
+ &vpshufd ($D2,$D2,0b11001000);
+ &vpshufd ($D3,$D3,0b11001000);
+ &vpshufd ($D4,$D4,0b11001000);
+ &vmovdqa (&QWP(32*0-128,"edx"),$D0);
+ &vmovdqu (&X($D0),&QWP(16*5,"edi"));
+ &vmovdqa (&QWP(32*1-128,"edx"),$D1);
+ &vmovdqu (&X($D1),&QWP(16*6,"edi"));
+ &vmovdqa (&QWP(32*2-128,"edx"),$D2);
+ &vmovdqu (&X($D2),&QWP(16*7,"edi"));
+ &vmovdqa (&QWP(32*3-128,"edx"),$D3);
+ &vmovdqu (&X($D3),&QWP(16*8,"edi"));
+ &vmovdqa (&QWP(32*4-128,"edx"),$D4);
+ &vpermq ($D0,$D0,0b01000000);
+ &vpermq ($D1,$D1,0b01000000);
+ &vpermq ($D2,$D2,0b01000000);
+ &vpermq ($D3,$D3,0b01000000);
+ &vpshufd ($D0,$D0,0b11001000);
+ &vpshufd ($D1,$D1,0b11001000);
+ &vpshufd ($D2,$D2,0b11001000);
+ &vpshufd ($D3,$D3,0b11001000);
+ &vmovdqa (&QWP(32*5-128,"edx"),$D0);
+ &vmovd (&X($D0),&DWP(-16*3+4*0,"edi"));# load hash value
+ &vmovdqa (&QWP(32*6-128,"edx"),$D1);
+ &vmovd (&X($D1),&DWP(-16*3+4*1,"edi"));
+ &vmovdqa (&QWP(32*7-128,"edx"),$D2);
+ &vmovd (&X($D2),&DWP(-16*3+4*2,"edi"));
+ &vmovdqa (&QWP(32*8-128,"edx"),$D3);
+ &vmovd (&X($D3),&DWP(-16*3+4*3,"edi"));
+ &vmovd (&X($D4),&DWP(-16*3+4*4,"edi"));
+ &vmovdqa ($MASK,&QWP(64,"ebx"));
+ &neg ("eax"); # padbit
+
+ &test ("ecx",63);
+ &jz (&label("even"));
+
+ &mov ("edx","ecx");
+ &and ("ecx",-64);
+ &and ("edx",63);
+
+ &vmovdqu (&X($T0),&QWP(16*0,"esi"));
+ &cmp ("edx",32);
+ &jb (&label("one"));
+
+ &vmovdqu (&X($T1),&QWP(16*1,"esi"));
+ &je (&label("two"));
+
+ &vinserti128 ($T0,$T0,&QWP(16*2,"esi"),1);
+ &lea ("esi",&DWP(16*3,"esi"));
+ &lea ("ebx",&DWP(8,"ebx")); # three padbits
+ &lea ("edx",&DWP(32*5+128+8,"esp")); # --:r^1:r^2:r^3 (*)
+ &jmp (&label("tail"));
+
+&set_label("two");
+ &lea ("esi",&DWP(16*2,"esi"));
+ &lea ("ebx",&DWP(16,"ebx")); # two padbits
+ &lea ("edx",&DWP(32*5+128+16,"esp"));# --:--:r^1:r^2 (*)
+ &jmp (&label("tail"));
+
+&set_label("one");
+ &lea ("esi",&DWP(16*1,"esi"));
+ &vpxor ($T1,$T1,$T1);
+ &lea ("ebx",&DWP(32,"ebx","eax",8)); # one or no padbits
+ &lea ("edx",&DWP(32*5+128+24,"esp"));# --:--:--:r^1 (*)
+ &jmp (&label("tail"));
+
+# (*) spots marked with '--' are data from next table entry, but they
+# are multiplied by 0 and therefore rendered insignificant
+
+&set_label("even",32);
+ &vmovdqu (&X($T0),&QWP(16*0,"esi")); # load input
+ &vmovdqu (&X($T1),&QWP(16*1,"esi"));
+ &vinserti128 ($T0,$T0,&QWP(16*2,"esi"),1);
+ &vinserti128 ($T1,$T1,&QWP(16*3,"esi"),1);
+ &lea ("esi",&DWP(16*4,"esi"));
+ &sub ("ecx",64);
+ &jz (&label("tail"));
+
+&set_label("loop");
+ ################################################################
+ # ((inp[0]*r^4+r[4])*r^4+r[8])*r^4
+ # ((inp[1]*r^4+r[5])*r^4+r[9])*r^3
+ # ((inp[2]*r^4+r[6])*r^4+r[10])*r^2
+ # ((inp[3]*r^4+r[7])*r^4+r[11])*r^1
+ # \________/ \_______/
+ ################################################################
+
+sub vsplat_input {
+ &vmovdqa (&QWP(32*2,"esp"),$D2);
+ &vpsrldq ($D2,$T0,6); # splat input
+ &vmovdqa (&QWP(32*0,"esp"),$D0);
+ &vpsrldq ($D0,$T1,6);
+ &vmovdqa (&QWP(32*1,"esp"),$D1);
+ &vpunpckhqdq ($D1,$T0,$T1); # 4
+ &vpunpcklqdq ($T0,$T0,$T1); # 0:1
+ &vpunpcklqdq ($D2,$D2,$D0); # 2:3
+
+ &vpsrlq ($D0,$D2,30);
+ &vpsrlq ($D2,$D2,4);
+ &vpsrlq ($T1,$T0,26);
+ &vpsrlq ($D1,$D1,40); # 4
+ &vpand ($D2,$D2,$MASK); # 2
+ &vpand ($T0,$T0,$MASK); # 0
+ &vpand ($T1,$T1,$MASK); # 1
+ &vpand ($D0,$D0,$MASK); # 3 (*)
+ &vpor ($D1,$D1,&QWP(0,"ebx")); # padbit, yes, always
+
+ # (*) note that output is counterintuitive, inp[3:4] is
+ # returned in $D1-2, while $D3-4 are preserved;
+}
+ &vsplat_input ();
+
+sub vpmuladd {
+my $addr = shift;
+
+ &vpaddq ($D2,$D2,&QWP(32*2,"esp")); # add hash value
+ &vpaddq ($T0,$T0,&QWP(32*0,"esp"));
+ &vpaddq ($T1,$T1,&QWP(32*1,"esp"));
+ &vpaddq ($D0,$D0,$D3);
+ &vpaddq ($D1,$D1,$D4);
+
+ ################################################################
+ # d3 = h2*r1 + h0*r3 + h1*r2 + h3*r0 + h4*5*r4
+ # d4 = h2*r2 + h0*r4 + h1*r3 + h3*r1 + h4*r0
+ # d0 = h2*5*r3 + h0*r0 + h1*5*r4 + h3*5*r2 + h4*5*r1
+ # d1 = h2*5*r4 + h0*r1 + h1*r0 + h3*5*r3 + h4*5*r2
+ # d2 = h2*r0 + h0*r2 + h1*r1 + h3*5*r4 + h4*5*r3
+
+ &vpmuludq ($D3,$D2,&$addr(1)); # d3 = h2*r1
+ &vmovdqa (QWP(32*1,"esp"),$T1);
+ &vpmuludq ($D4,$D2,&$addr(2)); # d4 = h2*r2
+ &vmovdqa (QWP(32*3,"esp"),$D0);
+ &vpmuludq ($D0,$D2,&$addr(7)); # d0 = h2*s3
+ &vmovdqa (QWP(32*4,"esp"),$D1);
+ &vpmuludq ($D1,$D2,&$addr(8)); # d1 = h2*s4
+ &vpmuludq ($D2,$D2,&$addr(0)); # d2 = h2*r0
+
+ &vpmuludq ($T2,$T0,&$addr(3)); # h0*r3
+ &vpaddq ($D3,$D3,$T2); # d3 += h0*r3
+ &vpmuludq ($T1,$T0,&$addr(4)); # h0*r4
+ &vpaddq ($D4,$D4,$T1); # d4 + h0*r4
+ &vpmuludq ($T2,$T0,&$addr(0)); # h0*r0
+ &vpaddq ($D0,$D0,$T2); # d0 + h0*r0
+ &vmovdqa ($T2,&QWP(32*1,"esp")); # h1
+ &vpmuludq ($T1,$T0,&$addr(1)); # h0*r1
+ &vpaddq ($D1,$D1,$T1); # d1 += h0*r1
+ &vpmuludq ($T0,$T0,&$addr(2)); # h0*r2
+ &vpaddq ($D2,$D2,$T0); # d2 += h0*r2
+
+ &vpmuludq ($T1,$T2,&$addr(2)); # h1*r2
+ &vpaddq ($D3,$D3,$T1); # d3 += h1*r2
+ &vpmuludq ($T0,$T2,&$addr(3)); # h1*r3
+ &vpaddq ($D4,$D4,$T0); # d4 += h1*r3
+ &vpmuludq ($T1,$T2,&$addr(8)); # h1*s4
+ &vpaddq ($D0,$D0,$T1); # d0 += h1*s4
+ &vmovdqa ($T1,&QWP(32*3,"esp")); # h3
+ &vpmuludq ($T0,$T2,&$addr(0)); # h1*r0
+ &vpaddq ($D1,$D1,$T0); # d1 += h1*r0
+ &vpmuludq ($T2,$T2,&$addr(1)); # h1*r1
+ &vpaddq ($D2,$D2,$T2); # d2 += h1*r1
+
+ &vpmuludq ($T0,$T1,&$addr(0)); # h3*r0
+ &vpaddq ($D3,$D3,$T0); # d3 += h3*r0
+ &vpmuludq ($T2,$T1,&$addr(1)); # h3*r1
+ &vpaddq ($D4,$D4,$T2); # d4 += h3*r1
+ &vpmuludq ($T0,$T1,&$addr(6)); # h3*s2
+ &vpaddq ($D0,$D0,$T0); # d0 += h3*s2
+ &vmovdqa ($T0,&QWP(32*4,"esp")); # h4
+ &vpmuludq ($T2,$T1,&$addr(7)); # h3*s3
+ &vpaddq ($D1,$D1,$T2); # d1+= h3*s3
+ &vpmuludq ($T1,$T1,&$addr(8)); # h3*s4
+ &vpaddq ($D2,$D2,$T1); # d2 += h3*s4
+
+ &vpmuludq ($T2,$T0,&$addr(8)); # h4*s4
+ &vpaddq ($D3,$D3,$T2); # d3 += h4*s4
+ &vpmuludq ($T1,$T0,&$addr(5)); # h4*s1
+ &vpaddq ($D0,$D0,$T1); # d0 += h4*s1
+ &vpmuludq ($T2,$T0,&$addr(0)); # h4*r0
+ &vpaddq ($D4,$D4,$T2); # d4 += h4*r0
+ &vmovdqa ($MASK,&QWP(64,"ebx"));
+ &vpmuludq ($T1,$T0,&$addr(6)); # h4*s2
+ &vpaddq ($D1,$D1,$T1); # d1 += h4*s2
+ &vpmuludq ($T0,$T0,&$addr(7)); # h4*s3
+ &vpaddq ($D2,$D2,$T0); # d2 += h4*s3
+}
+ &vpmuladd (sub { my $i=shift; &QWP(32*$i-128,"edx"); });
+
+sub vlazy_reduction {
+ ################################################################
+ # lazy reduction
+
+ &vpsrlq ($T0,$D3,26);
+ &vpand ($D3,$D3,$MASK);
+ &vpsrlq ($T1,$D0,26);
+ &vpand ($D0,$D0,$MASK);
+ &vpaddq ($D4,$D4,$T0); # h3 -> h4
+ &vpaddq ($D1,$D1,$T1); # h0 -> h1
+ &vpsrlq ($T0,$D4,26);
+ &vpand ($D4,$D4,$MASK);
+ &vpsrlq ($T1,$D1,26);
+ &vpand ($D1,$D1,$MASK);
+ &vpaddq ($D2,$D2,$T1); # h1 -> h2
+ &vpaddq ($D0,$D0,$T0);
+ &vpsllq ($T0,$T0,2);
+ &vpsrlq ($T1,$D2,26);
+ &vpand ($D2,$D2,$MASK);
+ &vpaddq ($D0,$D0,$T0); # h4 -> h0
+ &vpaddq ($D3,$D3,$T1); # h2 -> h3
+ &vpsrlq ($T1,$D3,26);
+ &vpsrlq ($T0,$D0,26);
+ &vpand ($D0,$D0,$MASK);
+ &vpand ($D3,$D3,$MASK);
+ &vpaddq ($D1,$D1,$T0); # h0 -> h1
+ &vpaddq ($D4,$D4,$T1); # h3 -> h4
+}
+ &vlazy_reduction();
+
+ &vmovdqu (&X($T0),&QWP(16*0,"esi")); # load input
+ &vmovdqu (&X($T1),&QWP(16*1,"esi"));
+ &vinserti128 ($T0,$T0,&QWP(16*2,"esi"),1);
+ &vinserti128 ($T1,$T1,&QWP(16*3,"esi"),1);
+ &lea ("esi",&DWP(16*4,"esi"));
+ &sub ("ecx",64);
+ &jnz (&label("loop"));
+
+&set_label("tail");
+ &vsplat_input ();
+ &and ("ebx",-64); # restore pointer
+
+ &vpmuladd (sub { my $i=shift; &QWP(4+32*$i-128,"edx"); });
+
+ ################################################################
+ # horizontal addition
+
+ &vpsrldq ($T0,$D4,8);
+ &vpsrldq ($T1,$D3,8);
+ &vpaddq ($D4,$D4,$T0);
+ &vpsrldq ($T0,$D0,8);
+ &vpaddq ($D3,$D3,$T1);
+ &vpsrldq ($T1,$D1,8);
+ &vpaddq ($D0,$D0,$T0);
+ &vpsrldq ($T0,$D2,8);
+ &vpaddq ($D1,$D1,$T1);
+ &vpermq ($T1,$D4,2); # keep folding
+ &vpaddq ($D2,$D2,$T0);
+ &vpermq ($T0,$D3,2);
+ &vpaddq ($D4,$D4,$T1);
+ &vpermq ($T1,$D0,2);
+ &vpaddq ($D3,$D3,$T0);
+ &vpermq ($T0,$D1,2);
+ &vpaddq ($D0,$D0,$T1);
+ &vpermq ($T1,$D2,2);
+ &vpaddq ($D1,$D1,$T0);
+ &vpaddq ($D2,$D2,$T1);
+
+ &vlazy_reduction();
+
+ &cmp ("ecx",0);
+ &je (&label("done"));
+
+ ################################################################
+ # clear all but single word
+
+ &vpshufd (&X($D0),&X($D0),0b11111100);
+ &lea ("edx",&DWP(32*5+128,"esp")); # restore pointer
+ &vpshufd (&X($D1),&X($D1),0b11111100);
+ &vpshufd (&X($D2),&X($D2),0b11111100);
+ &vpshufd (&X($D3),&X($D3),0b11111100);
+ &vpshufd (&X($D4),&X($D4),0b11111100);
+ &jmp (&label("even"));
+
+&set_label("done",16);
+ &vmovd (&DWP(-16*3+4*0,"edi"),&X($D0));# store hash value
+ &vmovd (&DWP(-16*3+4*1,"edi"),&X($D1));
+ &vmovd (&DWP(-16*3+4*2,"edi"),&X($D2));
+ &vmovd (&DWP(-16*3+4*3,"edi"),&X($D3));
+ &vmovd (&DWP(-16*3+4*4,"edi"),&X($D4));
+ &vzeroupper ();
+ &mov ("esp","ebp");
+&set_label("nodata");
+&function_end("_poly1305_blocks_avx2");
+}
+&set_label("const_sse2",64);
+ &data_word(1<<24,0, 1<<24,0, 1<<24,0, 1<<24,0);
+ &data_word(0,0, 0,0, 0,0, 0,0);
+ &data_word(0x03ffffff,0,0x03ffffff,0, 0x03ffffff,0, 0x03ffffff,0);
+ &data_word(0x0fffffff,0x0ffffffc,0x0ffffffc,0x0ffffffc);
+}
+&asciz ("Poly1305 for x86, CRYPTOGAMS by <appro\@openssl.org>");
+&align (4);
+
+&asm_finish();
diff --git a/crypto/poly1305/asm/poly1305-x86_64.pl b/crypto/poly1305/asm/poly1305-x86_64.pl
new file mode 100755
index 00000000..3c810c5a
--- /dev/null
+++ b/crypto/poly1305/asm/poly1305-x86_64.pl
@@ -0,0 +1,2235 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# This module implements Poly1305 hash for x86_64.
+#
+# March 2015
+#
+# Numbers are cycles per processed byte with poly1305_blocks alone,
+# measured with rdtsc at fixed clock frequency.
+#
+# IALU/gcc-4.8(*) AVX(**) AVX2
+# P4 4.90/+120% -
+# Core 2 2.39/+90% -
+# Westmere 1.86/+120% -
+# Sandy Bridge 1.39/+140% 1.10
+# Haswell 1.10/+175% 1.11 0.65
+# Skylake 1.12/+120% 0.96 0.51
+# Silvermont 2.83/+95% -
+# VIA Nano 1.82/+150% -
+# Sledgehammer 1.38/+160% -
+# Bulldozer 2.21/+130% 0.97
+#
+# (*) improvement coefficients relative to clang are more modest and
+# are ~50% on most processors, in both cases we are comparing to
+# __int128 code;
+# (**) SSE2 implementation was attempted, but among non-AVX processors
+# it was faster than integer-only code only on older Intel P4 and
+# Core processors, 50-30%, less newer processor is, but slower on
+# contemporary ones, for example almost 2x slower on Atom, and as
+# former are naturally disappearing, SSE2 is deemed unnecessary;
+
+$flavour = shift;
+$output = shift;
+if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
+
+$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
+( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
+die "can't locate x86_64-xlate.pl";
+
+$avx = 2;
+
+open OUT,"| \"$^X\" $xlate $flavour $output";
+*STDOUT=*OUT;
+
+my ($ctx,$inp,$len,$padbit)=("%rdi","%rsi","%rdx","%rcx");
+my ($mac,$nonce)=($inp,$len); # *_emit arguments
+my ($d1,$d2,$d3, $r0,$r1,$s1)=map("%r$_",(8..13));
+my ($h0,$h1,$h2)=("%r14","%rbx","%rbp");
+
+sub poly1305_iteration {
+# input: copy of $r1 in %rax, $h0-$h2, $r0-$r1
+# output: $h0-$h2 *= $r0-$r1
+$code.=<<___;
+ mulq $h0 # h0*r1
+ mov %rax,$d2
+ mov $r0,%rax
+ mov %rdx,$d3
+
+ mulq $h0 # h0*r0
+ mov %rax,$h0 # future $h0
+ mov $r0,%rax
+ mov %rdx,$d1
+
+ mulq $h1 # h1*r0
+ add %rax,$d2
+ mov $s1,%rax
+ adc %rdx,$d3
+
+ mulq $h1 # h1*s1
+ mov $h2,$h1 # borrow $h1
+ add %rax,$h0
+ adc %rdx,$d1
+
+ imulq $s1,$h1 # h2*s1
+ add $h1,$d2
+ mov $d1,$h1
+ adc \$0,$d3
+
+ imulq $r0,$h2 # h2*r0
+ add $d2,$h1
+ mov \$-4,%rax # mask value
+ adc $h2,$d3
+
+ and $d3,%rax # last reduction step
+ mov $d3,$h2
+ shr \$2,$d3
+ and \$3,$h2
+ add $d3,%rax
+ add %rax,$h0
+ adc \$0,$h1
+___
+}
+
+########################################################################
+# Layout of opaque area is following.
+#
+# unsigned __int64 h[3]; # current hash value base 2^64
+# unsigned __int64 r[2]; # key value base 2^64
+
+$code.=<<___;
+.text
+
+.extern OPENSSL_ia32cap_P
+
+.globl poly1305_init
+.globl poly1305_blocks
+.globl poly1305_emit
+.type poly1305_init,\@function,3
+.align 32
+poly1305_init:
+ xor %rax,%rax
+ mov %rax,0($ctx) # initialize hash value
+ mov %rax,8($ctx)
+ mov %rax,16($ctx)
+
+ cmp \$0,$inp
+ je .Lno_key
+
+ lea poly1305_blocks(%rip),%r10
+ lea poly1305_emit(%rip),%r11
+___
+$code.=<<___ if ($avx);
+ mov OPENSSL_ia32cap_P+4(%rip),%r9
+ lea poly1305_blocks_avx(%rip),%rax
+ lea poly1305_emit_avx(%rip),%rcx
+ bt \$`60-32`,%r9 # AVX?
+ cmovc %rax,%r10
+ cmovc %rcx,%r11
+___
+$code.=<<___ if ($avx>1);
+ lea poly1305_blocks_avx2(%rip),%rax
+ bt \$`5+32`,%r9 # AVX2?
+ cmovc %rax,%r10
+___
+$code.=<<___;
+ mov \$0x0ffffffc0fffffff,%rax
+ mov \$0x0ffffffc0ffffffc,%rcx
+ and 0($inp),%rax
+ and 8($inp),%rcx
+ mov %rax,24($ctx)
+ mov %rcx,32($ctx)
+___
+$code.=<<___ if ($flavour !~ /elf32/);
+ mov %r10,0(%rdx)
+ mov %r11,8(%rdx)
+___
+$code.=<<___ if ($flavour =~ /elf32/);
+ mov %r10d,0(%rdx)
+ mov %r11d,4(%rdx)
+___
+$code.=<<___;
+ mov \$1,%eax
+.Lno_key:
+ ret
+.size poly1305_init,.-poly1305_init
+
+.type poly1305_blocks,\@function,4
+.align 32
+poly1305_blocks:
+.Lblocks:
+ sub \$16,$len # too short?
+ jc .Lno_data
+
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+.Lblocks_body:
+
+ mov $len,%r15 # reassign $len
+
+ mov 24($ctx),$r0 # load r
+ mov 32($ctx),$s1
+
+ mov 0($ctx),$h0 # load hash value
+ mov 8($ctx),$h1
+ mov 16($ctx),$h2
+
+ mov $s1,$r1
+ shr \$2,$s1
+ mov $r1,%rax
+ add $r1,$s1 # s1 = r1 + (r1 >> 2)
+ jmp .Loop
+
+.align 32
+.Loop:
+ add 0($inp),$h0 # accumulate input
+ adc 8($inp),$h1
+ lea 16($inp),$inp
+ adc $padbit,$h2
+___
+ &poly1305_iteration();
+$code.=<<___;
+ mov $r1,%rax
+ sub \$16,%r15 # len-=16
+ jnc .Loop
+
+ mov $h0,0($ctx) # store hash value
+ mov $h1,8($ctx)
+ mov $h2,16($ctx)
+
+ mov 0(%rsp),%r15
+ mov 8(%rsp),%r14
+ mov 16(%rsp),%r13
+ mov 24(%rsp),%r12
+ mov 32(%rsp),%rbp
+ mov 40(%rsp),%rbx
+ lea 48(%rsp),%rsp
+.Lno_data:
+.Lblocks_epilogue:
+ ret
+.size poly1305_blocks,.-poly1305_blocks
+
+.type poly1305_emit,\@function,3
+.align 32
+poly1305_emit:
+.Lemit:
+ mov 0($ctx),%r8 # load hash value
+ mov 8($ctx),%r9
+ mov 16($ctx),%r10
+
+ mov %r8,%rax
+ add \$5,%r8 # compare to modulus
+ mov %r9,%rcx
+ adc \$0,%r9
+ adc \$0,%r10
+ shr \$2,%r10 # did 130-bit value overfow?
+ cmovnz %r8,%rax
+ cmovnz %r9,%rcx
+
+ add 0($nonce),%rax # accumulate nonce
+ adc 8($nonce),%rcx
+ mov %rax,0($mac) # write result
+ mov %rcx,8($mac)
+
+ ret
+.size poly1305_emit,.-poly1305_emit
+___
+if ($avx) {
+
+########################################################################
+# Layout of opaque area is following.
+#
+# unsigned __int32 h[5]; # current hash value base 2^26
+# unsigned __int32 is_base2_26;
+# unsigned __int64 r[2]; # key value base 2^64
+# unsigned __int64 pad;
+# struct { unsigned __int32 r^2, r^1, r^4, r^3; } r[9];
+#
+# where r^n are base 2^26 digits of degrees of multiplier key. There are
+# 5 digits, but last four are interleaved with multiples of 5, totalling
+# in 9 elements: r0, r1, 5*r1, r2, 5*r2, r3, 5*r3, r4, 5*r4.
+
+my ($H0,$H1,$H2,$H3,$H4, $T0,$T1,$T2,$T3,$T4, $D0,$D1,$D2,$D3,$D4, $MASK) =
+ map("%xmm$_",(0..15));
+
+$code.=<<___;
+.type __poly1305_block,\@abi-omnipotent
+.align 32
+__poly1305_block:
+___
+ &poly1305_iteration();
+$code.=<<___;
+ ret
+.size __poly1305_block,.-__poly1305_block
+
+.type __poly1305_init_avx,\@abi-omnipotent
+.align 32
+__poly1305_init_avx:
+ mov $r0,$h0
+ mov $r1,$h1
+ xor $h2,$h2
+
+ lea 48+64($ctx),$ctx # size optimization
+
+ mov $r1,%rax
+ call __poly1305_block # r^2
+
+ mov \$0x3ffffff,%eax # save interleaved r^2 and r base 2^26
+ mov \$0x3ffffff,%edx
+ mov $h0,$d1
+ and $h0#d,%eax
+ mov $r0,$d2
+ and $r0#d,%edx
+ mov %eax,`16*0+0-64`($ctx)
+ shr \$26,$d1
+ mov %edx,`16*0+4-64`($ctx)
+ shr \$26,$d2
+
+ mov \$0x3ffffff,%eax
+ mov \$0x3ffffff,%edx
+ and $d1#d,%eax
+ and $d2#d,%edx
+ mov %eax,`16*1+0-64`($ctx)
+ lea (%rax,%rax,4),%eax # *5
+ mov %edx,`16*1+4-64`($ctx)
+ lea (%rdx,%rdx,4),%edx # *5
+ mov %eax,`16*2+0-64`($ctx)
+ shr \$26,$d1
+ mov %edx,`16*2+4-64`($ctx)
+ shr \$26,$d2
+
+ mov $h1,%rax
+ mov $r1,%rdx
+ shl \$12,%rax
+ shl \$12,%rdx
+ or $d1,%rax
+ or $d2,%rdx
+ and \$0x3ffffff,%eax
+ and \$0x3ffffff,%edx
+ mov %eax,`16*3+0-64`($ctx)
+ lea (%rax,%rax,4),%eax # *5
+ mov %edx,`16*3+4-64`($ctx)
+ lea (%rdx,%rdx,4),%edx # *5
+ mov %eax,`16*4+0-64`($ctx)
+ mov $h1,$d1
+ mov %edx,`16*4+4-64`($ctx)
+ mov $r1,$d2
+
+ mov \$0x3ffffff,%eax
+ mov \$0x3ffffff,%edx
+ shr \$14,$d1
+ shr \$14,$d2
+ and $d1#d,%eax
+ and $d2#d,%edx
+ mov %eax,`16*5+0-64`($ctx)
+ lea (%rax,%rax,4),%eax # *5
+ mov %edx,`16*5+4-64`($ctx)
+ lea (%rdx,%rdx,4),%edx # *5
+ mov %eax,`16*6+0-64`($ctx)
+ shr \$26,$d1
+ mov %edx,`16*6+4-64`($ctx)
+ shr \$26,$d2
+
+ mov $h2,%rax
+ shl \$24,%rax
+ or %rax,$d1
+ mov $d1#d,`16*7+0-64`($ctx)
+ lea ($d1,$d1,4),$d1 # *5
+ mov $d2#d,`16*7+4-64`($ctx)
+ lea ($d2,$d2,4),$d2 # *5
+ mov $d1#d,`16*8+0-64`($ctx)
+ mov $d2#d,`16*8+4-64`($ctx)
+
+ mov $r1,%rax
+ call __poly1305_block # r^3
+
+ mov \$0x3ffffff,%eax # save r^3 base 2^26
+ mov $h0,$d1
+ and $h0#d,%eax
+ shr \$26,$d1
+ mov %eax,`16*0+12-64`($ctx)
+
+ mov \$0x3ffffff,%edx
+ and $d1#d,%edx
+ mov %edx,`16*1+12-64`($ctx)
+ lea (%rdx,%rdx,4),%edx # *5
+ shr \$26,$d1
+ mov %edx,`16*2+12-64`($ctx)
+
+ mov $h1,%rax
+ shl \$12,%rax
+ or $d1,%rax
+ and \$0x3ffffff,%eax
+ mov %eax,`16*3+12-64`($ctx)
+ lea (%rax,%rax,4),%eax # *5
+ mov $h1,$d1
+ mov %eax,`16*4+12-64`($ctx)
+
+ mov \$0x3ffffff,%edx
+ shr \$14,$d1
+ and $d1#d,%edx
+ mov %edx,`16*5+12-64`($ctx)
+ lea (%rdx,%rdx,4),%edx # *5
+ shr \$26,$d1
+ mov %edx,`16*6+12-64`($ctx)
+
+ mov $h2,%rax
+ shl \$24,%rax
+ or %rax,$d1
+ mov $d1#d,`16*7+12-64`($ctx)
+ lea ($d1,$d1,4),$d1 # *5
+ mov $d1#d,`16*8+12-64`($ctx)
+
+ mov $r1,%rax
+ call __poly1305_block # r^4
+
+ mov \$0x3ffffff,%eax # save r^4 base 2^26
+ mov $h0,$d1
+ and $h0#d,%eax
+ shr \$26,$d1
+ mov %eax,`16*0+8-64`($ctx)
+
+ mov \$0x3ffffff,%edx
+ and $d1#d,%edx
+ mov %edx,`16*1+8-64`($ctx)
+ lea (%rdx,%rdx,4),%edx # *5
+ shr \$26,$d1
+ mov %edx,`16*2+8-64`($ctx)
+
+ mov $h1,%rax
+ shl \$12,%rax
+ or $d1,%rax
+ and \$0x3ffffff,%eax
+ mov %eax,`16*3+8-64`($ctx)
+ lea (%rax,%rax,4),%eax # *5
+ mov $h1,$d1
+ mov %eax,`16*4+8-64`($ctx)
+
+ mov \$0x3ffffff,%edx
+ shr \$14,$d1
+ and $d1#d,%edx
+ mov %edx,`16*5+8-64`($ctx)
+ lea (%rdx,%rdx,4),%edx # *5
+ shr \$26,$d1
+ mov %edx,`16*6+8-64`($ctx)
+
+ mov $h2,%rax
+ shl \$24,%rax
+ or %rax,$d1
+ mov $d1#d,`16*7+8-64`($ctx)
+ lea ($d1,$d1,4),$d1 # *5
+ mov $d1#d,`16*8+8-64`($ctx)
+
+ lea -48-64($ctx),$ctx # size [de-]optimization
+ ret
+.size __poly1305_init_avx,.-__poly1305_init_avx
+
+.type poly1305_blocks_avx,\@function,4
+.align 32
+poly1305_blocks_avx:
+ mov 20($ctx),%r8d # is_base2_26
+ cmp \$128,$len
+ jae .Lblocks_avx
+ test %r8d,%r8d
+ jz .Lblocks
+
+.Lblocks_avx:
+ and \$-16,$len
+ jz .Lno_data_avx
+
+ vzeroupper
+
+ test %r8d,%r8d
+ jz .Lbase2_64_avx
+
+ test \$31,$len
+ jz .Leven_avx
+
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+.Lblocks_avx_body:
+
+ mov $len,%r15 # reassign $len
+
+ mov 0($ctx),$d1 # load hash value
+ mov 8($ctx),$d2
+ mov 16($ctx),$h2#d
+
+ mov 24($ctx),$r0 # load r
+ mov 32($ctx),$s1
+
+ ################################# base 2^26 -> base 2^64
+ mov $d1#d,$h0#d
+ and \$-1<<31,$d1
+ mov $d2,$r1 # borrow $r1
+ mov $d2#d,$h1#d
+ and \$-1<<31,$d2
+
+ shr \$6,$d1
+ shl \$52,$r1
+ add $d1,$h0
+ shr \$12,$h1
+ shr \$18,$d2
+ add $r1,$h0
+ adc $d2,$h1
+
+ mov $h2,$d1
+ shl \$40,$d1
+ shr \$24,$h2
+ add $d1,$h1
+ adc \$0,$h2 # can be partially reduced...
+
+ mov \$-4,$d2 # ... so reduce
+ mov $h2,$d1
+ and $h2,$d2
+ shr \$2,$d1
+ and \$3,$h2
+ add $d2,$d1 # =*5
+ add $d1,$h0
+ adc \$0,$h1
+
+ mov $s1,$r1
+ mov $s1,%rax
+ shr \$2,$s1
+ add $r1,$s1 # s1 = r1 + (r1 >> 2)
+
+ add 0($inp),$h0 # accumulate input
+ adc 8($inp),$h1
+ lea 16($inp),$inp
+ adc $padbit,$h2
+
+ call __poly1305_block
+
+ test $padbit,$padbit # if $padbit is zero,
+ jz .Lstore_base2_64_avx # store hash in base 2^64 format
+
+ ################################# base 2^64 -> base 2^26
+ mov $h0,%rax
+ mov $h0,%rdx
+ shr \$52,$h0
+ mov $h1,$r0
+ mov $h1,$r1
+ shr \$26,%rdx
+ and \$0x3ffffff,%rax # h[0]
+ shl \$12,$r0
+ and \$0x3ffffff,%rdx # h[1]
+ shr \$14,$h1
+ or $r0,$h0
+ shl \$24,$h2
+ and \$0x3ffffff,$h0 # h[2]
+ shr \$40,$r1
+ and \$0x3ffffff,$h1 # h[3]
+ or $r1,$h2 # h[4]
+
+ sub \$16,%r15
+ jz .Lstore_base2_26_avx
+
+ vmovd %rax#d,$H0
+ vmovd %rdx#d,$H1
+ vmovd $h0#d,$H2
+ vmovd $h1#d,$H3
+ vmovd $h2#d,$H4
+ jmp .Lproceed_avx
+
+.align 32
+.Lstore_base2_64_avx:
+ mov $h0,0($ctx)
+ mov $h1,8($ctx)
+ mov $h2,16($ctx) # note that is_base2_26 is zeroed
+ jmp .Ldone_avx
+
+.align 16
+.Lstore_base2_26_avx:
+ mov %rax#d,0($ctx) # store hash value base 2^26
+ mov %rdx#d,4($ctx)
+ mov $h0#d,8($ctx)
+ mov $h1#d,12($ctx)
+ mov $h2#d,16($ctx)
+.align 16
+.Ldone_avx:
+ mov 0(%rsp),%r15
+ mov 8(%rsp),%r14
+ mov 16(%rsp),%r13
+ mov 24(%rsp),%r12
+ mov 32(%rsp),%rbp
+ mov 40(%rsp),%rbx
+ lea 48(%rsp),%rsp
+.Lno_data_avx:
+.Lblocks_avx_epilogue:
+ ret
+
+.align 32
+.Lbase2_64_avx:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+.Lbase2_64_avx_body:
+
+ mov $len,%r15 # reassign $len
+
+ mov 24($ctx),$r0 # load r
+ mov 32($ctx),$s1
+
+ mov 0($ctx),$h0 # load hash value
+ mov 8($ctx),$h1
+ mov 16($ctx),$h2#d
+
+ mov $s1,$r1
+ mov $s1,%rax
+ shr \$2,$s1
+ add $r1,$s1 # s1 = r1 + (r1 >> 2)
+
+ test \$31,$len
+ jz .Linit_avx
+
+ add 0($inp),$h0 # accumulate input
+ adc 8($inp),$h1
+ lea 16($inp),$inp
+ adc $padbit,$h2
+ sub \$16,%r15
+
+ call __poly1305_block
+
+.Linit_avx:
+ ################################# base 2^64 -> base 2^26
+ mov $h0,%rax
+ mov $h0,%rdx
+ shr \$52,$h0
+ mov $h1,$d1
+ mov $h1,$d2
+ shr \$26,%rdx
+ and \$0x3ffffff,%rax # h[0]
+ shl \$12,$d1
+ and \$0x3ffffff,%rdx # h[1]
+ shr \$14,$h1
+ or $d1,$h0
+ shl \$24,$h2
+ and \$0x3ffffff,$h0 # h[2]
+ shr \$40,$d2
+ and \$0x3ffffff,$h1 # h[3]
+ or $d2,$h2 # h[4]
+
+ vmovd %rax#d,$H0
+ vmovd %rdx#d,$H1
+ vmovd $h0#d,$H2
+ vmovd $h1#d,$H3
+ vmovd $h2#d,$H4
+ movl \$1,20($ctx) # set is_base2_26
+
+ call __poly1305_init_avx
+
+.Lproceed_avx:
+ mov %r15,$len
+
+ mov 0(%rsp),%r15
+ mov 8(%rsp),%r14
+ mov 16(%rsp),%r13
+ mov 24(%rsp),%r12
+ mov 32(%rsp),%rbp
+ mov 40(%rsp),%rbx
+ lea 48(%rsp),%rax
+ lea 48(%rsp),%rsp
+.Lbase2_64_avx_epilogue:
+ jmp .Ldo_avx
+
+.align 32
+.Leven_avx:
+ vmovd 4*0($ctx),$H0 # load hash value
+ vmovd 4*1($ctx),$H1
+ vmovd 4*2($ctx),$H2
+ vmovd 4*3($ctx),$H3
+ vmovd 4*4($ctx),$H4
+
+.Ldo_avx:
+___
+$code.=<<___ if (!$win64);
+ lea -0x58(%rsp),%r11
+ sub \$0x178,%rsp
+___
+$code.=<<___ if ($win64);
+ lea -0xf8(%rsp),%r11
+ sub \$0x218,%rsp
+ vmovdqa %xmm6,0x50(%r11)
+ vmovdqa %xmm7,0x60(%r11)
+ vmovdqa %xmm8,0x70(%r11)
+ vmovdqa %xmm9,0x80(%r11)
+ vmovdqa %xmm10,0x90(%r11)
+ vmovdqa %xmm11,0xa0(%r11)
+ vmovdqa %xmm12,0xb0(%r11)
+ vmovdqa %xmm13,0xc0(%r11)
+ vmovdqa %xmm14,0xd0(%r11)
+ vmovdqa %xmm15,0xe0(%r11)
+.Ldo_avx_body:
+___
+$code.=<<___;
+ sub \$64,$len
+ lea -32($inp),%rax
+ cmovc %rax,$inp
+
+ vmovdqu `16*3`($ctx),$D4 # preload r0^2
+ lea `16*3+64`($ctx),$ctx # size optimization
+ lea .Lconst(%rip),%rcx
+
+ ################################################################
+ # load input
+ vmovdqu 16*2($inp),$T0
+ vmovdqu 16*3($inp),$T1
+ vmovdqa 64(%rcx),$MASK # .Lmask26
+
+ vpsrldq \$6,$T0,$T2 # splat input
+ vpsrldq \$6,$T1,$T3
+ vpunpckhqdq $T1,$T0,$T4 # 4
+ vpunpcklqdq $T1,$T0,$T0 # 0:1
+ vpunpcklqdq $T3,$T2,$T3 # 2:3
+
+ vpsrlq \$40,$T4,$T4 # 4
+ vpsrlq \$26,$T0,$T1
+ vpand $MASK,$T0,$T0 # 0
+ vpsrlq \$4,$T3,$T2
+ vpand $MASK,$T1,$T1 # 1
+ vpsrlq \$30,$T3,$T3
+ vpand $MASK,$T2,$T2 # 2
+ vpand $MASK,$T3,$T3 # 3
+ vpor 32(%rcx),$T4,$T4 # padbit, yes, always
+
+ jbe .Lskip_loop_avx
+
+ # expand and copy pre-calculated table to stack
+ vmovdqu `16*1-64`($ctx),$D1
+ vmovdqu `16*2-64`($ctx),$D2
+ vpshufd \$0xEE,$D4,$D3 # 34xx -> 3434
+ vpshufd \$0x44,$D4,$D0 # xx12 -> 1212
+ vmovdqa $D3,-0x90(%r11)
+ vmovdqa $D0,0x00(%rsp)
+ vpshufd \$0xEE,$D1,$D4
+ vmovdqu `16*3-64`($ctx),$D0
+ vpshufd \$0x44,$D1,$D1
+ vmovdqa $D4,-0x80(%r11)
+ vmovdqa $D1,0x10(%rsp)
+ vpshufd \$0xEE,$D2,$D3
+ vmovdqu `16*4-64`($ctx),$D1
+ vpshufd \$0x44,$D2,$D2
+ vmovdqa $D3,-0x70(%r11)
+ vmovdqa $D2,0x20(%rsp)
+ vpshufd \$0xEE,$D0,$D4
+ vmovdqu `16*5-64`($ctx),$D2
+ vpshufd \$0x44,$D0,$D0
+ vmovdqa $D4,-0x60(%r11)
+ vmovdqa $D0,0x30(%rsp)
+ vpshufd \$0xEE,$D1,$D3
+ vmovdqu `16*6-64`($ctx),$D0
+ vpshufd \$0x44,$D1,$D1
+ vmovdqa $D3,-0x50(%r11)
+ vmovdqa $D1,0x40(%rsp)
+ vpshufd \$0xEE,$D2,$D4
+ vmovdqu `16*7-64`($ctx),$D1
+ vpshufd \$0x44,$D2,$D2
+ vmovdqa $D4,-0x40(%r11)
+ vmovdqa $D2,0x50(%rsp)
+ vpshufd \$0xEE,$D0,$D3
+ vmovdqu `16*8-64`($ctx),$D2
+ vpshufd \$0x44,$D0,$D0
+ vmovdqa $D3,-0x30(%r11)
+ vmovdqa $D0,0x60(%rsp)
+ vpshufd \$0xEE,$D1,$D4
+ vpshufd \$0x44,$D1,$D1
+ vmovdqa $D4,-0x20(%r11)
+ vmovdqa $D1,0x70(%rsp)
+ vpshufd \$0xEE,$D2,$D3
+ vmovdqa 0x00(%rsp),$D4 # preload r0^2
+ vpshufd \$0x44,$D2,$D2
+ vmovdqa $D3,-0x10(%r11)
+ vmovdqa $D2,0x80(%rsp)
+
+ jmp .Loop_avx
+
+.align 32
+.Loop_avx:
+ ################################################################
+ # ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2
+ # ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^3+inp[7]*r
+ # \___________________/
+ # ((inp[0]*r^4+inp[2]*r^2+inp[4])*r^4+inp[6]*r^2+inp[8])*r^2
+ # ((inp[1]*r^4+inp[3]*r^2+inp[5])*r^4+inp[7]*r^2+inp[9])*r
+ # \___________________/ \____________________/
+ #
+ # Note that we start with inp[2:3]*r^2. This is because it
+ # doesn't depend on reduction in previous iteration.
+ ################################################################
+ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4
+ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4
+ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4
+ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4
+ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
+ #
+ # though note that $Tx and $Hx are "reversed" in this section,
+ # and $D4 is preloaded with r0^2...
+
+ vpmuludq $T0,$D4,$D0 # d0 = h0*r0
+ vpmuludq $T1,$D4,$D1 # d1 = h1*r0
+ vmovdqa $H2,0x20(%r11) # offload hash
+ vpmuludq $T2,$D4,$D2 # d3 = h2*r0
+ vmovdqa 0x10(%rsp),$H2 # r1^2
+ vpmuludq $T3,$D4,$D3 # d3 = h3*r0
+ vpmuludq $T4,$D4,$D4 # d4 = h4*r0
+
+ vmovdqa $H0,0x00(%r11) #
+ vpmuludq 0x20(%rsp),$T4,$H0 # h4*s1
+ vmovdqa $H1,0x10(%r11) #
+ vpmuludq $T3,$H2,$H1 # h3*r1
+ vpaddq $H0,$D0,$D0 # d0 += h4*s1
+ vpaddq $H1,$D4,$D4 # d4 += h3*r1
+ vmovdqa $H3,0x30(%r11) #
+ vpmuludq $T2,$H2,$H0 # h2*r1
+ vpmuludq $T1,$H2,$H1 # h1*r1
+ vpaddq $H0,$D3,$D3 # d3 += h2*r1
+ vmovdqa 0x30(%rsp),$H3 # r2^2
+ vpaddq $H1,$D2,$D2 # d2 += h1*r1
+ vmovdqa $H4,0x40(%r11) #
+ vpmuludq $T0,$H2,$H2 # h0*r1
+ vpmuludq $T2,$H3,$H0 # h2*r2
+ vpaddq $H2,$D1,$D1 # d1 += h0*r1
+
+ vmovdqa 0x40(%rsp),$H4 # s2^2
+ vpaddq $H0,$D4,$D4 # d4 += h2*r2
+ vpmuludq $T1,$H3,$H1 # h1*r2
+ vpmuludq $T0,$H3,$H3 # h0*r2
+ vpaddq $H1,$D3,$D3 # d3 += h1*r2
+ vmovdqa 0x50(%rsp),$H2 # r3^2
+ vpaddq $H3,$D2,$D2 # d2 += h0*r2
+ vpmuludq $T4,$H4,$H0 # h4*s2
+ vpmuludq $T3,$H4,$H4 # h3*s2
+ vpaddq $H0,$D1,$D1 # d1 += h4*s2
+ vmovdqa 0x60(%rsp),$H3 # s3^2
+ vpaddq $H4,$D0,$D0 # d0 += h3*s2
+
+ vmovdqa 0x80(%rsp),$H4 # s4^2
+ vpmuludq $T1,$H2,$H1 # h1*r3
+ vpmuludq $T0,$H2,$H2 # h0*r3
+ vpaddq $H1,$D4,$D4 # d4 += h1*r3
+ vpaddq $H2,$D3,$D3 # d3 += h0*r3
+ vpmuludq $T4,$H3,$H0 # h4*s3
+ vpmuludq $T3,$H3,$H1 # h3*s3
+ vpaddq $H0,$D2,$D2 # d2 += h4*s3
+ vmovdqu 16*0($inp),$H0 # load input
+ vpaddq $H1,$D1,$D1 # d1 += h3*s3
+ vpmuludq $T2,$H3,$H3 # h2*s3
+ vpmuludq $T2,$H4,$T2 # h2*s4
+ vpaddq $H3,$D0,$D0 # d0 += h2*s3
+
+ vmovdqu 16*1($inp),$H1 #
+ vpaddq $T2,$D1,$D1 # d1 += h2*s4
+ vpmuludq $T3,$H4,$T3 # h3*s4
+ vpmuludq $T4,$H4,$T4 # h4*s4
+ vpsrldq \$6,$H0,$H2 # splat input
+ vpaddq $T3,$D2,$D2 # d2 += h3*s4
+ vpaddq $T4,$D3,$D3 # d3 += h4*s4
+ vpsrldq \$6,$H1,$H3 #
+ vpmuludq 0x70(%rsp),$T0,$T4 # h0*r4
+ vpmuludq $T1,$H4,$T0 # h1*s4
+ vpunpckhqdq $H1,$H0,$H4 # 4
+ vpaddq $T4,$D4,$D4 # d4 += h0*r4
+ vmovdqa -0x90(%r11),$T4 # r0^4
+ vpaddq $T0,$D0,$D0 # d0 += h1*s4
+
+ vpunpcklqdq $H1,$H0,$H0 # 0:1
+ vpunpcklqdq $H3,$H2,$H3 # 2:3
+
+ #vpsrlq \$40,$H4,$H4 # 4
+ vpsrldq \$`40/8`,$H4,$H4 # 4
+ vpsrlq \$26,$H0,$H1
+ vpand $MASK,$H0,$H0 # 0
+ vpsrlq \$4,$H3,$H2
+ vpand $MASK,$H1,$H1 # 1
+ vpand 0(%rcx),$H4,$H4 # .Lmask24
+ vpsrlq \$30,$H3,$H3
+ vpand $MASK,$H2,$H2 # 2
+ vpand $MASK,$H3,$H3 # 3
+ vpor 32(%rcx),$H4,$H4 # padbit, yes, always
+
+ vpaddq 0x00(%r11),$H0,$H0 # add hash value
+ vpaddq 0x10(%r11),$H1,$H1
+ vpaddq 0x20(%r11),$H2,$H2
+ vpaddq 0x30(%r11),$H3,$H3
+ vpaddq 0x40(%r11),$H4,$H4
+
+ lea 16*2($inp),%rax
+ lea 16*4($inp),$inp
+ sub \$64,$len
+ cmovc %rax,$inp
+
+ ################################################################
+ # Now we accumulate (inp[0:1]+hash)*r^4
+ ################################################################
+ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4
+ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4
+ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4
+ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4
+ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
+
+ vpmuludq $H0,$T4,$T0 # h0*r0
+ vpmuludq $H1,$T4,$T1 # h1*r0
+ vpaddq $T0,$D0,$D0
+ vpaddq $T1,$D1,$D1
+ vmovdqa -0x80(%r11),$T2 # r1^4
+ vpmuludq $H2,$T4,$T0 # h2*r0
+ vpmuludq $H3,$T4,$T1 # h3*r0
+ vpaddq $T0,$D2,$D2
+ vpaddq $T1,$D3,$D3
+ vpmuludq $H4,$T4,$T4 # h4*r0
+ vpmuludq -0x70(%r11),$H4,$T0 # h4*s1
+ vpaddq $T4,$D4,$D4
+
+ vpaddq $T0,$D0,$D0 # d0 += h4*s1
+ vpmuludq $H2,$T2,$T1 # h2*r1
+ vpmuludq $H3,$T2,$T0 # h3*r1
+ vpaddq $T1,$D3,$D3 # d3 += h2*r1
+ vmovdqa -0x60(%r11),$T3 # r2^4
+ vpaddq $T0,$D4,$D4 # d4 += h3*r1
+ vpmuludq $H1,$T2,$T1 # h1*r1
+ vpmuludq $H0,$T2,$T2 # h0*r1
+ vpaddq $T1,$D2,$D2 # d2 += h1*r1
+ vpaddq $T2,$D1,$D1 # d1 += h0*r1
+
+ vmovdqa -0x50(%r11),$T4 # s2^4
+ vpmuludq $H2,$T3,$T0 # h2*r2
+ vpmuludq $H1,$T3,$T1 # h1*r2
+ vpaddq $T0,$D4,$D4 # d4 += h2*r2
+ vpaddq $T1,$D3,$D3 # d3 += h1*r2
+ vmovdqa -0x40(%r11),$T2 # r3^4
+ vpmuludq $H0,$T3,$T3 # h0*r2
+ vpmuludq $H4,$T4,$T0 # h4*s2
+ vpaddq $T3,$D2,$D2 # d2 += h0*r2
+ vpaddq $T0,$D1,$D1 # d1 += h4*s2
+ vmovdqa -0x30(%r11),$T3 # s3^4
+ vpmuludq $H3,$T4,$T4 # h3*s2
+ vpmuludq $H1,$T2,$T1 # h1*r3
+ vpaddq $T4,$D0,$D0 # d0 += h3*s2
+
+ vmovdqa -0x10(%r11),$T4 # s4^4
+ vpaddq $T1,$D4,$D4 # d4 += h1*r3
+ vpmuludq $H0,$T2,$T2 # h0*r3
+ vpmuludq $H4,$T3,$T0 # h4*s3
+ vpaddq $T2,$D3,$D3 # d3 += h0*r3
+ vpaddq $T0,$D2,$D2 # d2 += h4*s3
+ vmovdqu 16*2($inp),$T0 # load input
+ vpmuludq $H3,$T3,$T2 # h3*s3
+ vpmuludq $H2,$T3,$T3 # h2*s3
+ vpaddq $T2,$D1,$D1 # d1 += h3*s3
+ vmovdqu 16*3($inp),$T1 #
+ vpaddq $T3,$D0,$D0 # d0 += h2*s3
+
+ vpmuludq $H2,$T4,$H2 # h2*s4
+ vpmuludq $H3,$T4,$H3 # h3*s4
+ vpsrldq \$6,$T0,$T2 # splat input
+ vpaddq $H2,$D1,$D1 # d1 += h2*s4
+ vpmuludq $H4,$T4,$H4 # h4*s4
+ vpsrldq \$6,$T1,$T3 #
+ vpaddq $H3,$D2,$H2 # h2 = d2 + h3*s4
+ vpaddq $H4,$D3,$H3 # h3 = d3 + h4*s4
+ vpmuludq -0x20(%r11),$H0,$H4 # h0*r4
+ vpmuludq $H1,$T4,$H0
+ vpunpckhqdq $T1,$T0,$T4 # 4
+ vpaddq $H4,$D4,$H4 # h4 = d4 + h0*r4
+ vpaddq $H0,$D0,$H0 # h0 = d0 + h1*s4
+
+ vpunpcklqdq $T1,$T0,$T0 # 0:1
+ vpunpcklqdq $T3,$T2,$T3 # 2:3
+
+ #vpsrlq \$40,$T4,$T4 # 4
+ vpsrldq \$`40/8`,$T4,$T4 # 4
+ vpsrlq \$26,$T0,$T1
+ vmovdqa 0x00(%rsp),$D4 # preload r0^2
+ vpand $MASK,$T0,$T0 # 0
+ vpsrlq \$4,$T3,$T2
+ vpand $MASK,$T1,$T1 # 1
+ vpand 0(%rcx),$T4,$T4 # .Lmask24
+ vpsrlq \$30,$T3,$T3
+ vpand $MASK,$T2,$T2 # 2
+ vpand $MASK,$T3,$T3 # 3
+ vpor 32(%rcx),$T4,$T4 # padbit, yes, always
+
+ ################################################################
+ # lazy reduction as discussed in "NEON crypto" by D.J. Bernstein
+ # and P. Schwabe
+
+ vpsrlq \$26,$H3,$D3
+ vpand $MASK,$H3,$H3
+ vpaddq $D3,$H4,$H4 # h3 -> h4
+
+ vpsrlq \$26,$H0,$D0
+ vpand $MASK,$H0,$H0
+ vpaddq $D0,$D1,$H1 # h0 -> h1
+
+ vpsrlq \$26,$H4,$D0
+ vpand $MASK,$H4,$H4
+
+ vpsrlq \$26,$H1,$D1
+ vpand $MASK,$H1,$H1
+ vpaddq $D1,$H2,$H2 # h1 -> h2
+
+ vpaddq $D0,$H0,$H0
+ vpsllq \$2,$D0,$D0
+ vpaddq $D0,$H0,$H0 # h4 -> h0
+
+ vpsrlq \$26,$H2,$D2
+ vpand $MASK,$H2,$H2
+ vpaddq $D2,$H3,$H3 # h2 -> h3
+
+ vpsrlq \$26,$H0,$D0
+ vpand $MASK,$H0,$H0
+ vpaddq $D0,$H1,$H1 # h0 -> h1
+
+ vpsrlq \$26,$H3,$D3
+ vpand $MASK,$H3,$H3
+ vpaddq $D3,$H4,$H4 # h3 -> h4
+
+ ja .Loop_avx
+
+.Lskip_loop_avx:
+ ################################################################
+ # multiply (inp[0:1]+hash) or inp[2:3] by r^2:r^1
+
+ vpshufd \$0x10,$D4,$D4 # r0^n, xx12 -> x1x2
+ add \$32,$len
+ jnz .Long_tail_avx
+
+ vpaddq $H2,$T2,$T2
+ vpaddq $H0,$T0,$T0
+ vpaddq $H1,$T1,$T1
+ vpaddq $H3,$T3,$T3
+ vpaddq $H4,$T4,$T4
+
+.Long_tail_avx:
+ vmovdqa $H2,0x20(%r11)
+ vmovdqa $H0,0x00(%r11)
+ vmovdqa $H1,0x10(%r11)
+ vmovdqa $H3,0x30(%r11)
+ vmovdqa $H4,0x40(%r11)
+
+ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4
+ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4
+ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4
+ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4
+ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
+
+ vpmuludq $T2,$D4,$D2 # d2 = h2*r0
+ vpmuludq $T0,$D4,$D0 # d0 = h0*r0
+ vpshufd \$0x10,`16*1-64`($ctx),$H2 # r1^n
+ vpmuludq $T1,$D4,$D1 # d1 = h1*r0
+ vpmuludq $T3,$D4,$D3 # d3 = h3*r0
+ vpmuludq $T4,$D4,$D4 # d4 = h4*r0
+
+ vpmuludq $T3,$H2,$H0 # h3*r1
+ vpaddq $H0,$D4,$D4 # d4 += h3*r1
+ vpshufd \$0x10,`16*2-64`($ctx),$H3 # s1^n
+ vpmuludq $T2,$H2,$H1 # h2*r1
+ vpaddq $H1,$D3,$D3 # d3 += h2*r1
+ vpshufd \$0x10,`16*3-64`($ctx),$H4 # r2^n
+ vpmuludq $T1,$H2,$H0 # h1*r1
+ vpaddq $H0,$D2,$D2 # d2 += h1*r1
+ vpmuludq $T0,$H2,$H2 # h0*r1
+ vpaddq $H2,$D1,$D1 # d1 += h0*r1
+ vpmuludq $T4,$H3,$H3 # h4*s1
+ vpaddq $H3,$D0,$D0 # d0 += h4*s1
+
+ vpshufd \$0x10,`16*4-64`($ctx),$H2 # s2^n
+ vpmuludq $T2,$H4,$H1 # h2*r2
+ vpaddq $H1,$D4,$D4 # d4 += h2*r2
+ vpmuludq $T1,$H4,$H0 # h1*r2
+ vpaddq $H0,$D3,$D3 # d3 += h1*r2
+ vpshufd \$0x10,`16*5-64`($ctx),$H3 # r3^n
+ vpmuludq $T0,$H4,$H4 # h0*r2
+ vpaddq $H4,$D2,$D2 # d2 += h0*r2
+ vpmuludq $T4,$H2,$H1 # h4*s2
+ vpaddq $H1,$D1,$D1 # d1 += h4*s2
+ vpshufd \$0x10,`16*6-64`($ctx),$H4 # s3^n
+ vpmuludq $T3,$H2,$H2 # h3*s2
+ vpaddq $H2,$D0,$D0 # d0 += h3*s2
+
+ vpmuludq $T1,$H3,$H0 # h1*r3
+ vpaddq $H0,$D4,$D4 # d4 += h1*r3
+ vpmuludq $T0,$H3,$H3 # h0*r3
+ vpaddq $H3,$D3,$D3 # d3 += h0*r3
+ vpshufd \$0x10,`16*7-64`($ctx),$H2 # r4^n
+ vpmuludq $T4,$H4,$H1 # h4*s3
+ vpaddq $H1,$D2,$D2 # d2 += h4*s3
+ vpshufd \$0x10,`16*8-64`($ctx),$H3 # s4^n
+ vpmuludq $T3,$H4,$H0 # h3*s3
+ vpaddq $H0,$D1,$D1 # d1 += h3*s3
+ vpmuludq $T2,$H4,$H4 # h2*s3
+ vpaddq $H4,$D0,$D0 # d0 += h2*s3
+
+ vpmuludq $T0,$H2,$H2 # h0*r4
+ vpaddq $H2,$D4,$D4 # h4 = d4 + h0*r4
+ vpmuludq $T4,$H3,$H1 # h4*s4
+ vpaddq $H1,$D3,$D3 # h3 = d3 + h4*s4
+ vpmuludq $T3,$H3,$H0 # h3*s4
+ vpaddq $H0,$D2,$D2 # h2 = d2 + h3*s4
+ vpmuludq $T2,$H3,$H1 # h2*s4
+ vpaddq $H1,$D1,$D1 # h1 = d1 + h2*s4
+ vpmuludq $T1,$H3,$H3 # h1*s4
+ vpaddq $H3,$D0,$D0 # h0 = d0 + h1*s4
+
+ jz .Lshort_tail_avx
+
+ vmovdqu 16*0($inp),$H0 # load input
+ vmovdqu 16*1($inp),$H1
+
+ vpsrldq \$6,$H0,$H2 # splat input
+ vpsrldq \$6,$H1,$H3
+ vpunpckhqdq $H1,$H0,$H4 # 4
+ vpunpcklqdq $H1,$H0,$H0 # 0:1
+ vpunpcklqdq $H3,$H2,$H3 # 2:3
+
+ vpsrlq \$40,$H4,$H4 # 4
+ vpsrlq \$26,$H0,$H1
+ vpand $MASK,$H0,$H0 # 0
+ vpsrlq \$4,$H3,$H2
+ vpand $MASK,$H1,$H1 # 1
+ vpsrlq \$30,$H3,$H3
+ vpand $MASK,$H2,$H2 # 2
+ vpand $MASK,$H3,$H3 # 3
+ vpor 32(%rcx),$H4,$H4 # padbit, yes, always
+
+ vpshufd \$0x32,`16*0-64`($ctx),$T4 # r0^n, 34xx -> x3x4
+ vpaddq 0x00(%r11),$H0,$H0
+ vpaddq 0x10(%r11),$H1,$H1
+ vpaddq 0x20(%r11),$H2,$H2
+ vpaddq 0x30(%r11),$H3,$H3
+ vpaddq 0x40(%r11),$H4,$H4
+
+ ################################################################
+ # multiply (inp[0:1]+hash) by r^4:r^3 and accumulate
+
+ vpmuludq $H0,$T4,$T0 # h0*r0
+ vpaddq $T0,$D0,$D0 # d0 += h0*r0
+ vpmuludq $H1,$T4,$T1 # h1*r0
+ vpaddq $T1,$D1,$D1 # d1 += h1*r0
+ vpmuludq $H2,$T4,$T0 # h2*r0
+ vpaddq $T0,$D2,$D2 # d2 += h2*r0
+ vpshufd \$0x32,`16*1-64`($ctx),$T2 # r1^n
+ vpmuludq $H3,$T4,$T1 # h3*r0
+ vpaddq $T1,$D3,$D3 # d3 += h3*r0
+ vpmuludq $H4,$T4,$T4 # h4*r0
+ vpaddq $T4,$D4,$D4 # d4 += h4*r0
+
+ vpmuludq $H3,$T2,$T0 # h3*r1
+ vpaddq $T0,$D4,$D4 # d4 += h3*r1
+ vpshufd \$0x32,`16*2-64`($ctx),$T3 # s1
+ vpmuludq $H2,$T2,$T1 # h2*r1
+ vpaddq $T1,$D3,$D3 # d3 += h2*r1
+ vpshufd \$0x32,`16*3-64`($ctx),$T4 # r2
+ vpmuludq $H1,$T2,$T0 # h1*r1
+ vpaddq $T0,$D2,$D2 # d2 += h1*r1
+ vpmuludq $H0,$T2,$T2 # h0*r1
+ vpaddq $T2,$D1,$D1 # d1 += h0*r1
+ vpmuludq $H4,$T3,$T3 # h4*s1
+ vpaddq $T3,$D0,$D0 # d0 += h4*s1
+
+ vpshufd \$0x32,`16*4-64`($ctx),$T2 # s2
+ vpmuludq $H2,$T4,$T1 # h2*r2
+ vpaddq $T1,$D4,$D4 # d4 += h2*r2
+ vpmuludq $H1,$T4,$T0 # h1*r2
+ vpaddq $T0,$D3,$D3 # d3 += h1*r2
+ vpshufd \$0x32,`16*5-64`($ctx),$T3 # r3
+ vpmuludq $H0,$T4,$T4 # h0*r2
+ vpaddq $T4,$D2,$D2 # d2 += h0*r2
+ vpmuludq $H4,$T2,$T1 # h4*s2
+ vpaddq $T1,$D1,$D1 # d1 += h4*s2
+ vpshufd \$0x32,`16*6-64`($ctx),$T4 # s3
+ vpmuludq $H3,$T2,$T2 # h3*s2
+ vpaddq $T2,$D0,$D0 # d0 += h3*s2
+
+ vpmuludq $H1,$T3,$T0 # h1*r3
+ vpaddq $T0,$D4,$D4 # d4 += h1*r3
+ vpmuludq $H0,$T3,$T3 # h0*r3
+ vpaddq $T3,$D3,$D3 # d3 += h0*r3
+ vpshufd \$0x32,`16*7-64`($ctx),$T2 # r4
+ vpmuludq $H4,$T4,$T1 # h4*s3
+ vpaddq $T1,$D2,$D2 # d2 += h4*s3
+ vpshufd \$0x32,`16*8-64`($ctx),$T3 # s4
+ vpmuludq $H3,$T4,$T0 # h3*s3
+ vpaddq $T0,$D1,$D1 # d1 += h3*s3
+ vpmuludq $H2,$T4,$T4 # h2*s3
+ vpaddq $T4,$D0,$D0 # d0 += h2*s3
+
+ vpmuludq $H0,$T2,$T2 # h0*r4
+ vpaddq $T2,$D4,$D4 # d4 += h0*r4
+ vpmuludq $H4,$T3,$T1 # h4*s4
+ vpaddq $T1,$D3,$D3 # d3 += h4*s4
+ vpmuludq $H3,$T3,$T0 # h3*s4
+ vpaddq $T0,$D2,$D2 # d2 += h3*s4
+ vpmuludq $H2,$T3,$T1 # h2*s4
+ vpaddq $T1,$D1,$D1 # d1 += h2*s4
+ vpmuludq $H1,$T3,$T3 # h1*s4
+ vpaddq $T3,$D0,$D0 # d0 += h1*s4
+
+.Lshort_tail_avx:
+ ################################################################
+ # horizontal addition
+
+ vpsrldq \$8,$D4,$T4
+ vpsrldq \$8,$D3,$T3
+ vpsrldq \$8,$D1,$T1
+ vpsrldq \$8,$D0,$T0
+ vpsrldq \$8,$D2,$T2
+ vpaddq $T3,$D3,$D3
+ vpaddq $T4,$D4,$D4
+ vpaddq $T0,$D0,$D0
+ vpaddq $T1,$D1,$D1
+ vpaddq $T2,$D2,$D2
+
+ ################################################################
+ # lazy reduction
+
+ vpsrlq \$26,$D3,$H3
+ vpand $MASK,$D3,$D3
+ vpaddq $H3,$D4,$D4 # h3 -> h4
+
+ vpsrlq \$26,$D0,$H0
+ vpand $MASK,$D0,$D0
+ vpaddq $H0,$D1,$D1 # h0 -> h1
+
+ vpsrlq \$26,$D4,$H4
+ vpand $MASK,$D4,$D4
+
+ vpsrlq \$26,$D1,$H1
+ vpand $MASK,$D1,$D1
+ vpaddq $H1,$D2,$D2 # h1 -> h2
+
+ vpaddq $H4,$D0,$D0
+ vpsllq \$2,$H4,$H4
+ vpaddq $H4,$D0,$D0 # h4 -> h0
+
+ vpsrlq \$26,$D2,$H2
+ vpand $MASK,$D2,$D2
+ vpaddq $H2,$D3,$D3 # h2 -> h3
+
+ vpsrlq \$26,$D0,$H0
+ vpand $MASK,$D0,$D0
+ vpaddq $H0,$D1,$D1 # h0 -> h1
+
+ vpsrlq \$26,$D3,$H3
+ vpand $MASK,$D3,$D3
+ vpaddq $H3,$D4,$D4 # h3 -> h4
+
+ vmovd $D0,`4*0-48-64`($ctx) # save partially reduced
+ vmovd $D1,`4*1-48-64`($ctx)
+ vmovd $D2,`4*2-48-64`($ctx)
+ vmovd $D3,`4*3-48-64`($ctx)
+ vmovd $D4,`4*4-48-64`($ctx)
+___
+$code.=<<___ if ($win64);
+ vmovdqa 0x50(%r11),%xmm6
+ vmovdqa 0x60(%r11),%xmm7
+ vmovdqa 0x70(%r11),%xmm8
+ vmovdqa 0x80(%r11),%xmm9
+ vmovdqa 0x90(%r11),%xmm10
+ vmovdqa 0xa0(%r11),%xmm11
+ vmovdqa 0xb0(%r11),%xmm12
+ vmovdqa 0xc0(%r11),%xmm13
+ vmovdqa 0xd0(%r11),%xmm14
+ vmovdqa 0xe0(%r11),%xmm15
+ lea 0xf8(%r11),%rsp
+.Ldo_avx_epilogue:
+___
+$code.=<<___ if (!$win64);
+ lea 0x58(%r11),%rsp
+___
+$code.=<<___;
+ vzeroupper
+ ret
+.size poly1305_blocks_avx,.-poly1305_blocks_avx
+
+.type poly1305_emit_avx,\@function,3
+.align 32
+poly1305_emit_avx:
+ cmpl \$0,20($ctx) # is_base2_26?
+ je .Lemit
+
+ mov 0($ctx),%eax # load hash value base 2^26
+ mov 4($ctx),%ecx
+ mov 8($ctx),%r8d
+ mov 12($ctx),%r11d
+ mov 16($ctx),%r10d
+
+ shl \$26,%rcx # base 2^26 -> base 2^64
+ mov %r8,%r9
+ shl \$52,%r8
+ add %rcx,%rax
+ shr \$12,%r9
+ add %rax,%r8 # h0
+ adc \$0,%r9
+
+ shl \$14,%r11
+ mov %r10,%rax
+ shr \$24,%r10
+ add %r11,%r9
+ shl \$40,%rax
+ add %rax,%r9 # h1
+ adc \$0,%r10 # h2
+
+ mov %r10,%rax # could be partially reduced, so reduce
+ mov %r10,%rcx
+ and \$3,%r10
+ shr \$2,%rax
+ and \$-4,%rcx
+ add %rcx,%rax
+ add %rax,%r8
+ adc \$0,%r9
+
+ mov %r8,%rax
+ add \$5,%r8 # compare to modulus
+ mov %r9,%rcx
+ adc \$0,%r9
+ adc \$0,%r10
+ shr \$2,%r10 # did 130-bit value overfow?
+ cmovnz %r8,%rax
+ cmovnz %r9,%rcx
+
+ add 0($nonce),%rax # accumulate nonce
+ adc 8($nonce),%rcx
+ mov %rax,0($mac) # write result
+ mov %rcx,8($mac)
+
+ ret
+.size poly1305_emit_avx,.-poly1305_emit_avx
+___
+
+if ($avx>1) {
+my ($H0,$H1,$H2,$H3,$H4, $MASK, $T4,$T0,$T1,$T2,$T3, $D0,$D1,$D2,$D3,$D4) =
+ map("%ymm$_",(0..15));
+my $S4=$MASK;
+
+$code.=<<___;
+.type poly1305_blocks_avx2,\@function,4
+.align 32
+poly1305_blocks_avx2:
+ mov 20($ctx),%r8d # is_base2_26
+ cmp \$128,$len
+ jae .Lblocks_avx2
+ test %r8d,%r8d
+ jz .Lblocks
+
+.Lblocks_avx2:
+ and \$-16,$len
+ jz .Lno_data_avx2
+
+ vzeroupper
+
+ test %r8d,%r8d
+ jz .Lbase2_64_avx2
+
+ test \$63,$len
+ jz .Leven_avx2
+
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+.Lblocks_avx2_body:
+
+ mov $len,%r15 # reassign $len
+
+ mov 0($ctx),$d1 # load hash value
+ mov 8($ctx),$d2
+ mov 16($ctx),$h2#d
+
+ mov 24($ctx),$r0 # load r
+ mov 32($ctx),$s1
+
+ ################################# base 2^26 -> base 2^64
+ mov $d1#d,$h0#d
+ and \$-1<<31,$d1
+ mov $d2,$r1 # borrow $r1
+ mov $d2#d,$h1#d
+ and \$-1<<31,$d2
+
+ shr \$6,$d1
+ shl \$52,$r1
+ add $d1,$h0
+ shr \$12,$h1
+ shr \$18,$d2
+ add $r1,$h0
+ adc $d2,$h1
+
+ mov $h2,$d1
+ shl \$40,$d1
+ shr \$24,$h2
+ add $d1,$h1
+ adc \$0,$h2 # can be partially reduced...
+
+ mov \$-4,$d2 # ... so reduce
+ mov $h2,$d1
+ and $h2,$d2
+ shr \$2,$d1
+ and \$3,$h2
+ add $d2,$d1 # =*5
+ add $d1,$h0
+ adc \$0,$h1
+
+ mov $s1,$r1
+ mov $s1,%rax
+ shr \$2,$s1
+ add $r1,$s1 # s1 = r1 + (r1 >> 2)
+
+.Lbase2_26_pre_avx2:
+ add 0($inp),$h0 # accumulate input
+ adc 8($inp),$h1
+ lea 16($inp),$inp
+ adc $padbit,$h2
+ sub \$16,%r15
+
+ call __poly1305_block
+ mov $r1,%rax
+
+ test \$63,%r15
+ jnz .Lbase2_26_pre_avx2
+
+ test $padbit,$padbit # if $padbit is zero,
+ jz .Lstore_base2_64_avx2 # store hash in base 2^64 format
+
+ ################################# base 2^64 -> base 2^26
+ mov $h0,%rax
+ mov $h0,%rdx
+ shr \$52,$h0
+ mov $h1,$r0
+ mov $h1,$r1
+ shr \$26,%rdx
+ and \$0x3ffffff,%rax # h[0]
+ shl \$12,$r0
+ and \$0x3ffffff,%rdx # h[1]
+ shr \$14,$h1
+ or $r0,$h0
+ shl \$24,$h2
+ and \$0x3ffffff,$h0 # h[2]
+ shr \$40,$r1
+ and \$0x3ffffff,$h1 # h[3]
+ or $r1,$h2 # h[4]
+
+ test %r15,%r15
+ jz .Lstore_base2_26_avx2
+
+ vmovd %rax#d,%x#$H0
+ vmovd %rdx#d,%x#$H1
+ vmovd $h0#d,%x#$H2
+ vmovd $h1#d,%x#$H3
+ vmovd $h2#d,%x#$H4
+ jmp .Lproceed_avx2
+
+.align 32
+.Lstore_base2_64_avx2:
+ mov $h0,0($ctx)
+ mov $h1,8($ctx)
+ mov $h2,16($ctx) # note that is_base2_26 is zeroed
+ jmp .Ldone_avx2
+
+.align 16
+.Lstore_base2_26_avx2:
+ mov %rax#d,0($ctx) # store hash value base 2^26
+ mov %rdx#d,4($ctx)
+ mov $h0#d,8($ctx)
+ mov $h1#d,12($ctx)
+ mov $h2#d,16($ctx)
+.align 16
+.Ldone_avx2:
+ mov 0(%rsp),%r15
+ mov 8(%rsp),%r14
+ mov 16(%rsp),%r13
+ mov 24(%rsp),%r12
+ mov 32(%rsp),%rbp
+ mov 40(%rsp),%rbx
+ lea 48(%rsp),%rsp
+.Lno_data_avx2:
+.Lblocks_avx2_epilogue:
+ ret
+
+.align 32
+.Lbase2_64_avx2:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+.Lbase2_64_avx2_body:
+
+ mov $len,%r15 # reassign $len
+
+ mov 24($ctx),$r0 # load r
+ mov 32($ctx),$s1
+
+ mov 0($ctx),$h0 # load hash value
+ mov 8($ctx),$h1
+ mov 16($ctx),$h2#d
+
+ mov $s1,$r1
+ mov $s1,%rax
+ shr \$2,$s1
+ add $r1,$s1 # s1 = r1 + (r1 >> 2)
+
+ test \$63,$len
+ jz .Linit_avx2
+
+.Lbase2_64_pre_avx2:
+ add 0($inp),$h0 # accumulate input
+ adc 8($inp),$h1
+ lea 16($inp),$inp
+ adc $padbit,$h2
+ sub \$16,%r15
+
+ call __poly1305_block
+ mov $r1,%rax
+
+ test \$63,%r15
+ jnz .Lbase2_64_pre_avx2
+
+.Linit_avx2:
+ ################################# base 2^64 -> base 2^26
+ mov $h0,%rax
+ mov $h0,%rdx
+ shr \$52,$h0
+ mov $h1,$d1
+ mov $h1,$d2
+ shr \$26,%rdx
+ and \$0x3ffffff,%rax # h[0]
+ shl \$12,$d1
+ and \$0x3ffffff,%rdx # h[1]
+ shr \$14,$h1
+ or $d1,$h0
+ shl \$24,$h2
+ and \$0x3ffffff,$h0 # h[2]
+ shr \$40,$d2
+ and \$0x3ffffff,$h1 # h[3]
+ or $d2,$h2 # h[4]
+
+ vmovd %rax#d,%x#$H0
+ vmovd %rdx#d,%x#$H1
+ vmovd $h0#d,%x#$H2
+ vmovd $h1#d,%x#$H3
+ vmovd $h2#d,%x#$H4
+ movl \$1,20($ctx) # set is_base2_26
+
+ call __poly1305_init_avx
+
+.Lproceed_avx2:
+ mov %r15,$len
+
+ mov 0(%rsp),%r15
+ mov 8(%rsp),%r14
+ mov 16(%rsp),%r13
+ mov 24(%rsp),%r12
+ mov 32(%rsp),%rbp
+ mov 40(%rsp),%rbx
+ lea 48(%rsp),%rax
+ lea 48(%rsp),%rsp
+.Lbase2_64_avx2_epilogue:
+ jmp .Ldo_avx2
+
+.align 32
+.Leven_avx2:
+ vmovd 4*0($ctx),%x#$H0 # load hash value base 2^26
+ vmovd 4*1($ctx),%x#$H1
+ vmovd 4*2($ctx),%x#$H2
+ vmovd 4*3($ctx),%x#$H3
+ vmovd 4*4($ctx),%x#$H4
+
+.Ldo_avx2:
+___
+$code.=<<___ if (!$win64);
+ lea -8(%rsp),%r11
+ sub \$0x128,%rsp
+___
+$code.=<<___ if ($win64);
+ lea -0xf8(%rsp),%r11
+ sub \$0x1c8,%rsp
+ vmovdqa %xmm6,0x50(%r11)
+ vmovdqa %xmm7,0x60(%r11)
+ vmovdqa %xmm8,0x70(%r11)
+ vmovdqa %xmm9,0x80(%r11)
+ vmovdqa %xmm10,0x90(%r11)
+ vmovdqa %xmm11,0xa0(%r11)
+ vmovdqa %xmm12,0xb0(%r11)
+ vmovdqa %xmm13,0xc0(%r11)
+ vmovdqa %xmm14,0xd0(%r11)
+ vmovdqa %xmm15,0xe0(%r11)
+.Ldo_avx2_body:
+___
+$code.=<<___;
+ lea 48+64($ctx),$ctx # size optimization
+ lea .Lconst(%rip),%rcx
+
+ # expand and copy pre-calculated table to stack
+ vmovdqu `16*0-64`($ctx),%x#$T2
+ and \$-512,%rsp
+ vmovdqu `16*1-64`($ctx),%x#$T3
+ vmovdqu `16*2-64`($ctx),%x#$T4
+ vmovdqu `16*3-64`($ctx),%x#$D0
+ vmovdqu `16*4-64`($ctx),%x#$D1
+ vmovdqu `16*5-64`($ctx),%x#$D2
+ vmovdqu `16*6-64`($ctx),%x#$D3
+ vpermq \$0x15,$T2,$T2 # 00003412 -> 12343434
+ vmovdqu `16*7-64`($ctx),%x#$D4
+ vpermq \$0x15,$T3,$T3
+ vpshufd \$0xc8,$T2,$T2 # 12343434 -> 14243444
+ vmovdqu `16*8-64`($ctx),%x#$MASK
+ vpermq \$0x15,$T4,$T4
+ vpshufd \$0xc8,$T3,$T3
+ vmovdqa $T2,0x00(%rsp)
+ vpermq \$0x15,$D0,$D0
+ vpshufd \$0xc8,$T4,$T4
+ vmovdqa $T3,0x20(%rsp)
+ vpermq \$0x15,$D1,$D1
+ vpshufd \$0xc8,$D0,$D0
+ vmovdqa $T4,0x40(%rsp)
+ vpermq \$0x15,$D2,$D2
+ vpshufd \$0xc8,$D1,$D1
+ vmovdqa $D0,0x60(%rsp)
+ vpermq \$0x15,$D3,$D3
+ vpshufd \$0xc8,$D2,$D2
+ vmovdqa $D1,0x80(%rsp)
+ vpermq \$0x15,$D4,$D4
+ vpshufd \$0xc8,$D3,$D3
+ vmovdqa $D2,0xa0(%rsp)
+ vpermq \$0x15,$MASK,$MASK
+ vpshufd \$0xc8,$D4,$D4
+ vmovdqa $D3,0xc0(%rsp)
+ vpshufd \$0xc8,$MASK,$MASK
+ vmovdqa $D4,0xe0(%rsp)
+ vmovdqa $MASK,0x100(%rsp)
+ vmovdqa 64(%rcx),$MASK # .Lmask26
+
+ ################################################################
+ # load input
+ vmovdqu 16*0($inp),%x#$T0
+ vmovdqu 16*1($inp),%x#$T1
+ vinserti128 \$1,16*2($inp),$T0,$T0
+ vinserti128 \$1,16*3($inp),$T1,$T1
+ lea 16*4($inp),$inp
+
+ vpsrldq \$6,$T0,$T2 # splat input
+ vpsrldq \$6,$T1,$T3
+ vpunpckhqdq $T1,$T0,$T4 # 4
+ vpunpcklqdq $T3,$T2,$T2 # 2:3
+ vpunpcklqdq $T1,$T0,$T0 # 0:1
+
+ vpsrlq \$30,$T2,$T3
+ vpsrlq \$4,$T2,$T2
+ vpsrlq \$26,$T0,$T1
+ vpsrlq \$40,$T4,$T4 # 4
+ vpand $MASK,$T2,$T2 # 2
+ vpand $MASK,$T0,$T0 # 0
+ vpand $MASK,$T1,$T1 # 1
+ vpand $MASK,$T3,$T3 # 3
+ vpor 32(%rcx),$T4,$T4 # padbit, yes, always
+
+ lea 0x90(%rsp),%rax # size optimization
+ vpaddq $H2,$T2,$H2 # accumulate input
+ sub \$64,$len
+ jz .Ltail_avx2
+ jmp .Loop_avx2
+
+.align 32
+.Loop_avx2:
+ ################################################################
+ # ((inp[0]*r^4+r[4])*r^4+r[8])*r^4
+ # ((inp[1]*r^4+r[5])*r^4+r[9])*r^3
+ # ((inp[2]*r^4+r[6])*r^4+r[10])*r^2
+ # ((inp[3]*r^4+r[7])*r^4+r[11])*r^1
+ # \________/\________/
+ ################################################################
+ #vpaddq $H2,$T2,$H2 # accumulate input
+ vpaddq $H0,$T0,$H0
+ vmovdqa `32*0`(%rsp),$T0 # r0^4
+ vpaddq $H1,$T1,$H1
+ vmovdqa `32*1`(%rsp),$T1 # r1^4
+ vpaddq $H3,$T3,$H3
+ vmovdqa `32*3`(%rsp),$T2 # r2^4
+ vpaddq $H4,$T4,$H4
+ vmovdqa `32*6-0x90`(%rax),$T3 # s3^4
+ vmovdqa `32*8-0x90`(%rax),$S4 # s4^4
+
+ # d4 = h4*r0 + h3*r1 + h2*r2 + h1*r3 + h0*r4
+ # d3 = h3*r0 + h2*r1 + h1*r2 + h0*r3 + h4*5*r4
+ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4
+ # d1 = h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3 + h2*5*r4
+ # d0 = h0*r0 + h4*5*r1 + h3*5*r2 + h2*5*r3 + h1*5*r4
+ #
+ # however, as h2 is "chronologically" first one available pull
+ # corresponding operations up, so it's
+ #
+ # d4 = h2*r2 + h4*r0 + h3*r1 + h1*r3 + h0*r4
+ # d3 = h2*r1 + h3*r0 + h1*r2 + h0*r3 + h4*5*r4
+ # d2 = h2*r0 + h1*r1 + h0*r2 + h4*5*r3 + h3*5*r4
+ # d1 = h2*5*r4 + h1*r0 + h0*r1 + h4*5*r2 + h3*5*r3
+ # d0 = h2*5*r3 + h0*r0 + h4*5*r1 + h3*5*r2 + h1*5*r4
+
+ vpmuludq $H2,$T0,$D2 # d2 = h2*r0
+ vpmuludq $H2,$T1,$D3 # d3 = h2*r1
+ vpmuludq $H2,$T2,$D4 # d4 = h2*r2
+ vpmuludq $H2,$T3,$D0 # d0 = h2*s3
+ vpmuludq $H2,$S4,$D1 # d1 = h2*s4
+
+ vpmuludq $H0,$T1,$T4 # h0*r1
+ vpmuludq $H1,$T1,$H2 # h1*r1, borrow $H2 as temp
+ vpaddq $T4,$D1,$D1 # d1 += h0*r1
+ vpaddq $H2,$D2,$D2 # d2 += h1*r1
+ vpmuludq $H3,$T1,$T4 # h3*r1
+ vpmuludq `32*2`(%rsp),$H4,$H2 # h4*s1
+ vpaddq $T4,$D4,$D4 # d4 += h3*r1
+ vpaddq $H2,$D0,$D0 # d0 += h4*s1
+ vmovdqa `32*4-0x90`(%rax),$T1 # s2
+
+ vpmuludq $H0,$T0,$T4 # h0*r0
+ vpmuludq $H1,$T0,$H2 # h1*r0
+ vpaddq $T4,$D0,$D0 # d0 += h0*r0
+ vpaddq $H2,$D1,$D1 # d1 += h1*r0
+ vpmuludq $H3,$T0,$T4 # h3*r0
+ vpmuludq $H4,$T0,$H2 # h4*r0
+ vmovdqu 16*0($inp),%x#$T0 # load input
+ vpaddq $T4,$D3,$D3 # d3 += h3*r0
+ vpaddq $H2,$D4,$D4 # d4 += h4*r0
+ vinserti128 \$1,16*2($inp),$T0,$T0
+
+ vpmuludq $H3,$T1,$T4 # h3*s2
+ vpmuludq $H4,$T1,$H2 # h4*s2
+ vmovdqu 16*1($inp),%x#$T1
+ vpaddq $T4,$D0,$D0 # d0 += h3*s2
+ vpaddq $H2,$D1,$D1 # d1 += h4*s2
+ vmovdqa `32*5-0x90`(%rax),$H2 # r3
+ vpmuludq $H1,$T2,$T4 # h1*r2
+ vpmuludq $H0,$T2,$T2 # h0*r2
+ vpaddq $T4,$D3,$D3 # d3 += h1*r2
+ vpaddq $T2,$D2,$D2 # d2 += h0*r2
+ vinserti128 \$1,16*3($inp),$T1,$T1
+ lea 16*4($inp),$inp
+
+ vpmuludq $H1,$H2,$T4 # h1*r3
+ vpmuludq $H0,$H2,$H2 # h0*r3
+ vpsrldq \$6,$T0,$T2 # splat input
+ vpaddq $T4,$D4,$D4 # d4 += h1*r3
+ vpaddq $H2,$D3,$D3 # d3 += h0*r3
+ vpmuludq $H3,$T3,$T4 # h3*s3
+ vpmuludq $H4,$T3,$H2 # h4*s3
+ vpsrldq \$6,$T1,$T3
+ vpaddq $T4,$D1,$D1 # d1 += h3*s3
+ vpaddq $H2,$D2,$D2 # d2 += h4*s3
+ vpunpckhqdq $T1,$T0,$T4 # 4
+
+ vpmuludq $H3,$S4,$H3 # h3*s4
+ vpmuludq $H4,$S4,$H4 # h4*s4
+ vpunpcklqdq $T1,$T0,$T0 # 0:1
+ vpaddq $H3,$D2,$H2 # h2 = d2 + h3*r4
+ vpaddq $H4,$D3,$H3 # h3 = d3 + h4*r4
+ vpunpcklqdq $T3,$T2,$T3 # 2:3
+ vpmuludq `32*7-0x90`(%rax),$H0,$H4 # h0*r4
+ vpmuludq $H1,$S4,$H0 # h1*s4
+ vmovdqa 64(%rcx),$MASK # .Lmask26
+ vpaddq $H4,$D4,$H4 # h4 = d4 + h0*r4
+ vpaddq $H0,$D0,$H0 # h0 = d0 + h1*s4
+
+ ################################################################
+ # lazy reduction (interleaved with tail of input splat)
+
+ vpsrlq \$26,$H3,$D3
+ vpand $MASK,$H3,$H3
+ vpaddq $D3,$H4,$H4 # h3 -> h4
+
+ vpsrlq \$26,$H0,$D0
+ vpand $MASK,$H0,$H0
+ vpaddq $D0,$D1,$H1 # h0 -> h1
+
+ vpsrlq \$26,$H4,$D4
+ vpand $MASK,$H4,$H4
+
+ vpsrlq \$4,$T3,$T2
+
+ vpsrlq \$26,$H1,$D1
+ vpand $MASK,$H1,$H1
+ vpaddq $D1,$H2,$H2 # h1 -> h2
+
+ vpaddq $D4,$H0,$H0
+ vpsllq \$2,$D4,$D4
+ vpaddq $D4,$H0,$H0 # h4 -> h0
+
+ vpand $MASK,$T2,$T2 # 2
+ vpsrlq \$26,$T0,$T1
+
+ vpsrlq \$26,$H2,$D2
+ vpand $MASK,$H2,$H2
+ vpaddq $D2,$H3,$H3 # h2 -> h3
+
+ vpaddq $T2,$H2,$H2 # modulo-scheduled
+ vpsrlq \$30,$T3,$T3
+
+ vpsrlq \$26,$H0,$D0
+ vpand $MASK,$H0,$H0
+ vpaddq $D0,$H1,$H1 # h0 -> h1
+
+ vpsrlq \$40,$T4,$T4 # 4
+
+ vpsrlq \$26,$H3,$D3
+ vpand $MASK,$H3,$H3
+ vpaddq $D3,$H4,$H4 # h3 -> h4
+
+ vpand $MASK,$T0,$T0 # 0
+ vpand $MASK,$T1,$T1 # 1
+ vpand $MASK,$T3,$T3 # 3
+ vpor 32(%rcx),$T4,$T4 # padbit, yes, always
+
+ sub \$64,$len
+ jnz .Loop_avx2
+
+ .byte 0x66,0x90
+.Ltail_avx2:
+ ################################################################
+ # while above multiplications were by r^4 in all lanes, in last
+ # iteration we multiply least significant lane by r^4 and most
+ # significant one by r, so copy of above except that references
+ # to the precomputed table are displaced by 4...
+
+ #vpaddq $H2,$T2,$H2 # accumulate input
+ vpaddq $H0,$T0,$H0
+ vmovdqu `32*0+4`(%rsp),$T0 # r0^4
+ vpaddq $H1,$T1,$H1
+ vmovdqu `32*1+4`(%rsp),$T1 # r1^4
+ vpaddq $H3,$T3,$H3
+ vmovdqu `32*3+4`(%rsp),$T2 # r2^4
+ vpaddq $H4,$T4,$H4
+ vmovdqu `32*6+4-0x90`(%rax),$T3 # s3^4
+ vmovdqu `32*8+4-0x90`(%rax),$S4 # s4^4
+
+ vpmuludq $H2,$T0,$D2 # d2 = h2*r0
+ vpmuludq $H2,$T1,$D3 # d3 = h2*r1
+ vpmuludq $H2,$T2,$D4 # d4 = h2*r2
+ vpmuludq $H2,$T3,$D0 # d0 = h2*s3
+ vpmuludq $H2,$S4,$D1 # d1 = h2*s4
+
+ vpmuludq $H0,$T1,$T4 # h0*r1
+ vpmuludq $H1,$T1,$H2 # h1*r1
+ vpaddq $T4,$D1,$D1 # d1 += h0*r1
+ vpaddq $H2,$D2,$D2 # d2 += h1*r1
+ vpmuludq $H3,$T1,$T4 # h3*r1
+ vpmuludq `32*2+4`(%rsp),$H4,$H2 # h4*s1
+ vpaddq $T4,$D4,$D4 # d4 += h3*r1
+ vpaddq $H2,$D0,$D0 # d0 += h4*s1
+
+ vpmuludq $H0,$T0,$T4 # h0*r0
+ vpmuludq $H1,$T0,$H2 # h1*r0
+ vpaddq $T4,$D0,$D0 # d0 += h0*r0
+ vmovdqu `32*4+4-0x90`(%rax),$T1 # s2
+ vpaddq $H2,$D1,$D1 # d1 += h1*r0
+ vpmuludq $H3,$T0,$T4 # h3*r0
+ vpmuludq $H4,$T0,$H2 # h4*r0
+ vpaddq $T4,$D3,$D3 # d3 += h3*r0
+ vpaddq $H2,$D4,$D4 # d4 += h4*r0
+
+ vpmuludq $H3,$T1,$T4 # h3*s2
+ vpmuludq $H4,$T1,$H2 # h4*s2
+ vpaddq $T4,$D0,$D0 # d0 += h3*s2
+ vpaddq $H2,$D1,$D1 # d1 += h4*s2
+ vmovdqu `32*5+4-0x90`(%rax),$H2 # r3
+ vpmuludq $H1,$T2,$T4 # h1*r2
+ vpmuludq $H0,$T2,$T2 # h0*r2
+ vpaddq $T4,$D3,$D3 # d3 += h1*r2
+ vpaddq $T2,$D2,$D2 # d2 += h0*r2
+
+ vpmuludq $H1,$H2,$T4 # h1*r3
+ vpmuludq $H0,$H2,$H2 # h0*r3
+ vpaddq $T4,$D4,$D4 # d4 += h1*r3
+ vpaddq $H2,$D3,$D3 # d3 += h0*r3
+ vpmuludq $H3,$T3,$T4 # h3*s3
+ vpmuludq $H4,$T3,$H2 # h4*s3
+ vpaddq $T4,$D1,$D1 # d1 += h3*s3
+ vpaddq $H2,$D2,$D2 # d2 += h4*s3
+
+ vpmuludq $H3,$S4,$H3 # h3*s4
+ vpmuludq $H4,$S4,$H4 # h4*s4
+ vpaddq $H3,$D2,$H2 # h2 = d2 + h3*r4
+ vpaddq $H4,$D3,$H3 # h3 = d3 + h4*r4
+ vpmuludq `32*7+4-0x90`(%rax),$H0,$H4 # h0*r4
+ vpmuludq $H1,$S4,$H0 # h1*s4
+ vmovdqa 64(%rcx),$MASK # .Lmask26
+ vpaddq $H4,$D4,$H4 # h4 = d4 + h0*r4
+ vpaddq $H0,$D0,$H0 # h0 = d0 + h1*s4
+
+ ################################################################
+ # horizontal addition
+
+ vpsrldq \$8,$D1,$T1
+ vpsrldq \$8,$H2,$T2
+ vpsrldq \$8,$H3,$T3
+ vpsrldq \$8,$H4,$T4
+ vpsrldq \$8,$H0,$T0
+ vpaddq $T1,$D1,$D1
+ vpaddq $T2,$H2,$H2
+ vpaddq $T3,$H3,$H3
+ vpaddq $T4,$H4,$H4
+ vpaddq $T0,$H0,$H0
+
+ vpermq \$0x2,$H3,$T3
+ vpermq \$0x2,$H4,$T4
+ vpermq \$0x2,$H0,$T0
+ vpermq \$0x2,$D1,$T1
+ vpermq \$0x2,$H2,$T2
+ vpaddq $T3,$H3,$H3
+ vpaddq $T4,$H4,$H4
+ vpaddq $T0,$H0,$H0
+ vpaddq $T1,$D1,$D1
+ vpaddq $T2,$H2,$H2
+
+ ################################################################
+ # lazy reduction
+
+ vpsrlq \$26,$H3,$D3
+ vpand $MASK,$H3,$H3
+ vpaddq $D3,$H4,$H4 # h3 -> h4
+
+ vpsrlq \$26,$H0,$D0
+ vpand $MASK,$H0,$H0
+ vpaddq $D0,$D1,$H1 # h0 -> h1
+
+ vpsrlq \$26,$H4,$D4
+ vpand $MASK,$H4,$H4
+
+ vpsrlq \$26,$H1,$D1
+ vpand $MASK,$H1,$H1
+ vpaddq $D1,$H2,$H2 # h1 -> h2
+
+ vpaddq $D4,$H0,$H0
+ vpsllq \$2,$D4,$D4
+ vpaddq $D4,$H0,$H0 # h4 -> h0
+
+ vpsrlq \$26,$H2,$D2
+ vpand $MASK,$H2,$H2
+ vpaddq $D2,$H3,$H3 # h2 -> h3
+
+ vpsrlq \$26,$H0,$D0
+ vpand $MASK,$H0,$H0
+ vpaddq $D0,$H1,$H1 # h0 -> h1
+
+ vpsrlq \$26,$H3,$D3
+ vpand $MASK,$H3,$H3
+ vpaddq $D3,$H4,$H4 # h3 -> h4
+
+ vmovd %x#$H0,`4*0-48-64`($ctx)# save partially reduced
+ vmovd %x#$H1,`4*1-48-64`($ctx)
+ vmovd %x#$H2,`4*2-48-64`($ctx)
+ vmovd %x#$H3,`4*3-48-64`($ctx)
+ vmovd %x#$H4,`4*4-48-64`($ctx)
+___
+$code.=<<___ if ($win64);
+ vmovdqa 0x50(%r11),%xmm6
+ vmovdqa 0x60(%r11),%xmm7
+ vmovdqa 0x70(%r11),%xmm8
+ vmovdqa 0x80(%r11),%xmm9
+ vmovdqa 0x90(%r11),%xmm10
+ vmovdqa 0xa0(%r11),%xmm11
+ vmovdqa 0xb0(%r11),%xmm12
+ vmovdqa 0xc0(%r11),%xmm13
+ vmovdqa 0xd0(%r11),%xmm14
+ vmovdqa 0xe0(%r11),%xmm15
+ lea 0xf8(%r11),%rsp
+.Ldo_avx2_epilogue:
+___
+$code.=<<___ if (!$win64);
+ lea 8(%r11),%rsp
+___
+$code.=<<___;
+ vzeroupper
+ ret
+.size poly1305_blocks_avx2,.-poly1305_blocks_avx2
+___
+}
+$code.=<<___;
+.align 64
+.Lconst:
+.Lmask24:
+.long 0x0ffffff,0,0x0ffffff,0,0x0ffffff,0,0x0ffffff,0
+.L129:
+.long 1<<24,0,1<<24,0,1<<24,0,1<<24,0
+.Lmask26:
+.long 0x3ffffff,0,0x3ffffff,0,0x3ffffff,0,0x3ffffff,0
+.Lfive:
+.long 5,0,5,0,5,0,5,0
+___
+}
+
+$code.=<<___;
+.asciz "Poly1305 for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+.align 16
+___
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type se_handler,\@abi-omnipotent
+.align 16
+se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue label
+ cmp %r10,%rbx # context->Rip<.Lprologue
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=.Lepilogue
+ jae .Lcommon_seh_tail
+
+ lea 48(%rax),%rax
+
+ mov -8(%rax),%rbx
+ mov -16(%rax),%rbp
+ mov -24(%rax),%r12
+ mov -32(%rax),%r13
+ mov -40(%rax),%r14
+ mov -48(%rax),%r15
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+ mov %r14,232($context) # restore context->R14
+ mov %r15,240($context) # restore context->R14
+
+ jmp .Lcommon_seh_tail
+.size se_handler,.-se_handler
+
+.type avx_handler,\@abi-omnipotent
+.align 16
+avx_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue label
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lcommon_seh_tail
+
+ mov 208($context),%rax # pull context->R11
+
+ lea 0x50(%rax),%rsi
+ lea 0xf8(%rax),%rax
+ lea 512($context),%rdi # &context.Xmm6
+ mov \$20,%ecx
+ .long 0xa548f3fc # cld; rep movsq
+
+.Lcommon_seh_tail:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$154,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size avx_handler,.-avx_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_poly1305_init
+ .rva .LSEH_end_poly1305_init
+ .rva .LSEH_info_poly1305_init
+
+ .rva .LSEH_begin_poly1305_blocks
+ .rva .LSEH_end_poly1305_blocks
+ .rva .LSEH_info_poly1305_blocks
+
+ .rva .LSEH_begin_poly1305_emit
+ .rva .LSEH_end_poly1305_emit
+ .rva .LSEH_info_poly1305_emit
+___
+$code.=<<___ if ($avx);
+ .rva .LSEH_begin_poly1305_blocks_avx
+ .rva .Lbase2_64_avx
+ .rva .LSEH_info_poly1305_blocks_avx_1
+
+ .rva .Lbase2_64_avx
+ .rva .Leven_avx
+ .rva .LSEH_info_poly1305_blocks_avx_2
+
+ .rva .Leven_avx
+ .rva .LSEH_end_poly1305_blocks_avx
+ .rva .LSEH_info_poly1305_blocks_avx_3
+
+ .rva .LSEH_begin_poly1305_emit_avx
+ .rva .LSEH_end_poly1305_emit_avx
+ .rva .LSEH_info_poly1305_emit_avx
+___
+$code.=<<___ if ($avx>1);
+ .rva .LSEH_begin_poly1305_blocks_avx2
+ .rva .Lbase2_64_avx2
+ .rva .LSEH_info_poly1305_blocks_avx2_1
+
+ .rva .Lbase2_64_avx2
+ .rva .Leven_avx2
+ .rva .LSEH_info_poly1305_blocks_avx2_2
+
+ .rva .Leven_avx2
+ .rva .LSEH_end_poly1305_blocks_avx2
+ .rva .LSEH_info_poly1305_blocks_avx2_3
+___
+$code.=<<___;
+.section .xdata
+.align 8
+.LSEH_info_poly1305_init:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .LSEH_begin_poly1305_init,.LSEH_begin_poly1305_init
+
+.LSEH_info_poly1305_blocks:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lblocks_body,.Lblocks_epilogue
+
+.LSEH_info_poly1305_emit:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .LSEH_begin_poly1305_emit,.LSEH_begin_poly1305_emit
+___
+$code.=<<___ if ($avx);
+.LSEH_info_poly1305_blocks_avx_1:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lblocks_avx_body,.Lblocks_avx_epilogue # HandlerData[]
+
+.LSEH_info_poly1305_blocks_avx_2:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lbase2_64_avx_body,.Lbase2_64_avx_epilogue # HandlerData[]
+
+.LSEH_info_poly1305_blocks_avx_3:
+ .byte 9,0,0,0
+ .rva avx_handler
+ .rva .Ldo_avx_body,.Ldo_avx_epilogue # HandlerData[]
+
+.LSEH_info_poly1305_emit_avx:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .LSEH_begin_poly1305_emit_avx,.LSEH_begin_poly1305_emit_avx
+___
+$code.=<<___ if ($avx>1);
+.LSEH_info_poly1305_blocks_avx2_1:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lblocks_avx2_body,.Lblocks_avx2_epilogue # HandlerData[]
+
+.LSEH_info_poly1305_blocks_avx2_2:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lbase2_64_avx2_body,.Lbase2_64_avx2_epilogue # HandlerData[]
+
+.LSEH_info_poly1305_blocks_avx2_3:
+ .byte 9,0,0,0
+ .rva avx_handler
+ .rva .Ldo_avx2_body,.Ldo_avx2_epilogue # HandlerData[]
+___
+}
+
+foreach (split('\n',$code)) {
+ s/\`([^\`]*)\`/eval($1)/ge;
+ s/%r([a-z]+)#d/%e$1/g;
+ s/%r([0-9]+)#d/%r$1d/g;
+ s/%x#%y/%x/g;
+
+ print $_,"\n";
+}
+close STDOUT;
diff --git a/crypto/poly1305/internal.h b/crypto/poly1305/internal.h
new file mode 100644
index 00000000..df6769ea
--- /dev/null
+++ b/crypto/poly1305/internal.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_POLY1305_INTERNAL_H
+#define OPENSSL_HEADER_POLY1305_INTERNAL_H
+
+#include <openssl/base.h>
+#include <openssl/poly1305.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
+void CRYPTO_poly1305_init_neon(poly1305_state *state, const uint8_t key[32]);
+
+void CRYPTO_poly1305_update_neon(poly1305_state *state, const uint8_t *in,
+ size_t in_len);
+
+void CRYPTO_poly1305_finish_neon(poly1305_state *state, uint8_t mac[16]);
+#endif
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_POLY1305_INTERNAL_H */
diff --git a/crypto/poly1305/poly1305.c b/crypto/poly1305/poly1305.c
index 5a49e2df..dc2d6a68 100644
--- a/crypto/poly1305/poly1305.c
+++ b/crypto/poly1305/poly1305.c
@@ -22,6 +22,8 @@
#include <openssl/cpu.h>
+#include "internal.h"
+
#if defined(OPENSSL_WINDOWS) || !defined(OPENSSL_X86_64)
@@ -48,15 +50,6 @@ static void U32TO8_LE(uint8_t *m, uint32_t v) {
}
#endif
-#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
-void CRYPTO_poly1305_init_neon(poly1305_state *state, const uint8_t key[32]);
-
-void CRYPTO_poly1305_update_neon(poly1305_state *state, const uint8_t *in,
- size_t in_len);
-
-void CRYPTO_poly1305_finish_neon(poly1305_state *state, uint8_t mac[16]);
-#endif
-
static uint64_t mul32x32_64(uint32_t a, uint32_t b) { return (uint64_t)a * b; }
struct poly1305_state_st {
@@ -170,7 +163,7 @@ void CRYPTO_poly1305_init(poly1305_state *statep, const uint8_t key[32]) {
uint32_t t0, t1, t2, t3;
#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
- if (CRYPTO_is_NEON_functional()) {
+ if (CRYPTO_is_NEON_capable()) {
CRYPTO_poly1305_init_neon(statep, key);
return;
}
@@ -217,7 +210,7 @@ void CRYPTO_poly1305_update(poly1305_state *statep, const uint8_t *in,
struct poly1305_state_st *state = (struct poly1305_state_st *)statep;
#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
- if (CRYPTO_is_NEON_functional()) {
+ if (CRYPTO_is_NEON_capable()) {
CRYPTO_poly1305_update_neon(statep, in, in_len);
return;
}
@@ -263,7 +256,7 @@ void CRYPTO_poly1305_finish(poly1305_state *statep, uint8_t mac[16]) {
uint32_t b, nb;
#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
- if (CRYPTO_is_NEON_functional()) {
+ if (CRYPTO_is_NEON_capable()) {
CRYPTO_poly1305_finish_neon(statep, mac);
return;
}
diff --git a/crypto/poly1305/poly1305_arm.c b/crypto/poly1305/poly1305_arm.c
index 82876e18..de31d6b2 100644
--- a/crypto/poly1305/poly1305_arm.c
+++ b/crypto/poly1305/poly1305_arm.c
@@ -22,6 +22,7 @@
#include <string.h>
#include "../internal.h"
+#include "internal.h"
typedef struct {
diff --git a/crypto/poly1305/poly1305_test.cc b/crypto/poly1305/poly1305_test.cc
index cae30a42..2c25e93b 100644
--- a/crypto/poly1305/poly1305_test.cc
+++ b/crypto/poly1305/poly1305_test.cc
@@ -24,6 +24,54 @@
#include "../test/file_test.h"
+static bool TestSIMD(FileTest *t, unsigned excess,
+ const std::vector<uint8_t> &key,
+ const std::vector<uint8_t> &in,
+ const std::vector<uint8_t> &mac) {
+ poly1305_state state;
+ CRYPTO_poly1305_init(&state, key.data());
+
+ size_t done = 0;
+
+ // Feed 16 bytes in. Some implementations begin in non-SIMD mode and upgrade
+ // on-demand. Stress the upgrade path.
+ size_t todo = 16;
+ if (todo > in.size()) {
+ todo = in.size();
+ }
+ CRYPTO_poly1305_update(&state, in.data(), todo);
+ done += todo;
+
+ for (;;) {
+ // Feed 128 + |excess| bytes to test SIMD mode.
+ if (done + 128 + excess > in.size()) {
+ break;
+ }
+ CRYPTO_poly1305_update(&state, in.data() + done, 128 + excess);
+ done += 128 + excess;
+
+ // Feed |excess| bytes to ensure SIMD mode can handle short inputs.
+ if (done + excess > in.size()) {
+ break;
+ }
+ CRYPTO_poly1305_update(&state, in.data() + done, excess);
+ done += excess;
+ }
+
+ // Consume the remainder and finish.
+ CRYPTO_poly1305_update(&state, in.data() + done, in.size() - done);
+
+ // |CRYPTO_poly1305_finish| requires a 16-byte-aligned output.
+ alignas(16) uint8_t out[16];
+ CRYPTO_poly1305_finish(&state, out);
+ if (!t->ExpectBytesEqual(mac.data(), mac.size(), out, 16)) {
+ t->PrintLine("SIMD pattern %u failed.", excess);
+ return false;
+ }
+
+ return true;
+}
+
static bool TestPoly1305(FileTest *t, void *arg) {
std::vector<uint8_t> key, in, mac;
if (!t->GetBytes(&key, "Key") ||
@@ -54,11 +102,20 @@ static bool TestPoly1305(FileTest *t, void *arg) {
CRYPTO_poly1305_update(&state, &in[i], 1);
}
CRYPTO_poly1305_finish(&state, out);
- if (!t->ExpectBytesEqual(out, 16, mac.data(), mac.size())) {
+ if (!t->ExpectBytesEqual(mac.data(), mac.size(), out, 16)) {
t->PrintLine("Streaming Poly1305 failed.");
return false;
}
+ // Test SIMD stress patterns. OpenSSL's AVX2 assembly needs a multiple of
+ // four blocks, so test up to three blocks of excess.
+ if (!TestSIMD(t, 0, key, in, mac) ||
+ !TestSIMD(t, 16, key, in, mac) ||
+ !TestSIMD(t, 32, key, in, mac) ||
+ !TestSIMD(t, 48, key, in, mac)) {
+ return false;
+ }
+
return true;
}
diff --git a/crypto/poly1305/poly1305_test.txt b/crypto/poly1305/poly1305_test.txt
deleted file mode 100644
index ad40699e..00000000
--- a/crypto/poly1305/poly1305_test.txt
+++ /dev/null
@@ -1,52 +0,0 @@
-# RFC 7539, section 2.5.2.
-
-Key = 85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b
-Input = "Cryptographic Forum Research Group"
-MAC = a8061dc1305136c6c22b8baf0c0127a9
-
-
-# RFC 7539, section A.3.
-
-Key = 0000000000000000000000000000000000000000000000000000000000000000
-Input = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-MAC = 00000000000000000000000000000000
-
-Key = 0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e
-Input = 416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e7472696275746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e20224945544620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c2073746174656d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c656374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207768696368206172652061646472657373656420746f
-MAC = 36e5f6b5c5e06070f0efca96227a863e
-
-Key = 36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000
-Input = 416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e7472696275746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e20224945544620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c2073746174656d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c656374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207768696368206172652061646472657373656420746f
-MAC = f3477e7cd95417af89a6b8794c310cf0
-
-Key = 1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0
-Input = 2754776173206272696c6c69672c20616e642074686520736c6974687920746f7665730a446964206779726520616e642067696d626c6520696e2074686520776162653a0a416c6c206d696d737920776572652074686520626f726f676f7665732c0a416e6420746865206d6f6d65207261746873206f757467726162652e
-MAC = 4541669a7eaaee61e708dc7cbcc5eb62
-
-Key = 0200000000000000000000000000000000000000000000000000000000000000
-Input = ffffffffffffffffffffffffffffffff
-MAC = 03000000000000000000000000000000
-
-Key = 02000000000000000000000000000000ffffffffffffffffffffffffffffffff
-Input = 02000000000000000000000000000000
-MAC = 03000000000000000000000000000000
-
-Key = 0100000000000000000000000000000000000000000000000000000000000000
-Input = fffffffffffffffffffffffffffffffff0ffffffffffffffffffffffffffffff11000000000000000000000000000000
-MAC = 05000000000000000000000000000000
-
-Key = 0100000000000000000000000000000000000000000000000000000000000000
-Input = fffffffffffffffffffffffffffffffffbfefefefefefefefefefefefefefefe01010101010101010101010101010101
-MAC = 00000000000000000000000000000000
-
-Key = 0200000000000000000000000000000000000000000000000000000000000000
-Input = fdffffffffffffffffffffffffffffff
-MAC = faffffffffffffffffffffffffffffff
-
-Key = 0100000000000000040000000000000000000000000000000000000000000000
-Input = e33594d7505e43b900000000000000003394d7505e4379cd01000000000000000000000000000000000000000000000001000000000000000000000000000000
-MAC = 14000000000000005500000000000000
-
-Key = 0100000000000000040000000000000000000000000000000000000000000000
-Input = e33594d7505e43b900000000000000003394d7505e4379cd010000000000000000000000000000000000000000000000
-MAC = 13000000000000000000000000000000
diff --git a/crypto/poly1305/poly1305_tests.txt b/crypto/poly1305/poly1305_tests.txt
new file mode 100644
index 00000000..611007a0
--- /dev/null
+++ b/crypto/poly1305/poly1305_tests.txt
@@ -0,0 +1,159 @@
+# RFC 7539, section 2.5.2.
+
+Key = 85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b
+Input = "Cryptographic Forum Research Group"
+MAC = a8061dc1305136c6c22b8baf0c0127a9
+
+
+# RFC 7539, section A.3.
+
+Key = 0000000000000000000000000000000000000000000000000000000000000000
+Input = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+MAC = 00000000000000000000000000000000
+
+Key = 0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e
+Input = 416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e7472696275746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e20224945544620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c2073746174656d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c656374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207768696368206172652061646472657373656420746f
+MAC = 36e5f6b5c5e06070f0efca96227a863e
+
+Key = 36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000
+Input = 416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e7472696275746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e20224945544620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c2073746174656d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c656374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207768696368206172652061646472657373656420746f
+MAC = f3477e7cd95417af89a6b8794c310cf0
+
+Key = 1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0
+Input = 2754776173206272696c6c69672c20616e642074686520736c6974687920746f7665730a446964206779726520616e642067696d626c6520696e2074686520776162653a0a416c6c206d696d737920776572652074686520626f726f676f7665732c0a416e6420746865206d6f6d65207261746873206f757467726162652e
+MAC = 4541669a7eaaee61e708dc7cbcc5eb62
+
+Key = 0200000000000000000000000000000000000000000000000000000000000000
+Input = ffffffffffffffffffffffffffffffff
+MAC = 03000000000000000000000000000000
+
+Key = 02000000000000000000000000000000ffffffffffffffffffffffffffffffff
+Input = 02000000000000000000000000000000
+MAC = 03000000000000000000000000000000
+
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+Input = fffffffffffffffffffffffffffffffff0ffffffffffffffffffffffffffffff11000000000000000000000000000000
+MAC = 05000000000000000000000000000000
+
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+Input = fffffffffffffffffffffffffffffffffbfefefefefefefefefefefefefefefe01010101010101010101010101010101
+MAC = 00000000000000000000000000000000
+
+Key = 0200000000000000000000000000000000000000000000000000000000000000
+Input = fdffffffffffffffffffffffffffffff
+MAC = faffffffffffffffffffffffffffffff
+
+Key = 0100000000000000040000000000000000000000000000000000000000000000
+Input = e33594d7505e43b900000000000000003394d7505e4379cd01000000000000000000000000000000000000000000000001000000000000000000000000000000
+MAC = 14000000000000005500000000000000
+
+Key = 0100000000000000040000000000000000000000000000000000000000000000
+Input = e33594d7505e43b900000000000000003394d7505e4379cd010000000000000000000000000000000000000000000000
+MAC = 13000000000000000000000000000000
+
+
+# Additional test vectors that are long enough to ensure OpenSSL's SIMD
+# assembly is fully tested.
+
+# Length 2048.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfed
+MAC = 69d28f73dd09d39a92aa179da354b7ea
+
+# Length 2049.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc8
+MAC = d6a26654b88572e875d9661c83471c1b
+
+# Length 2050.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852
+MAC = 9fbbb7f7adcd0cd5b46a4a520b22499a
+
+# Length 2051.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f5
+MAC = eb7cdceb97ade2a07622f8f5a4b1ce15
+
+# Length 2052.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f590
+MAC = d41c310927cd92e14784ea78b85503db
+
+# Length 2053.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073
+MAC = 16af133c423f783a14c49d9f526384cf
+
+# Length 2054.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4
+MAC = 00c75db8f0636b22f195645b03091f5f
+
+# Length 2055.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f434
+MAC = 4a532bc740f581555831345f3b75bf33
+
+# Length 2056.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a
+MAC = 698c7d32c5923871d124a2479e521706
+
+# Length 2057.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c
+MAC = a677187dbf3c927aeeafb9ebce0f61dc
+
+# Length 2058.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c8a
+MAC = 201fed7eee981b31d2cc42ff6c38141a
+
+# Length 2059.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c8a28
+MAC = 0c3d3d01a37f347c4f7c5826bcafb3e1
+
+# Length 2060.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c8a28c9
+MAC = 33a4e0e0bed7c84c5cc5dd4784410f07
+
+# Length 2061.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c8a28c99e
+MAC = 8e41c40a2f8ec58fe594f3a3a2de4ae1
+
+# Length 2062.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c8a28c99e21
+MAC = c6e5d1810fd878ac6b844c66cef36a22
+
+# Length 2063.
+Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
+Input = 248ac31085b6c2adaaa38259a0d7192c5c35d1bb4ef39ad94c38d1c82479e2dd2159a077024b0589bc8a20101b506f0a1ad0bbab76e83a83f1b94be6beae74e874cab692c5963a75436b776121ec9f62399a3e66b2d22707dae81933b6277f3c8516bcbe26dbbd86f373103d7cf4cad1888c952118fbfbd0d7b4bedc4ae4936aff91157e7aa47c54442ea78d6ac251d324a0fbe49d89cc3521b66d16e9c66a3709894e4eb0a4eedc4ae19468e66b81f271351b1d921ea551047abcc6b87a901fde7db79fa1818c11336dbc07244a40eb14cf77bde35e78ae9ad7d3f57ed7e7f23926c9172f82d77684ea5ed7d74ebc6f142b997036bcb7cce8df1bbc0d5b35a46509c954fc9469d214d6238f166cbf872156b4c41d7aac5942cffb175023078252a3f36e315c5d4ce0e39928a018252862becacef96a19f03bdcf46d75584299d1f8b03c0169e9e407d937145b5e5024139e7022a1978f114f24cdfa23780a119735c41da8fb759bbb3f025c6ec30e6c6e9bce8615be68e392fce59fd26a8e6a6cc5c606e3848116e4d01d29565a1facfb524b6d29643b826eee1e42869fc76df229dd79b39a2b1df28bb335c3a5f15a855d0121e4a6da34b5e4d5b7b5d5746a03ecff70811e1516fcec1bf7462e8876a2d21710aa168c78f45a6a15015950e221da85d3ec822ad6d0a6931b25a06b7bb5f3c10bb36cd4d647f9561982fde9818de5d4bf8db7f86c53b4ff14928ac15f79023b61861e73e44216540bb302153770da2533de9795252ab5fb77ad924c9338c8144c23d4c90dab9a18feac1a1574d4545e1435eb405e6c4c439fc724fce992ae85badf345bad16d85fbd338f04433703614754d0e7e54c4ccde2670587d52ecfb5a70a14a501bacc727722649931d8515b13d020a78e511fe136d45fbf97f9c7f689fcc677cfb3683723878350ffe9d08130cc6e567b6179e01b7eb2b3bbcf0873e1308eec018edeb8cce946338e15d5bf68c71916a83a99358039ef071e009546a2df936879dffbba397a93925d229a469fd17d71b7f524e03a30da6ee927542f8b369bed4734fe25dbd63d24ffd2a222f5f84f75d858ab989be925af570ad6d45bd28ce61b5139e1dd2f0b7795fe072e6e83acbb5e7b777a70c641e4cab2af40eed69abc334cd2703c3273204fac580c6a3d6680427e5f7d051e8380a53f93a180f4556ecea4530b9a2d5948dad63d415b6874f6b90e767d6d265be86351b53ba690780bb57c21b57418c5b97559e840c68257f839e7583a4bf7c7645c5987d40cc1ba79a218c35edfacdabe581d950e4bb7a481ebe64d61d00e75b1f25f1ce5f5462334a5b9038a697aa0937a3f8017e05d2c9c05dcb05c0b02508dea619b137f5444b6f088eb3cb2c66788f88afdfbba8faa1c490485624c88ae11e57347a676902e7553f056188493209bdbb30acc63c9e41e16a9d6c009416b520a76ba38f57628170c43626b5cb46179dc5bf65de865085f84bf741c223fbe474d2d19d8f43914fbd6586351089e73babf344f988b7963fe44528457d7aad3c564f6bcbd0d772a4c9fd328e6022d1c7c9f86726f8d5a23797d309c0f653ab1ac687833eb2700f156296062a8b377078f45f6b68c3d07cae1913ba8d5a6f9bf7525a3439eb932d4cefc4bf8e1b07b48ca13ece366cbc3e0388915915d1757475103a9e9454e7e6355de2d6acbf4710f9a63e4f6d3cd70c2d6fca88dd8a14448fdb63ce9350fdaafbe0b8bd1c5d307dae76dfed799aef2d8f23d5608d37d1330dd38b94860905dbeebf78d7b7318b7d42aed40d3f9899e9f420cbd92a6eeae3026f7725694e0e4bee016ba346fed2c21172bdb4a461cebe0cfe38e76645226ac127a259c193264d735ce8c8a57e17dd3f0579e2e86dc295ad1f45ba2d85db35044da61f7d401274b31eefbeb34e8d2ae596e9b4541aae117bdac5ed0b324c20539c27c07a411d5288b0b5f6fa16e9a7df85dc319fa6b71cd08a859c06a3f7b0289e1750adbf182f9750fea96fea5ab7aa3473340607cd7ed2c626f5382491c26d5d5bea61401dee7319c94d418f297e61ceac8f258ee8c23831bda081591f5a918e96855774ddedffc51e5b180f1971806d42fc333020b734aeb45adb0bc47325d0cea5f6713a786558022afc39d573892aa3635efbfd8bcb11c57f306c72146afe8b45388125cb7bf9ecf965a7ba4f768c77be366470dcdcf214b7f6a5a9460ed4fe44ae559d85e2fdc2094de83fff12ea8804db1215c4ca865871bdd7f8ef32ab799bf923ffb02c1ded7d129beadad46c5eda31ab1a6f43da05ea08bff7ffa88d8966353d01830558c39b930b01d175e437124d8edd0d2698fd8932f2b2c9b14746e52879c57a395538150f390264f00e60d470711202f4194499ff79037ca9885dc8d695f7d917a3086ca88e8f8d0243efee09302cf39e039eb7cc8dd19d28120d5fe533b5727cd39133181c729ca6f90a015ed30be7668d5cb5ecc33a53ee69bf7d1a5ecbdb153803743c6adaaabd36bf84e5be38d3f04a5d5dbfd67bdcd3b176e65bd1391ade775cc32ce43a847fb6c672a3fe97a5d4081c4986959ec5fb898f42a9397ba2b3ec2c1018f8d76d057f2366bd0e4465514ad6560c599664fb85621fe771e00f43d39b591b2a6a321100f4d1ef23a376d5ae3eeedbfe23da73dff0ee4d16b34ebddd8f5f053db9824105fc7300dbee7ea6af56b112319e3e215a0fc79ae946f6b5227453ec7fcaf17cf7651f71499a50d81221404d5f129ac50ea7528ff0e0069ec4ab8acb7919d81749ab37a870c5ef2cc5a15cf96709d3c65b4addc77e7416847160bcabb94ea36377e0ef71be80b5cc53effd5444888044a353574c72c924bba2a8b4e8354188ebfedc852f59073f4347a8c8a28c99e21df
+MAC = f6eaae369c3cb5c05748e8d919178e00
+
+# Regression test for https://rt.openssl.org/Ticket/Display.html?id=4439
+Key = 2d773be37adb1e4d683bf0075e79c4ee037918535a7f99ccb7040fb5f5f43aea
+Input = 89dab80b7717c1db5db437860a3f70218e93e1b8f461fb677f16f35f6f87e2a91c99bc3a47ace47640cc95c345be5ecca5a3523c35cc01893af0b64a620334270372ec12482d1b1e363561698a578b359803495bb4e2ef1930b17a5190b580f141300df30adbeca28f6427a8bc1a999fd51c554a017d095d8c3e3127daf9f595
+MAC = c85d15ed44c378d6b00e23064c7bcd51
+
+# Regression tests for https://rt.openssl.org/Ticket/Display.html?id=4483
+
+Key = 7f1b02640000000000000000000000000000000000000000cccccccccccccccc
+Input = cccccccccccccccccccccccccccccccccccccccccccccccccc80ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccceccccccccccccccccccccccccccccccccccccc5cccccccccccccccccccccccccccccccccccccccccce3ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaccccccccccccccccccccce6cccccccccc000000afccccccccccccccccccfffffff5000000000000000000000000000000000000000000000000000000ffffffe70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000719205a8521dfc
+MAC = 8559b876eceed66eb37798c0457baff9
+
+Key = e00016000000000000000000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaa
+Input = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa000000000000000000800264
+MAC = 00bd1258978e205444c9aaaa82006fed
+
+Key = 0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+Input = 02fc
+MAC = 06120c0c0c0c0c0c0c0c0c0c0c0c0c0c
+
+Key = 00ff000000000000000000000000000000000000001e00000000000000007b7b
+Input = 7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7a7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b5c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b6e7b007b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7a7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b5c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b6e7b001300000000b300000000000000000000000000000000000000000000f20000000000000000000000000000000000002000efff0009000000000000000000000000100000000009000000640000000000000000000000001300000000b300000000000000000000000000000000000000000000f20000000000000000000000000000000000002000efff00090000000000000000007a000010000000000900000064000000000000000000000000000000000000000000000000fc
+MAC = 33205bbf9e9f8f7212ab9e2ab9b7e4a5
diff --git a/crypto/poly1305/poly1305_vec.c b/crypto/poly1305/poly1305_vec.c
index 59aab199..3045a2f1 100644
--- a/crypto/poly1305/poly1305_vec.c
+++ b/crypto/poly1305/poly1305_vec.c
@@ -701,9 +701,9 @@ static size_t poly1305_combine(poly1305_state_internal *st, const uint8_t *m,
t0 &= 0x3ffffff;
t1 = t1 + c;
- st->HH[0] = ((t0) | (t1 << 26)) & 0xfffffffffffull;
- st->HH[1] = ((t1 >> 18) | (t2 << 8) | (t3 << 34)) & 0xfffffffffffull;
- st->HH[2] = ((t3 >> 10) | (t4 << 16)) & 0x3ffffffffffull;
+ st->HH[0] = ((t0) | (t1 << 26)) & UINT64_C(0xfffffffffff);
+ st->HH[1] = ((t1 >> 18) | (t2 << 8) | (t3 << 34)) & UINT64_C(0xfffffffffff);
+ st->HH[2] = ((t3 >> 10) | (t4 << 16)) & UINT64_C(0x3ffffffffff);
return consumed;
}
diff --git a/crypto/rand/CMakeLists.txt b/crypto/rand/CMakeLists.txt
index eedf81b8..c66d2eeb 100644
--- a/crypto/rand/CMakeLists.txt
+++ b/crypto/rand/CMakeLists.txt
@@ -13,6 +13,7 @@ add_library(
OBJECT
+ deterministic.c
rand.c
urandom.c
windows.c
diff --git a/crypto/rand/deterministic.c b/crypto/rand/deterministic.c
new file mode 100644
index 00000000..e6b7bb7e
--- /dev/null
+++ b/crypto/rand/deterministic.c
@@ -0,0 +1,49 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/rand.h>
+
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+
+#include <string.h>
+
+#include <openssl/chacha.h>
+
+#include "internal.h"
+
+
+/* g_num_calls is the number of calls to |CRYPTO_sysrand| that have occured.
+ *
+ * TODO(davidben): This is intentionally not thread-safe. If the fuzzer mode is
+ * ever used in a multi-threaded program, replace this with a thread-local. (A
+ * mutex would not be deterministic.) */
+static uint64_t g_num_calls = 0;
+
+void RAND_cleanup(void) {}
+
+void RAND_reset_for_fuzzing(void) { g_num_calls = 0; }
+
+void CRYPTO_sysrand(uint8_t *out, size_t requested) {
+ static const uint8_t kZeroKey[32];
+
+ uint8_t nonce[12];
+ memset(nonce, 0, sizeof(nonce));
+ memcpy(nonce, &g_num_calls, sizeof(g_num_calls));
+
+ memset(out, 0, requested);
+ CRYPTO_chacha_20(out, out, requested, kZeroKey, nonce, 0);
+ g_num_calls++;
+}
+
+#endif /* BORINGSSL_UNSAFE_FUZZER_MODE */
diff --git a/crypto/rand/rand.c b/crypto/rand/rand.c
index 82087ba2..5a1bec2e 100644
--- a/crypto/rand/rand.c
+++ b/crypto/rand/rand.c
@@ -72,7 +72,8 @@ static void rand_thread_state_free(void *state) {
OPENSSL_free(state);
}
-#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM)
+#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) && \
+ !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
/* These functions are defined in asm/rdrand-x86_64.pl */
extern int CRYPTO_rdrand(uint8_t out[8]);
diff --git a/crypto/rand/urandom.c b/crypto/rand/urandom.c
index 5bf5c739..434fe431 100644
--- a/crypto/rand/urandom.c
+++ b/crypto/rand/urandom.c
@@ -14,7 +14,7 @@
#include <openssl/rand.h>
-#if !defined(OPENSSL_WINDOWS)
+#if !defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
#include <assert.h>
#include <errno.h>
@@ -69,7 +69,7 @@ static void init_once(void) {
CRYPTO_STATIC_MUTEX_lock_read(&requested_lock);
urandom_buffering = urandom_buffering_requested;
int fd = urandom_fd_requested;
- CRYPTO_STATIC_MUTEX_unlock(&requested_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&requested_lock);
if (fd == -2) {
do {
@@ -106,7 +106,7 @@ void RAND_set_urandom_fd(int fd) {
CRYPTO_STATIC_MUTEX_lock_write(&requested_lock);
urandom_fd_requested = fd;
- CRYPTO_STATIC_MUTEX_unlock(&requested_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock);
CRYPTO_once(&once, init_once);
if (urandom_fd != fd) {
@@ -127,7 +127,7 @@ void RAND_enable_fork_unsafe_buffering(int fd) {
CRYPTO_STATIC_MUTEX_lock_write(&requested_lock);
urandom_buffering_requested = 1;
urandom_fd_requested = fd;
- CRYPTO_STATIC_MUTEX_unlock(&requested_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock);
CRYPTO_once(&once, init_once);
if (urandom_buffering != 1 || (fd >= 0 && urandom_fd != fd)) {
@@ -220,4 +220,4 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
}
}
-#endif /* !OPENSSL_WINDOWS */
+#endif /* !OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_FUZZER_MODE */
diff --git a/crypto/rand/windows.c b/crypto/rand/windows.c
index 1a0cb8b0..5a9a96b4 100644
--- a/crypto/rand/windows.c
+++ b/crypto/rand/windows.c
@@ -14,12 +14,12 @@
#include <openssl/rand.h>
-#if defined(OPENSSL_WINDOWS)
+#if defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
#include <limits.h>
#include <stdlib.h>
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
@@ -30,7 +30,7 @@
#include <ntsecapi.h>
#undef SystemFunction036
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#include "internal.h"
@@ -53,4 +53,4 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
return;
}
-#endif /* OPENSSL_WINDOWS */
+#endif /* OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_FUZZER_MODE */
diff --git a/crypto/rc4/asm/rc4-586.pl b/crypto/rc4/asm/rc4-586.pl
index fc860ae2..8d3ccb72 100644
--- a/crypto/rc4/asm/rc4-586.pl
+++ b/crypto/rc4/asm/rc4-586.pl
@@ -384,31 +384,5 @@ $idx="edx";
&mov (&DWP(-4,$out),"eax"); # key->y=0;
&function_end("asm_RC4_set_key");
-# const char *RC4_options(void);
-&function_begin_B("RC4_options");
- &call (&label("pic_point"));
-&set_label("pic_point");
- &blindpop("eax");
- &lea ("eax",&DWP(&label("opts")."-".&label("pic_point"),"eax"));
- &picmeup("edx","OPENSSL_ia32cap_P");
- &mov ("edx",&DWP(0,"edx"));
- &bt ("edx",20);
- &jc (&label("1xchar"));
- &bt ("edx",26);
- &jnc (&label("ret"));
- &add ("eax",25);
- &ret ();
-&set_label("1xchar");
- &add ("eax",12);
-&set_label("ret");
- &ret ();
-&set_label("opts",64);
-&asciz ("rc4(4x,int)");
-&asciz ("rc4(1x,char)");
-&asciz ("rc4(8x,mmx)");
-&asciz ("RC4 for x86, CRYPTOGAMS by <appro\@openssl.org>");
-&align (64);
-&function_end_B("RC4_options");
-
&asm_finish();
diff --git a/crypto/refcount_lock.c b/crypto/refcount_lock.c
index bb8ef86b..ea6a06d3 100644
--- a/crypto/refcount_lock.c
+++ b/crypto/refcount_lock.c
@@ -31,7 +31,7 @@ void CRYPTO_refcount_inc(CRYPTO_refcount_t *count) {
if (*count < CRYPTO_REFCOUNT_MAX) {
(*count)++;
}
- CRYPTO_STATIC_MUTEX_unlock(&g_refcount_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&g_refcount_lock);
}
int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count) {
@@ -45,7 +45,7 @@ int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count) {
(*count)--;
}
ret = (*count == 0);
- CRYPTO_STATIC_MUTEX_unlock(&g_refcount_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&g_refcount_lock);
return ret;
}
diff --git a/crypto/rsa/blinding.c b/crypto/rsa/blinding.c
index e6b987d9..d9d90c2b 100644
--- a/crypto/rsa/blinding.c
+++ b/crypto/rsa/blinding.c
@@ -120,53 +120,35 @@
#define BN_BLINDING_COUNTER 32
struct bn_blinding_st {
- BIGNUM *A;
- BIGNUM *Ai;
- BIGNUM *e;
- BIGNUM *mod;
- int counter;
- /* mont is the Montgomery context used for this |BN_BLINDING|. It is not
- * owned and must outlive this structure. */
- const BN_MONT_CTX *mont;
- int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx, const BN_MONT_CTX *mont);
+ BIGNUM *A; /* The base blinding factor, Montgomery-encoded. */
+ BIGNUM *Ai; /* The inverse of the blinding factor, Montgomery-encoded. */
+ unsigned counter;
};
-BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod) {
- BN_BLINDING *ret = NULL;
+static int bn_blinding_create_param(BN_BLINDING *b, const BIGNUM *e,
+ const BN_MONT_CTX *mont, BN_CTX *ctx);
- ret = (BN_BLINDING*) OPENSSL_malloc(sizeof(BN_BLINDING));
+BN_BLINDING *BN_BLINDING_new(void) {
+ BN_BLINDING *ret = OPENSSL_malloc(sizeof(BN_BLINDING));
if (ret == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return NULL;
}
memset(ret, 0, sizeof(BN_BLINDING));
- if (A != NULL) {
- ret->A = BN_dup(A);
- if (ret->A == NULL) {
- goto err;
- }
- }
- if (Ai != NULL) {
- ret->Ai = BN_dup(Ai);
- if (ret->Ai == NULL) {
- goto err;
- }
- }
- /* save a copy of mod in the BN_BLINDING structure */
- ret->mod = BN_dup(mod);
- if (ret->mod == NULL) {
+ ret->A = BN_new();
+ if (ret->A == NULL) {
goto err;
}
- if (BN_get_flags(mod, BN_FLG_CONSTTIME) != 0) {
- BN_set_flags(ret->mod, BN_FLG_CONSTTIME);
+
+ ret->Ai = BN_new();
+ if (ret->Ai == NULL) {
+ goto err;
}
- /* Set the counter to the special value -1
- * to indicate that this is never-used fresh blinding
- * that does not need updating before first use. */
- ret->counter = -1;
+ /* The blinding values need to be created before this blinding can be used. */
+ ret->counter = BN_BLINDING_COUNTER - 1;
+
return ret;
err:
@@ -181,242 +163,105 @@ void BN_BLINDING_free(BN_BLINDING *r) {
BN_free(r->A);
BN_free(r->Ai);
- BN_free(r->e);
- BN_free(r->mod);
OPENSSL_free(r);
}
-int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx) {
- int ret = 0;
-
- if (b->A == NULL || b->Ai == NULL) {
- OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED);
- goto err;
- }
-
- if (b->counter == -1) {
- b->counter = 0;
- }
-
- if (++b->counter == BN_BLINDING_COUNTER && b->e != NULL) {
+static int bn_blinding_update(BN_BLINDING *b, const BIGNUM *e,
+ const BN_MONT_CTX *mont, BN_CTX *ctx) {
+ if (++b->counter == BN_BLINDING_COUNTER) {
/* re-create blinding parameters */
- if (!BN_BLINDING_create_param(b, NULL, NULL, ctx, NULL, NULL)) {
+ if (!bn_blinding_create_param(b, e, mont, ctx)) {
goto err;
}
+ b->counter = 0;
} else {
- if (!BN_mod_mul(b->A, b->A, b->A, b->mod, ctx)) {
- goto err;
- }
- if (!BN_mod_mul(b->Ai, b->Ai, b->Ai, b->mod, ctx)) {
+ if (!BN_mod_mul_montgomery(b->A, b->A, b->A, mont, ctx) ||
+ !BN_mod_mul_montgomery(b->Ai, b->Ai, b->Ai, mont, ctx)) {
goto err;
}
}
- ret = 1;
+ return 1;
err:
- if (b->counter == BN_BLINDING_COUNTER) {
- b->counter = 0;
- }
- return ret;
-}
-
-int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx) {
- int ret = 1;
+ /* |A| and |Ai| may be in an inconsistent state so they both need to be
+ * replaced the next time this blinding is used. Note that this is only
+ * sufficient because support for |BN_BLINDING_NO_UPDATE| and
+ * |BN_BLINDING_NO_RECREATE| was previously dropped. */
+ b->counter = BN_BLINDING_COUNTER - 1;
- if (b->A == NULL || b->Ai == NULL) {
- OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED);
- return 0;
- }
+ return 0;
+}
- if (b->counter == -1) {
- /* Fresh blinding, doesn't need updating. */
- b->counter = 0;
- } else if (!BN_BLINDING_update(b, ctx)) {
+int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, const BIGNUM *e,
+ const BN_MONT_CTX *mont, BN_CTX *ctx) {
+ /* |n| is not Montgomery-encoded and |b->A| is. |BN_mod_mul_montgomery|
+ * cancels one Montgomery factor, so the resulting value of |n| is unencoded.
+ */
+ if (!bn_blinding_update(b, e, mont, ctx) ||
+ !BN_mod_mul_montgomery(n, n, b->A, mont, ctx)) {
return 0;
}
- if (!BN_mod_mul(n, n, b->A, b->mod, ctx)) {
- ret = 0;
- }
-
- return ret;
+ return 1;
}
-int BN_BLINDING_invert(BIGNUM *n, const BN_BLINDING *b, BN_CTX *ctx) {
- if (b->Ai == NULL) {
- OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED);
- return 0;
- }
- return BN_mod_mul(n, n, b->Ai, b->mod, ctx);
+int BN_BLINDING_invert(BIGNUM *n, const BN_BLINDING *b, BN_MONT_CTX *mont,
+ BN_CTX *ctx) {
+ /* |n| is not Montgomery-encoded and |b->A| is. |BN_mod_mul_montgomery|
+ * cancels one Montgomery factor, so the resulting value of |n| is unencoded.
+ */
+ return BN_mod_mul_montgomery(n, n, b->Ai, mont, ctx);
}
-BN_BLINDING *BN_BLINDING_create_param(
- BN_BLINDING *b, const BIGNUM *e, BIGNUM *m, BN_CTX *ctx,
- int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx, const BN_MONT_CTX *mont),
- const BN_MONT_CTX *mont) {
+static int bn_blinding_create_param(BN_BLINDING *b, const BIGNUM *e,
+ const BN_MONT_CTX *mont, BN_CTX *ctx) {
+ BIGNUM mont_N_consttime;
+ BN_init(&mont_N_consttime);
+ BN_with_flags(&mont_N_consttime, &mont->N, BN_FLG_CONSTTIME);
int retry_counter = 32;
- BN_BLINDING *ret = NULL;
-
- if (b == NULL) {
- ret = BN_BLINDING_new(NULL, NULL, m);
- } else {
- ret = b;
- }
-
- if (ret == NULL) {
- goto err;
- }
-
- if (ret->A == NULL && (ret->A = BN_new()) == NULL) {
- goto err;
- }
- if (ret->Ai == NULL && (ret->Ai = BN_new()) == NULL) {
- goto err;
- }
-
- if (e != NULL) {
- BN_free(ret->e);
- ret->e = BN_dup(e);
- }
- if (ret->e == NULL) {
- goto err;
- }
-
- if (bn_mod_exp != NULL) {
- ret->bn_mod_exp = bn_mod_exp;
- }
- if (mont != NULL) {
- ret->mont = mont;
- }
do {
- if (!BN_rand_range(ret->A, ret->mod)) {
- goto err;
+ if (!BN_rand_range(b->A, &mont->N)) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /* |BN_from_montgomery| + |BN_mod_inverse_no_branch| is equivalent to, but
+ * more efficient than, |BN_mod_inverse_no_branch| + |BN_to_montgomery|. */
+ if (!BN_from_montgomery(b->Ai, b->A, mont, ctx)) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
+ return 0;
}
int no_inverse;
- if (BN_mod_inverse_ex(ret->Ai, &no_inverse, ret->A, ret->mod, ctx) == NULL) {
+ if (BN_mod_inverse_ex(b->Ai, &no_inverse, b->Ai, &mont_N_consttime, ctx) ==
+ NULL) {
/* this should almost never happen for good RSA keys */
if (no_inverse) {
if (retry_counter-- == 0) {
OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_MANY_ITERATIONS);
- goto err;
+ return 0;
}
ERR_clear_error();
} else {
- goto err;
+ OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
+ return 0;
}
} else {
break;
}
} while (1);
- if (ret->bn_mod_exp != NULL && ret->mont != NULL) {
- if (!ret->bn_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx, ret->mont)) {
- goto err;
- }
- } else {
- if (!BN_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx)) {
- goto err;
- }
- }
-
- return ret;
-
-err:
- if (b == NULL) {
- BN_BLINDING_free(ret);
- ret = NULL;
- }
-
- return ret;
-}
-
-static BIGNUM *rsa_get_public_exp(const BIGNUM *d, const BIGNUM *p,
- const BIGNUM *q, BN_CTX *ctx) {
- BIGNUM *ret = NULL, *r0, *r1, *r2;
-
- if (d == NULL || p == NULL || q == NULL) {
- return NULL;
- }
-
- BN_CTX_start(ctx);
- r0 = BN_CTX_get(ctx);
- r1 = BN_CTX_get(ctx);
- r2 = BN_CTX_get(ctx);
- if (r2 == NULL) {
- goto err;
- }
-
- if (!BN_sub(r1, p, BN_value_one())) {
- goto err;
- }
- if (!BN_sub(r2, q, BN_value_one())) {
- goto err;
- }
- if (!BN_mul(r0, r1, r2, ctx)) {
- goto err;
- }
-
- ret = BN_mod_inverse(NULL, d, r0, ctx);
-
-err:
- BN_CTX_end(ctx);
- return ret;
-}
-
-BN_BLINDING *rsa_setup_blinding(RSA *rsa, BN_CTX *in_ctx) {
- BIGNUM local_n;
- BIGNUM *e, *n;
- BN_CTX *ctx;
- BN_BLINDING *ret = NULL;
- BN_MONT_CTX *mont_ctx = NULL;
-
- if (in_ctx == NULL) {
- ctx = BN_CTX_new();
- if (ctx == NULL) {
- return 0;
- }
- } else {
- ctx = in_ctx;
- }
-
- if (rsa->e == NULL) {
- e = rsa_get_public_exp(rsa->d, rsa->p, rsa->q, ctx);
- if (e == NULL) {
- OPENSSL_PUT_ERROR(RSA, RSA_R_NO_PUBLIC_EXPONENT);
- goto err;
- }
- } else {
- e = rsa->e;
- }
-
- n = &local_n;
- BN_with_flags(n, rsa->n, BN_FLG_CONSTTIME);
-
- if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
- mont_ctx = BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx);
- if (mont_ctx == NULL) {
- goto err;
- }
- }
-
- ret = BN_BLINDING_create_param(NULL, e, n, ctx, rsa->meth->bn_mod_exp,
- mont_ctx);
- if (ret == NULL) {
- OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB);
- goto err;
+ if (!BN_mod_exp_mont(b->A, b->A, e, &mont->N, ctx, mont)) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
+ return 0;
}
-err:
- if (in_ctx == NULL) {
- BN_CTX_free(ctx);
- }
- if (rsa->e == NULL) {
- BN_free(e);
+ if (!BN_to_montgomery(b->A, b->A, mont, ctx)) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
+ return 0;
}
- return ret;
+ return 1;
}
diff --git a/crypto/rsa/internal.h b/crypto/rsa/internal.h
index 4d27344e..c6ea97f0 100644
--- a/crypto/rsa/internal.h
+++ b/crypto/rsa/internal.h
@@ -77,9 +77,6 @@ int rsa_default_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out,
int padding);
int rsa_default_decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
const uint8_t *in, size_t in_len, int padding);
-int rsa_default_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out,
- size_t max_out, const uint8_t *in, size_t in_len,
- int padding);
int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
size_t len);
int rsa_default_multi_prime_keygen(RSA *rsa, int bits, int num_primes,
@@ -90,17 +87,12 @@ int rsa_default_keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb);
#define RSA_PKCS1_PADDING_SIZE 11
-BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod);
+BN_BLINDING *BN_BLINDING_new(void);
void BN_BLINDING_free(BN_BLINDING *b);
-int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx);
-int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
-int BN_BLINDING_invert(BIGNUM *n, const BN_BLINDING *b, BN_CTX *ctx);
-BN_BLINDING *BN_BLINDING_create_param(
- BN_BLINDING *b, const BIGNUM *e, BIGNUM *m, BN_CTX *ctx,
- int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
- const BIGNUM *m, BN_CTX *ctx, const BN_MONT_CTX *mont),
- const BN_MONT_CTX *mont);
-BN_BLINDING *rsa_setup_blinding(RSA *rsa, BN_CTX *in_ctx);
+int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, const BIGNUM *e,
+ const BN_MONT_CTX *mont_ctx, BN_CTX *ctx);
+int BN_BLINDING_invert(BIGNUM *n, const BN_BLINDING *b, BN_MONT_CTX *mont_ctx,
+ BN_CTX *ctx);
int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned to_len,
diff --git a/crypto/rsa/padding.c b/crypto/rsa/padding.c
index 128950ae..12147ea4 100644
--- a/crypto/rsa/padding.c
+++ b/crypto/rsa/padding.c
@@ -59,6 +59,7 @@
#include <limits.h>
#include <string.h>
+#include <openssl/bn.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/mem.h>
@@ -73,7 +74,6 @@
int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned to_len,
const uint8_t *from, unsigned from_len) {
unsigned j;
- uint8_t *p;
if (to_len < RSA_PKCS1_PADDING_SIZE) {
OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
@@ -85,7 +85,7 @@ int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned to_len,
return 0;
}
- p = (uint8_t *)to;
+ uint8_t *p = to;
*(p++) = 0;
*(p++) = 1; /* Private Key BT (Block Type) */
@@ -154,7 +154,6 @@ int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned to_len,
int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned to_len,
const uint8_t *from, unsigned from_len) {
unsigned i, j;
- uint8_t *p;
if (to_len < RSA_PKCS1_PADDING_SIZE) {
OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
@@ -166,7 +165,7 @@ int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned to_len,
return 0;
}
- p = (unsigned char *)to;
+ uint8_t *p = to;
*(p++) = 0;
*(p++) = 2; /* Public Key BT (Block Type) */
@@ -275,8 +274,8 @@ int RSA_padding_add_none(uint8_t *to, unsigned to_len, const uint8_t *from,
return 1;
}
-int PKCS1_MGF1(uint8_t *mask, unsigned len, const uint8_t *seed,
- unsigned seedlen, const EVP_MD *dgst) {
+static int PKCS1_MGF1(uint8_t *mask, unsigned len, const uint8_t *seed,
+ unsigned seedlen, const EVP_MD *dgst) {
unsigned outlen = 0;
uint32_t i;
uint8_t cnt[4];
@@ -357,7 +356,7 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len,
seed = to + 1;
db = to + mdlen + 1;
- if (!EVP_Digest((void *)param, param_len, db, NULL, md, NULL)) {
+ if (!EVP_Digest(param, param_len, db, NULL, md, NULL)) {
return 0;
}
memset(db + mdlen, 0, emlen - from_len - 2 * mdlen - 1);
@@ -443,7 +442,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len,
db[i] ^= maskeddb[i];
}
- if (!EVP_Digest((void *)param, param_len, phash, NULL, md, NULL)) {
+ if (!EVP_Digest(param, param_len, phash, NULL, md, NULL)) {
goto err;
}
diff --git a/crypto/rsa/rsa.c b/crypto/rsa/rsa.c
index 9ffea1f2..e5f98916 100644
--- a/crypto/rsa/rsa.c
+++ b/crypto/rsa/rsa.c
@@ -64,7 +64,7 @@
#include <openssl/err.h>
#include <openssl/ex_data.h>
#include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/thread.h>
#include "internal.h"
@@ -258,16 +258,6 @@ int RSA_private_decrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa,
return out_len;
}
-int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
- const uint8_t *in, size_t in_len, int padding) {
- if (rsa->meth->verify_raw) {
- return rsa->meth->verify_raw(rsa, out_len, out, max_out, in, in_len, padding);
- }
-
- return rsa_default_verify_raw(rsa, out_len, out, max_out, in, in_len,
- padding);
-}
-
int RSA_public_decrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa,
int padding) {
size_t out_len;
@@ -473,6 +463,11 @@ finish:
int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
const uint8_t *sig, size_t sig_len, RSA *rsa) {
+ if (rsa->n == NULL || rsa->e == NULL) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING);
+ return 0;
+ }
+
const size_t rsa_size = RSA_size(rsa);
uint8_t *buf = NULL;
int ret = 0;
@@ -480,15 +475,6 @@ int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
size_t signed_msg_len, len;
int signed_msg_is_alloced = 0;
- if (rsa->meth->verify) {
- return rsa->meth->verify(hash_nid, msg, msg_len, sig, sig_len, rsa);
- }
-
- if (sig_len != rsa_size) {
- OPENSSL_PUT_ERROR(RSA, RSA_R_WRONG_SIGNATURE_LENGTH);
- return 0;
- }
-
if (hash_nid == NID_md5_sha1 && msg_len != SSL_SIG_LENGTH) {
OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
@@ -510,7 +496,7 @@ int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
goto out;
}
- if (len != signed_msg_len || CRYPTO_memcmp(buf, signed_msg, len) != 0) {
+ if (len != signed_msg_len || memcmp(buf, signed_msg, len) != 0) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_SIGNATURE);
goto out;
}
diff --git a/crypto/rsa/rsa_asn1.c b/crypto/rsa/rsa_asn1.c
index 1f3d6a24..d14ecaee 100644
--- a/crypto/rsa/rsa_asn1.c
+++ b/crypto/rsa/rsa_asn1.c
@@ -59,8 +59,6 @@
#include <limits.h>
#include <string.h>
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
@@ -390,6 +388,7 @@ int i2d_RSAPublicKey(const RSA *in, uint8_t **outp) {
CBB cbb;
if (!CBB_init(&cbb, 0) ||
!RSA_marshal_public_key(&cbb, in)) {
+ CBB_cleanup(&cbb);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
@@ -417,20 +416,12 @@ int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp) {
CBB cbb;
if (!CBB_init(&cbb, 0) ||
!RSA_marshal_private_key(&cbb, in)) {
+ CBB_cleanup(&cbb);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
}
-ASN1_SEQUENCE(RSA_PSS_PARAMS) = {
- ASN1_EXP_OPT(RSA_PSS_PARAMS, hashAlgorithm, X509_ALGOR,0),
- ASN1_EXP_OPT(RSA_PSS_PARAMS, maskGenAlgorithm, X509_ALGOR,1),
- ASN1_EXP_OPT(RSA_PSS_PARAMS, saltLength, ASN1_INTEGER,2),
- ASN1_EXP_OPT(RSA_PSS_PARAMS, trailerField, ASN1_INTEGER,3),
-} ASN1_SEQUENCE_END(RSA_PSS_PARAMS);
-
-IMPLEMENT_ASN1_FUNCTIONS(RSA_PSS_PARAMS);
-
RSA *RSAPublicKey_dup(const RSA *rsa) {
uint8_t *der;
size_t der_len;
diff --git a/crypto/rsa/rsa_impl.c b/crypto/rsa/rsa_impl.c
index ba310739..af44a3d5 100644
--- a/crypto/rsa/rsa_impl.c
+++ b/crypto/rsa/rsa_impl.c
@@ -56,6 +56,7 @@
#include <openssl/rsa.h>
+#include <assert.h>
#include <string.h>
#include <openssl/bn.h>
@@ -69,21 +70,37 @@
static int check_modulus_and_exponent_sizes(const RSA *rsa) {
unsigned rsa_bits = BN_num_bits(rsa->n);
+
if (rsa_bits > 16 * 1024) {
OPENSSL_PUT_ERROR(RSA, RSA_R_MODULUS_TOO_LARGE);
return 0;
}
- if (BN_ucmp(rsa->n, rsa->e) <= 0) {
+ /* Mitigate DoS attacks by limiting the exponent size. 33 bits was chosen as
+ * the limit based on the recommendations in [1] and [2]. Windows CryptoAPI
+ * doesn't support values larger than 32 bits [3], so it is unlikely that
+ * exponents larger than 32 bits are being used for anything Windows commonly
+ * does.
+ *
+ * [1] https://www.imperialviolet.org/2012/03/16/rsae.html
+ * [2] https://www.imperialviolet.org/2012/03/17/rsados.html
+ * [3] https://msdn.microsoft.com/en-us/library/aa387685(VS.85).aspx */
+ static const unsigned kMaxExponentBits = 33;
+
+ if (BN_num_bits(rsa->e) > kMaxExponentBits) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE);
return 0;
}
- /* For large moduli only, enforce exponent limit. */
- if (rsa_bits > 3072 && BN_num_bits(rsa->e) > 64) {
- OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE);
+ /* Verify |n > e|. Comparing |rsa_bits| to |kMaxExponentBits| is a small
+ * shortcut to comparing |n| and |e| directly. In reality, |kMaxExponentBits|
+ * is much smaller than the minimum RSA key size that any application should
+ * accept. */
+ if (rsa_bits <= kMaxExponentBits) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
+ assert(BN_ucmp(rsa->n, rsa->e) > 0);
return 1;
}
@@ -154,13 +171,8 @@ int rsa_default_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
goto err;
}
- if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
- if (BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) == NULL) {
- goto err;
- }
- }
-
- if (!rsa->meth->bn_mod_exp(result, f, rsa->e, rsa->n, ctx, rsa->mont_n)) {
+ if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) ||
+ !BN_mod_exp_mont(result, f, rsa->e, rsa->n, ctx, rsa->mont_n)) {
goto err;
}
@@ -201,6 +213,9 @@ err:
* |*index_used| and must be passed to |rsa_blinding_release| when finished. */
static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used,
BN_CTX *ctx) {
+ assert(ctx != NULL);
+ assert(rsa->mont_n != NULL);
+
BN_BLINDING *ret = NULL;
BN_BLINDING **new_blindings;
uint8_t *new_blindings_inuse;
@@ -219,7 +234,7 @@ static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used,
}
if (ret != NULL) {
- CRYPTO_MUTEX_unlock(&rsa->lock);
+ CRYPTO_MUTEX_unlock_write(&rsa->lock);
return ret;
}
@@ -228,8 +243,8 @@ static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used,
/* We didn't find a free BN_BLINDING to use so increase the length of
* the arrays by one and use the newly created element. */
- CRYPTO_MUTEX_unlock(&rsa->lock);
- ret = rsa_setup_blinding(rsa, ctx);
+ CRYPTO_MUTEX_unlock_write(&rsa->lock);
+ ret = BN_BLINDING_new();
if (ret == NULL) {
return NULL;
}
@@ -266,14 +281,14 @@ static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used,
rsa->blindings_inuse = new_blindings_inuse;
rsa->num_blindings++;
- CRYPTO_MUTEX_unlock(&rsa->lock);
+ CRYPTO_MUTEX_unlock_write(&rsa->lock);
return ret;
err2:
OPENSSL_free(new_blindings);
err1:
- CRYPTO_MUTEX_unlock(&rsa->lock);
+ CRYPTO_MUTEX_unlock_write(&rsa->lock);
BN_BLINDING_free(ret);
return NULL;
}
@@ -290,7 +305,7 @@ static void rsa_blinding_release(RSA *rsa, BN_BLINDING *blinding,
CRYPTO_MUTEX_lock_write(&rsa->lock);
rsa->blindings_inuse[blinding_index] = 0;
- CRYPTO_MUTEX_unlock(&rsa->lock);
+ CRYPTO_MUTEX_unlock_write(&rsa->lock);
}
/* signing */
@@ -409,33 +424,49 @@ err:
return ret;
}
-int rsa_default_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out,
- size_t max_out, const uint8_t *in, size_t in_len,
- int padding) {
+static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx);
+
+int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+ const uint8_t *in, size_t in_len, int padding) {
+ if (rsa->n == NULL || rsa->e == NULL) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING);
+ return 0;
+ }
+
const unsigned rsa_size = RSA_size(rsa);
BIGNUM *f, *result;
- int ret = 0;
int r = -1;
- uint8_t *buf = NULL;
- BN_CTX *ctx = NULL;
if (max_out < rsa_size) {
OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
+ if (in_len != rsa_size) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN);
+ return 0;
+ }
+
if (!check_modulus_and_exponent_sizes(rsa)) {
return 0;
}
- ctx = BN_CTX_new();
+ BN_CTX *ctx = BN_CTX_new();
if (ctx == NULL) {
- goto err;
+ return 0;
}
+ int ret = 0;
+ uint8_t *buf = NULL;
+
BN_CTX_start(ctx);
f = BN_CTX_get(ctx);
result = BN_CTX_get(ctx);
+ if (f == NULL || result == NULL) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
if (padding == RSA_NO_PADDING) {
buf = out;
} else {
@@ -446,15 +477,6 @@ int rsa_default_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out,
goto err;
}
}
- if (!f || !result) {
- OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- if (in_len != rsa_size) {
- OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN);
- goto err;
- }
if (BN_bin2bn(in, in_len, f) == NULL) {
goto err;
@@ -465,13 +487,8 @@ int rsa_default_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out,
goto err;
}
- if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
- if (BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) == NULL) {
- goto err;
- }
- }
-
- if (!rsa->meth->bn_mod_exp(result, f, rsa->e, rsa->n, ctx, rsa->mont_n)) {
+ if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) ||
+ !BN_mod_exp_mont(result, f, rsa->e, rsa->n, ctx, rsa->mont_n)) {
goto err;
}
@@ -500,12 +517,9 @@ int rsa_default_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out,
}
err:
- if (ctx != NULL) {
- BN_CTX_end(ctx);
- BN_CTX_free(ctx);
- }
- if (padding != RSA_NO_PADDING && buf != NULL) {
- OPENSSL_cleanse(buf, rsa_size);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ if (buf != out) {
OPENSSL_free(buf);
}
return ret;
@@ -542,21 +556,38 @@ int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
goto err;
}
- if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) {
+ if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx)) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /* We cannot do blinding or verification without |e|, and continuing without
+ * those countermeasures is dangerous. However, the Java/Android RSA API
+ * requires support for keys where only |d| and |n| (and not |e|) are known.
+ * The callers that require that bad behavior set |RSA_FLAG_NO_BLINDING|. */
+ int disable_security = (rsa->flags & RSA_FLAG_NO_BLINDING) && rsa->e == NULL;
+
+ if (!disable_security) {
+ /* Keys without public exponents must have blinding explicitly disabled to
+ * be used. */
+ if (rsa->e == NULL) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_NO_PUBLIC_EXPONENT);
+ goto err;
+ }
+
blinding = rsa_blinding_get(rsa, &blinding_index, ctx);
if (blinding == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
- if (!BN_BLINDING_convert(f, blinding, ctx)) {
+ if (!BN_BLINDING_convert(f, blinding, rsa->e, rsa->mont_n, ctx)) {
goto err;
}
}
- if ((rsa->flags & RSA_FLAG_EXT_PKEY) ||
- ((rsa->p != NULL) && (rsa->q != NULL) && (rsa->dmp1 != NULL) &&
- (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) {
- if (!rsa->meth->mod_exp(result, f, rsa, ctx)) {
+ if (rsa->p != NULL && rsa->q != NULL && rsa->e != NULL && rsa->dmp1 != NULL &&
+ rsa->dmq1 != NULL && rsa->iqmp != NULL) {
+ if (!mod_exp(result, f, rsa, ctx)) {
goto err;
}
} else {
@@ -567,20 +598,30 @@ int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
d = &local_d;
BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
- if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
- if (BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) ==
- NULL) {
- goto err;
- }
+ if (!BN_mod_exp_mont_consttime(result, f, d, rsa->n, ctx, rsa->mont_n)) {
+ goto err;
}
+ }
- if (!rsa->meth->bn_mod_exp(result, f, d, rsa->n, ctx, rsa->mont_n)) {
+ /* Verify the result to protect against fault attacks as described in the
+ * 1997 paper "On the Importance of Checking Cryptographic Protocols for
+ * Faults" by Dan Boneh, Richard A. DeMillo, and Richard J. Lipton. Some
+ * implementations do this only when the CRT is used, but we do it in all
+ * cases. Section 6 of the aforementioned paper describes an attack that
+ * works when the CRT isn't used. That attack is much less likely to succeed
+ * than the CRT attack, but there have likely been improvements since 1997.
+ *
+ * This check is cheap assuming |e| is small; it almost always is. */
+ if (!disable_security) {
+ BIGNUM *vrfy = BN_CTX_get(ctx);
+ if (vrfy == NULL ||
+ !BN_mod_exp_mont(vrfy, result, rsa->e, rsa->n, ctx, rsa->mont_n) ||
+ !BN_equal_consttime(vrfy, f)) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
- }
- if (blinding) {
- if (!BN_BLINDING_invert(result, blinding, ctx)) {
+ if (!BN_BLINDING_invert(result, blinding, rsa->mont_n, ctx)) {
goto err;
}
}
@@ -605,6 +646,17 @@ err:
}
static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
+ assert(ctx != NULL);
+
+ assert(rsa->n != NULL);
+ assert(rsa->e != NULL);
+ assert(rsa->d != NULL);
+ assert(rsa->p != NULL);
+ assert(rsa->q != NULL);
+ assert(rsa->dmp1 != NULL);
+ assert(rsa->dmq1 != NULL);
+ assert(rsa->iqmp != NULL);
+
BIGNUM *r1, *m1, *vrfy;
BIGNUM local_dmp1, local_dmq1, local_c, local_r1;
BIGNUM *dmp1, *dmq1, *c, *pr1;
@@ -619,6 +671,11 @@ static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
r1 = BN_CTX_get(ctx);
m1 = BN_CTX_get(ctx);
vrfy = BN_CTX_get(ctx);
+ if (r1 == NULL ||
+ m1 == NULL ||
+ vrfy == NULL) {
+ goto err;
+ }
{
BIGNUM local_p, local_q;
@@ -634,20 +691,14 @@ static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
q = &local_q;
BN_with_flags(q, rsa->q, BN_FLG_CONSTTIME);
- if (rsa->flags & RSA_FLAG_CACHE_PRIVATE) {
- if (BN_MONT_CTX_set_locked(&rsa->mont_p, &rsa->lock, p, ctx) == NULL) {
- goto err;
- }
- if (BN_MONT_CTX_set_locked(&rsa->mont_q, &rsa->lock, q, ctx) == NULL) {
- goto err;
- }
+ if (!BN_MONT_CTX_set_locked(&rsa->mont_p, &rsa->lock, p, ctx) ||
+ !BN_MONT_CTX_set_locked(&rsa->mont_q, &rsa->lock, q, ctx)) {
+ goto err;
}
}
- if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
- if (BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) == NULL) {
- goto err;
- }
+ if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx)) {
+ goto err;
}
/* compute I mod q */
@@ -660,7 +711,7 @@ static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
/* compute r1^dmq1 mod q */
dmq1 = &local_dmq1;
BN_with_flags(dmq1, rsa->dmq1, BN_FLG_CONSTTIME);
- if (!rsa->meth->bn_mod_exp(m1, r1, dmq1, rsa->q, ctx, rsa->mont_q)) {
+ if (!BN_mod_exp_mont_consttime(m1, r1, dmq1, rsa->q, ctx, rsa->mont_q)) {
goto err;
}
@@ -674,7 +725,7 @@ static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
/* compute r1^dmp1 mod p */
dmp1 = &local_dmp1;
BN_with_flags(dmp1, rsa->dmp1, BN_FLG_CONSTTIME);
- if (!rsa->meth->bn_mod_exp(r0, r1, dmp1, rsa->p, ctx, rsa->mont_p)) {
+ if (!BN_mod_exp_mont_consttime(r0, r1, dmp1, rsa->p, ctx, rsa->mont_p)) {
goto err;
}
@@ -734,12 +785,8 @@ static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
goto err;
}
- if ((rsa->flags & RSA_FLAG_CACHE_PRIVATE) &&
- !BN_MONT_CTX_set_locked(&ap->mont, &rsa->lock, prime, ctx)) {
- goto err;
- }
-
- if (!rsa->meth->bn_mod_exp(m1, r1, exp, prime, ctx, ap->mont)) {
+ if (!BN_MONT_CTX_set_locked(&ap->mont, &rsa->lock, prime, ctx) ||
+ !BN_mod_exp_mont_consttime(m1, r1, exp, prime, ctx, ap->mont)) {
goto err;
}
@@ -755,40 +802,6 @@ static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
}
}
- if (rsa->e && rsa->n) {
- if (!rsa->meth->bn_mod_exp(vrfy, r0, rsa->e, rsa->n, ctx, rsa->mont_n)) {
- goto err;
- }
- /* If 'I' was greater than (or equal to) rsa->n, the operation
- * will be equivalent to using 'I mod n'. However, the result of
- * the verify will *always* be less than 'n' so we don't check
- * for absolute equality, just congruency. */
- if (!BN_sub(vrfy, vrfy, I)) {
- goto err;
- }
- if (!BN_mod(vrfy, vrfy, rsa->n, ctx)) {
- goto err;
- }
- if (BN_is_negative(vrfy)) {
- if (!BN_add(vrfy, vrfy, rsa->n)) {
- goto err;
- }
- }
- if (!BN_is_zero(vrfy)) {
- /* 'I' and 'vrfy' aren't congruent mod n. Don't leak
- * miscalculated CRT output, just do a raw (slower)
- * mod_exp and return that instead. */
-
- BIGNUM local_d;
- BIGNUM *d = NULL;
-
- d = &local_d;
- BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
- if (!rsa->meth->bn_mod_exp(r0, I, d, rsa->n, ctx, rsa->mont_n)) {
- goto err;
- }
- }
- }
ret = 1;
err:
@@ -1090,9 +1103,9 @@ int rsa_default_keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
cb);
}
-/* Many of these methods are NULL to more easily drop unused functions. The
- * wrapper functions will select the appropriate |rsa_default_*| for all
- * methods. */
+/* All of the methods are NULL to make it easier for the compiler/linker to drop
+ * unused functions. The wrapper functions will select the appropriate
+ * |rsa_default_*| implementation. */
const RSA_METHOD RSA_default_method = {
{
0 /* references */,
@@ -1115,8 +1128,8 @@ const RSA_METHOD RSA_default_method = {
NULL /* private_transform (defaults to rsa_default_private_transform) */,
- mod_exp,
- BN_mod_exp_mont /* bn_mod_exp */,
+ NULL /* mod_exp (ignored) */,
+ NULL /* bn_mod_exp (ignored) */,
RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE,
diff --git a/crypto/rsa/rsa_test.cc b/crypto/rsa/rsa_test.cc
index 5545161c..62177a4c 100644
--- a/crypto/rsa/rsa_test.cc
+++ b/crypto/rsa/rsa_test.cc
@@ -63,7 +63,7 @@
#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include "../test/scoped_types.h"
@@ -593,6 +593,7 @@ static bool TestRSA(const uint8_t *der, size_t der_len,
fprintf(stderr, "Corrupt data decrypted!\n");
return false;
}
+ ERR_clear_error();
ciphertext[i] ^= 1;
}
@@ -603,6 +604,7 @@ static bool TestRSA(const uint8_t *der, size_t der_len,
fprintf(stderr, "Corrupt data decrypted!\n");
return false;
}
+ ERR_clear_error();
}
return true;
@@ -693,25 +695,27 @@ static bool TestBadKey() {
}
static bool TestOnlyDGiven() {
+ static const char kN[] =
+ "00e77bbf3889d4ef36a9a25d4d69f3f632eb4362214c74517da6d6aeaa9bd09ac42b2662"
+ "1cd88f3a6eb013772fc3bf9f83914b6467231c630202c35b3e5808c659";
+ static const char kE[] = "010001";
+ static const char kD[] =
+ "0365db9eb6d73b53b015c40cd8db4de7dd7035c68b5ac1bf786d7a4ee2cea316eaeca21a"
+ "73ac365e58713195f2ae9849348525ca855386b6d028e437a9495a01";
+
uint8_t buf[64];
unsigned buf_len = sizeof(buf);
ScopedRSA key(RSA_new());
if (!key ||
- !BN_hex2bn(&key->n,
- "00e77bbf3889d4ef36a9a25d4d69f3f632eb4362214c74517da6d6aeaa9bd"
- "09ac42b26621cd88f3a6eb013772fc3bf9f83914b6467231c630202c35b3e"
- "5808c659") ||
- !BN_hex2bn(&key->e, "010001") ||
- !BN_hex2bn(&key->d,
- "0365db9eb6d73b53b015c40cd8db4de7dd7035c68b5ac1bf786d7a4ee2cea"
- "316eaeca21a73ac365e58713195f2ae9849348525ca855386b6d028e437a9"
- "495a01") ||
+ !BN_hex2bn(&key->n, kN) ||
+ !BN_hex2bn(&key->e, kE) ||
+ !BN_hex2bn(&key->d, kD) ||
RSA_size(key.get()) > sizeof(buf)) {
return false;
}
if (!RSA_check_key(key.get())) {
- fprintf(stderr, "RSA_check_key failed with only d given.\n");
+ fprintf(stderr, "RSA_check_key failed with only n, d, and e given.\n");
ERR_print_errors_fp(stderr);
return false;
}
@@ -720,14 +724,46 @@ static bool TestOnlyDGiven() {
if (!RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, &buf_len,
key.get())) {
- fprintf(stderr, "RSA_sign failed with only d given.\n");
+ fprintf(stderr, "RSA_sign failed with only n, d, and e given.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ if (!RSA_verify(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, buf_len,
+ key.get())) {
+ fprintf(stderr, "RSA_verify failed with only n, d, and e given.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ // Keys without the public exponent must continue to work when blinding is
+ // disabled to support Java's RSAPrivateKeySpec API. See
+ // https://bugs.chromium.org/p/boringssl/issues/detail?id=12.
+ ScopedRSA key2(RSA_new());
+ if (!key2 ||
+ !BN_hex2bn(&key2->n, kN) ||
+ !BN_hex2bn(&key2->d, kD)) {
+ return false;
+ }
+ key2->flags |= RSA_FLAG_NO_BLINDING;
+
+ if (RSA_size(key2.get()) > sizeof(buf)) {
+ return false;
+ }
+
+ if (!RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, &buf_len,
+ key2.get())) {
+ fprintf(stderr, "RSA_sign failed with only n and d given.\n");
ERR_print_errors_fp(stderr);
return false;
}
+ // Verify the signature with |key|. |key2| has no public exponent.
if (!RSA_verify(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, buf_len,
key.get())) {
- fprintf(stderr, "RSA_verify failed with only d given.\n");
+ fprintf(stderr,
+ "Could not verify signature produced from key with only n and d "
+ "given.\n");
ERR_print_errors_fp(stderr);
return false;
}
diff --git a/crypto/sha/asm/sha512-armv4.pl b/crypto/sha/asm/sha512-armv4.pl
index cd3662a5..15d50f28 100644
--- a/crypto/sha/asm/sha512-armv4.pl
+++ b/crypto/sha/asm/sha512-armv4.pl
@@ -291,7 +291,7 @@ sha512_block_data_order:
#ifdef __APPLE__
ldr r12,[r12]
#endif
- tst r12,#1
+ tst r12,#ARMV7_NEON
bne .LNEON
#endif
add $len,$inp,$len,lsl#7 @ len to point at the end of inp
diff --git a/crypto/sha/sha256.c b/crypto/sha/sha256.c
index 0ddacbad..58f7c42c 100644
--- a/crypto/sha/sha256.c
+++ b/crypto/sha/sha256.c
@@ -104,8 +104,8 @@ uint8_t *SHA224(const uint8_t *data, size_t len, uint8_t *out) {
out = buf;
}
SHA224_Init(&ctx);
- SHA256_Update(&ctx, data, len);
- SHA256_Final(out, &ctx);
+ SHA224_Update(&ctx, data, len);
+ SHA224_Final(out, &ctx);
OPENSSL_cleanse(&ctx, sizeof(ctx));
return out;
}
diff --git a/crypto/sha/sha512.c b/crypto/sha/sha512.c
index 6ad8d40c..f4730463 100644
--- a/crypto/sha/sha512.c
+++ b/crypto/sha/sha512.c
@@ -129,8 +129,8 @@ uint8_t *SHA384(const uint8_t *data, size_t len, uint8_t *out) {
}
SHA384_Init(&ctx);
- SHA512_Update(&ctx, data, len);
- SHA512_Final(out, &ctx);
+ SHA384_Update(&ctx, data, len);
+ SHA384_Final(out, &ctx);
OPENSSL_cleanse(&ctx, sizeof(ctx));
return out;
}
diff --git a/crypto/stack/make_macros.sh b/crypto/stack/make_macros.sh
index 4837e449..3c3691b3 100644
--- a/crypto/stack/make_macros.sh
+++ b/crypto/stack/make_macros.sh
@@ -36,13 +36,13 @@ output_stack () {
((STACK_OF(${type})*) sk_new_null())
#define sk_${type}_num(sk)\\
- sk_num(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk))
+ sk_num(CHECKED_CAST(const _STACK*, const STACK_OF(${type})*, sk))
#define sk_${type}_zero(sk)\\
sk_zero(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk));
#define sk_${type}_value(sk, i)\\
- ((${ptrtype}) sk_value(CHECKED_CAST(_STACK*, const STACK_OF(${type})*, sk), (i)))
+ ((${ptrtype}) sk_value(CHECKED_CAST(const _STACK*, const STACK_OF(${type})*, sk), (i)))
#define sk_${type}_set(sk, i, p)\\
((${ptrtype}) sk_set(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), (i), CHECKED_CAST(void*, ${ptrtype}, p)))
@@ -75,13 +75,13 @@ output_stack () {
((${ptrtype}) sk_pop(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk)))
#define sk_${type}_dup(sk)\\
- ((STACK_OF(${type})*) sk_dup(CHECKED_CAST(_STACK*, const STACK_OF(${type})*, sk)))
+ ((STACK_OF(${type})*) sk_dup(CHECKED_CAST(const _STACK*, const STACK_OF(${type})*, sk)))
#define sk_${type}_sort(sk)\\
sk_sort(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk))
#define sk_${type}_is_sorted(sk)\\
- sk_is_sorted(CHECKED_CAST(_STACK*, const STACK_OF(${type})*, sk))
+ sk_is_sorted(CHECKED_CAST(const _STACK*, const STACK_OF(${type})*, sk))
#define sk_${type}_set_cmp_func(sk, comp)\\
((int (*) (const ${type} **a, const ${type} **b)) sk_set_cmp_func(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(stack_cmp_func, int (*) (const ${type} **a, const ${type} **b), comp)))
@@ -89,7 +89,6 @@ output_stack () {
#define sk_${type}_deep_copy(sk, copy_func, free_func)\\
((STACK_OF(${type})*) sk_deep_copy(CHECKED_CAST(const _STACK*, const STACK_OF(${type})*, sk), CHECKED_CAST(void* (*) (void*), ${ptrtype} (*) (${ptrtype}), copy_func), CHECKED_CAST(void (*) (void*), void (*) (${ptrtype}), free_func)))
-
EOF
}
diff --git a/crypto/stack/stack.c b/crypto/stack/stack.c
index c5845159..e8932217 100644
--- a/crypto/stack/stack.c
+++ b/crypto/stack/stack.c
@@ -329,7 +329,7 @@ err:
void sk_sort(_STACK *sk) {
int (*comp_func)(const void *,const void *);
- if (sk == NULL || sk->sorted) {
+ if (sk == NULL || sk->comp == NULL || sk->sorted) {
return;
}
diff --git a/crypto/test/file_test.cc b/crypto/test/file_test.cc
index d0447c34..d684aa09 100644
--- a/crypto/test/file_test.cc
+++ b/crypto/test/file_test.cc
@@ -14,6 +14,8 @@
#include "file_test.h"
+#include <memory>
+
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
@@ -73,10 +75,12 @@ FileTest::ReadResult FileTest::ReadNext() {
ClearTest();
+ static const size_t kBufLen = 64 + 8192*2;
+ std::unique_ptr<char[]> buf(new char[kBufLen]);
+
while (true) {
// Read the next line.
- char buf[4096];
- if (fgets(buf, sizeof(buf), file_) == nullptr) {
+ if (fgets(buf.get(), kBufLen, file_) == nullptr) {
if (feof(file_)) {
// EOF is a valid terminator for a test.
return start_line_ > 0 ? kReadSuccess : kReadEOF;
@@ -86,7 +90,7 @@ FileTest::ReadResult FileTest::ReadNext() {
}
line_++;
- size_t len = strlen(buf);
+ size_t len = strlen(buf.get());
// Check for truncation.
if (len > 0 && buf[len - 1] != '\n' && !feof(file_)) {
fprintf(stderr, "Line %u too long.\n", line_);
@@ -100,14 +104,14 @@ FileTest::ReadResult FileTest::ReadNext() {
}
} else if (buf[0] != '#') { // Comment lines are ignored.
// Parse the line as an attribute.
- const char *delimiter = FindDelimiter(buf);
+ const char *delimiter = FindDelimiter(buf.get());
if (delimiter == nullptr) {
fprintf(stderr, "Line %u: Could not parse attribute.\n", line_);
return kReadError;
}
- std::string key = StripSpace(buf, delimiter - buf);
+ std::string key = StripSpace(buf.get(), delimiter - buf.get());
std::string value = StripSpace(delimiter + 1,
- buf + len - delimiter - 1);
+ buf.get() + len - delimiter - 1);
unused_attributes_.insert(key);
attributes_[key] = value;
diff --git a/crypto/test/file_test.h b/crypto/test/file_test.h
index e90cc86a..a8591277 100644
--- a/crypto/test/file_test.h
+++ b/crypto/test/file_test.h
@@ -20,19 +20,15 @@
#include <stdint.h>
#include <stdio.h>
-#if defined(_MSC_VER)
-#pragma warning(push)
-#pragma warning(disable: 4702)
-#endif
+OPENSSL_MSVC_PRAGMA(warning(push))
+OPENSSL_MSVC_PRAGMA(warning(disable: 4702))
#include <string>
#include <map>
#include <set>
#include <vector>
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
+OPENSSL_MSVC_PRAGMA(warning(pop))
// File-based test framework.
//
diff --git a/crypto/test/scoped_types.h b/crypto/test/scoped_types.h
index b5ae324d..2a2c3713 100644
--- a/crypto/test/scoped_types.h
+++ b/crypto/test/scoped_types.h
@@ -24,14 +24,17 @@
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
+#include <openssl/bytestring.h>
#include <openssl/cmac.h>
+#include <openssl/curve25519.h>
#include <openssl/dh.h>
+#include <openssl/ecdsa.h>
#include <openssl/ec.h>
#include <openssl/ec_key.h>
-#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
+#include <openssl/newhope.h>
#include <openssl/pkcs8.h>
#include <openssl/rsa.h>
#include <openssl/stack.h>
@@ -109,9 +112,11 @@ using ScopedEC_KEY = ScopedOpenSSLType<EC_KEY, EC_KEY_free>;
using ScopedEC_POINT = ScopedOpenSSLType<EC_POINT, EC_POINT_free>;
using ScopedEVP_PKEY = ScopedOpenSSLType<EVP_PKEY, EVP_PKEY_free>;
using ScopedEVP_PKEY_CTX = ScopedOpenSSLType<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
+using ScopedNEWHOPE_POLY = ScopedOpenSSLType<NEWHOPE_POLY, NEWHOPE_POLY_free>;
using ScopedPKCS8_PRIV_KEY_INFO = ScopedOpenSSLType<PKCS8_PRIV_KEY_INFO,
PKCS8_PRIV_KEY_INFO_free>;
using ScopedPKCS12 = ScopedOpenSSLType<PKCS12, PKCS12_free>;
+using ScopedSPAKE2_CTX = ScopedOpenSSLType<SPAKE2_CTX, SPAKE2_CTX_free>;
using ScopedRSA = ScopedOpenSSLType<RSA, RSA_free>;
using ScopedX509 = ScopedOpenSSLType<X509, X509_free>;
using ScopedX509_ALGOR = ScopedOpenSSLType<X509_ALGOR, X509_ALGOR_free>;
diff --git a/crypto/thread.c b/crypto/thread.c
index 88371159..373f8dbc 100644
--- a/crypto/thread.c
+++ b/crypto/thread.c
@@ -61,9 +61,9 @@
#if !defined(OPENSSL_WINDOWS)
#include <errno.h>
#else
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
#endif
#include <openssl/mem.h>
@@ -74,6 +74,11 @@ int CRYPTO_num_locks(void) { return 1; }
void CRYPTO_set_locking_callback(void (*func)(int mode, int lock_num,
const char *file, int line)) {}
+void (*CRYPTO_get_locking_callback(void))(int mode, int lock_num,
+ const char *file, int line) {
+ return NULL;
+}
+
void CRYPTO_set_add_lock_callback(int (*func)(int *num, int mount, int lock_num,
const char *file, int line)) {}
@@ -99,3 +104,19 @@ void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)(
void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)(
struct CRYPTO_dynlock_value *l, const char *file, int line)) {}
+
+struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void))(
+ const char *file, int line) {
+ return NULL;
+}
+
+void (*CRYPTO_get_dynlock_lock_callback(void))(int mode,
+ struct CRYPTO_dynlock_value *l,
+ const char *file, int line) {
+ return NULL;
+}
+
+void (*CRYPTO_get_dynlock_destroy_callback(void))(
+ struct CRYPTO_dynlock_value *l, const char *file, int line) {
+ return NULL;
+}
diff --git a/crypto/thread_none.c b/crypto/thread_none.c
index cf4e85a7..85768b4b 100644
--- a/crypto/thread_none.c
+++ b/crypto/thread_none.c
@@ -22,7 +22,9 @@ void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) {}
void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) {}
-void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) {}
+void CRYPTO_MUTEX_unlock_read(CRYPTO_MUTEX *lock) {}
+
+void CRYPTO_MUTEX_unlock_write(CRYPTO_MUTEX *lock) {}
void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) {}
@@ -30,7 +32,9 @@ void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) {}
void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) {}
-void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) {}
+void CRYPTO_STATIC_MUTEX_unlock_read(struct CRYPTO_STATIC_MUTEX *lock) {}
+
+void CRYPTO_STATIC_MUTEX_unlock_write(struct CRYPTO_STATIC_MUTEX *lock) {}
void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) {
if (*once) {
diff --git a/crypto/thread_pthread.c b/crypto/thread_pthread.c
index 68aaab5b..2baa2b4d 100644
--- a/crypto/thread_pthread.c
+++ b/crypto/thread_pthread.c
@@ -17,7 +17,6 @@
#if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_THREADS)
#include <pthread.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -46,7 +45,13 @@ void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) {
}
}
-void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) {
+void CRYPTO_MUTEX_unlock_read(CRYPTO_MUTEX *lock) {
+ if (pthread_rwlock_unlock((pthread_rwlock_t *) lock) != 0) {
+ abort();
+ }
+}
+
+void CRYPTO_MUTEX_unlock_write(CRYPTO_MUTEX *lock) {
if (pthread_rwlock_unlock((pthread_rwlock_t *) lock) != 0) {
abort();
}
@@ -68,7 +73,13 @@ void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) {
}
}
-void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) {
+void CRYPTO_STATIC_MUTEX_unlock_read(struct CRYPTO_STATIC_MUTEX *lock) {
+ if (pthread_rwlock_unlock(&lock->lock) != 0) {
+ abort();
+ }
+}
+
+void CRYPTO_STATIC_MUTEX_unlock_write(struct CRYPTO_STATIC_MUTEX *lock) {
if (pthread_rwlock_unlock(&lock->lock) != 0) {
abort();
}
@@ -76,8 +87,6 @@ void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) {
void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) {
if (pthread_once(once, init) != 0) {
- fprintf(stderr,
- "pthread_once failed. Did you link against a threading library?\n");
abort();
}
}
diff --git a/crypto/thread_test.c b/crypto/thread_test.c
index e028b1be..12ca2ec0 100644
--- a/crypto/thread_test.c
+++ b/crypto/thread_test.c
@@ -21,9 +21,9 @@
#if defined(OPENSSL_WINDOWS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
typedef HANDLE thread_t;
@@ -53,6 +53,8 @@ static int wait_for_thread(thread_t thread) {
#else
#include <pthread.h>
+#include <string.h>
+#include <time.h>
typedef pthread_t thread_t;
@@ -77,6 +79,17 @@ static unsigned g_once_init_called = 0;
static void once_init(void) {
g_once_init_called++;
+
+ /* Sleep briefly so one |call_once_thread| instance will call |CRYPTO_once|
+ * while the other is running this function. */
+#if defined(OPENSSL_WINDOWS)
+ Sleep(1 /* milliseconds */);
+#else
+ struct timespec req;
+ memset(&req, 0, sizeof(req));
+ req.tv_nsec = 1000000;
+ nanosleep(&req, NULL);
+#endif
}
static CRYPTO_once_t g_test_once = CRYPTO_ONCE_INIT;
@@ -91,9 +104,11 @@ static int test_once(void) {
return 0;
}
- thread_t thread;
- if (!run_thread(&thread, call_once_thread) ||
- !wait_for_thread(thread)) {
+ thread_t thread1, thread2;
+ if (!run_thread(&thread1, call_once_thread) ||
+ !run_thread(&thread2, call_once_thread) ||
+ !wait_for_thread(thread1) ||
+ !wait_for_thread(thread2)) {
fprintf(stderr, "thread failed.\n");
return 0;
}
diff --git a/crypto/thread_win.c b/crypto/thread_win.c
index e48ab5f5..c7a90f7e 100644
--- a/crypto/thread_win.c
+++ b/crypto/thread_win.c
@@ -16,11 +16,10 @@
#if defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_THREADS)
-#pragma warning(push, 3)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-#pragma warning(pop)
+OPENSSL_MSVC_PRAGMA(warning(pop))
-#include <assert.h>
#include <stdlib.h>
#include <string.h>
@@ -28,110 +27,59 @@
#include <openssl/type_check.h>
-OPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(CRITICAL_SECTION),
+OPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(SRWLOCK),
CRYPTO_MUTEX_too_small);
-union run_once_arg_t {
- void (*func)(void);
- void *data;
-};
-
-static void run_once(CRYPTO_once_t *once, void (*init)(union run_once_arg_t),
- union run_once_arg_t arg) {
- /* Values must be aligned. */
- assert((((uintptr_t) once) & 3) == 0);
-
- /* This assumes that reading *once has acquire semantics. This should be true
- * on x86 and x86-64, where we expect Windows to run. */
-#if !defined(OPENSSL_X86) && !defined(OPENSSL_X86_64)
-#error "Windows once code may not work on other platforms." \
- "You can use InitOnceBeginInitialize on >=Vista"
-#endif
- if (*once == 1) {
- return;
- }
-
- for (;;) {
- switch (InterlockedCompareExchange(once, 2, 0)) {
- case 0:
- /* The value was zero so we are the first thread to call |CRYPTO_once|
- * on it. */
- init(arg);
- /* Write one to indicate that initialisation is complete. */
- InterlockedExchange(once, 1);
- return;
-
- case 1:
- /* Another thread completed initialisation between our fast-path check
- * and |InterlockedCompareExchange|. */
- return;
-
- case 2:
- /* Another thread is running the initialisation. Switch to it then try
- * again. */
- SwitchToThread();
- break;
-
- default:
- abort();
- }
- }
-}
-
-static void call_once_init(union run_once_arg_t arg) {
- arg.func();
+static BOOL CALLBACK call_once_init(INIT_ONCE *once, void *arg, void **out) {
+ void (**init)(void) = (void (**)(void))arg;
+ (**init)();
+ return TRUE;
}
-void CRYPTO_once(CRYPTO_once_t *in_once, void (*init)(void)) {
- union run_once_arg_t arg;
- arg.func = init;
- run_once(in_once, call_once_init, arg);
+void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) {
+ if (!InitOnceExecuteOnce(once, call_once_init, &init, NULL)) {
+ abort();
+ }
}
void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) {
- if (!InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION *) lock, 0x400)) {
- abort();
- }
+ InitializeSRWLock((SRWLOCK *) lock);
}
void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) {
- /* Since we have to support Windows XP, read locks are actually exclusive. */
- EnterCriticalSection((CRITICAL_SECTION *) lock);
+ AcquireSRWLockShared((SRWLOCK *) lock);
}
void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) {
- EnterCriticalSection((CRITICAL_SECTION *) lock);
+ AcquireSRWLockExclusive((SRWLOCK *) lock);
}
-void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) {
- LeaveCriticalSection((CRITICAL_SECTION *) lock);
+void CRYPTO_MUTEX_unlock_read(CRYPTO_MUTEX *lock) {
+ ReleaseSRWLockShared((SRWLOCK *) lock);
}
-void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) {
- DeleteCriticalSection((CRITICAL_SECTION *) lock);
+void CRYPTO_MUTEX_unlock_write(CRYPTO_MUTEX *lock) {
+ ReleaseSRWLockExclusive((SRWLOCK *) lock);
}
-static void static_lock_init(union run_once_arg_t arg) {
- struct CRYPTO_STATIC_MUTEX *lock = arg.data;
- if (!InitializeCriticalSectionAndSpinCount(&lock->lock, 0x400)) {
- abort();
- }
+void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) {
+ /* SRWLOCKs require no cleanup. */
}
void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) {
- union run_once_arg_t arg;
- arg.data = lock;
- /* Since we have to support Windows XP, read locks are actually exclusive. */
- run_once(&lock->once, static_lock_init, arg);
- EnterCriticalSection(&lock->lock);
+ AcquireSRWLockShared(&lock->lock);
}
void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) {
- CRYPTO_STATIC_MUTEX_lock_read(lock);
+ AcquireSRWLockExclusive(&lock->lock);
+}
+
+void CRYPTO_STATIC_MUTEX_unlock_read(struct CRYPTO_STATIC_MUTEX *lock) {
+ ReleaseSRWLockShared(&lock->lock);
}
-void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) {
- LeaveCriticalSection(&lock->lock);
+void CRYPTO_STATIC_MUTEX_unlock_write(struct CRYPTO_STATIC_MUTEX *lock) {
+ ReleaseSRWLockExclusive(&lock->lock);
}
static CRITICAL_SECTION g_destructors_lock;
@@ -150,9 +98,14 @@ static void thread_local_init(void) {
g_thread_local_failed = (g_thread_local_key == TLS_OUT_OF_INDEXES);
}
-static void NTAPI thread_local_destructor(PVOID module,
- DWORD reason, PVOID reserved) {
- if (DLL_THREAD_DETACH != reason && DLL_PROCESS_DETACH != reason) {
+static void NTAPI thread_local_destructor(PVOID module, DWORD reason,
+ PVOID reserved) {
+ /* Only free memory on |DLL_THREAD_DETACH|, not |DLL_PROCESS_DETACH|. In
+ * VS2015's debug runtime, the C runtime has been unloaded by the time
+ * |DLL_PROCESS_DETACH| runs. See https://crbug.com/575795. This is consistent
+ * with |pthread_key_create| which does not call destructors on process exit,
+ * only thread exit. */
+ if (reason != DLL_THREAD_DETACH) {
return;
}
diff --git a/crypto/x509/CMakeLists.txt b/crypto/x509/CMakeLists.txt
index de98eedf..bc867860 100644
--- a/crypto/x509/CMakeLists.txt
+++ b/crypto/x509/CMakeLists.txt
@@ -9,11 +9,13 @@ add_library(
a_sign.c
a_strex.c
a_verify.c
+ algorithm.c
asn1_gen.c
by_dir.c
by_file.c
i2d_pr.c
pkcs7.c
+ rsa_pss.c
t_crl.c
t_req.c
t_x509.c
diff --git a/crypto/x509/a_sign.c b/crypto/x509/a_sign.c
index 74f23438..13a3ac25 100644
--- a/crypto/x509/a_sign.c
+++ b/crypto/x509/a_sign.c
@@ -62,7 +62,7 @@
#include <openssl/obj.h>
#include <openssl/x509.h>
-#include "../evp/internal.h"
+#include "internal.h"
int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1,
X509_ALGOR *algor2, ASN1_BIT_STRING *signature, void *asn,
@@ -88,10 +88,10 @@ int ASN1_item_sign_ctx(const ASN1_ITEM *it,
pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
/* Write out the requested copies of the AlgorithmIdentifier. */
- if (algor1 && !EVP_DigestSignAlgorithm(ctx, algor1)) {
+ if (algor1 && !x509_digest_sign_algorithm(ctx, algor1)) {
goto err;
}
- if (algor2 && !EVP_DigestSignAlgorithm(ctx, algor2)) {
+ if (algor2 && !x509_digest_sign_algorithm(ctx, algor2)) {
goto err;
}
diff --git a/crypto/x509/a_verify.c b/crypto/x509/a_verify.c
index 969591c0..5a9adb65 100644
--- a/crypto/x509/a_verify.c
+++ b/crypto/x509/a_verify.c
@@ -68,7 +68,7 @@
#include <openssl/mem.h>
#include <openssl/obj.h>
-#include "../evp/internal.h"
+#include "internal.h"
int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a,
ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey)
@@ -89,7 +89,7 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a,
EVP_MD_CTX_init(&ctx);
- if (!EVP_DigestVerifyInitFromAlgorithm(&ctx, a, pkey)) {
+ if (!x509_digest_verify_init(&ctx, a, pkey)) {
goto err;
}
diff --git a/crypto/evp/algorithm.c b/crypto/x509/algorithm.c
index 63bc77af..78ae882b 100644
--- a/crypto/evp/algorithm.c
+++ b/crypto/x509/algorithm.c
@@ -54,100 +54,84 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
-#include <openssl/evp.h>
-
-#include <assert.h>
+#include <openssl/x509.h>
#include <openssl/asn1.h>
+#include <openssl/digest.h>
#include <openssl/err.h>
+#include <openssl/evp.h>
#include <openssl/obj.h>
-#include <openssl/x509.h>
#include "internal.h"
-int EVP_DigestSignAlgorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) {
- const EVP_MD *digest;
- EVP_PKEY *pkey;
- int sign_nid, paramtype;
-
- digest = EVP_MD_CTX_md(ctx);
- pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
- if (!digest || !pkey) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_CONTEXT_NOT_INITIALISED);
+int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) {
+ const EVP_MD *digest = EVP_MD_CTX_md(ctx);
+ EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
+ if (digest == NULL || pkey == NULL) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_R_CONTEXT_NOT_INITIALISED);
return 0;
}
- if (pkey->ameth->digest_sign_algorithm) {
- switch (pkey->ameth->digest_sign_algorithm(ctx, algor)) {
- case EVP_DIGEST_SIGN_ALGORITHM_ERROR:
- return 0;
- case EVP_DIGEST_SIGN_ALGORITHM_SUCCESS:
- return 1;
- case EVP_DIGEST_SIGN_ALGORITHM_DEFAULT:
- /* Use default behavior. */
- break;
- default:
- assert(0);
+ if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) {
+ int pad_mode;
+ if (!EVP_PKEY_CTX_get_rsa_padding(ctx->pctx, &pad_mode)) {
+ return 0;
+ }
+ /* RSA-PSS has special signature algorithm logic. */
+ if (pad_mode == RSA_PKCS1_PSS_PADDING) {
+ return x509_rsa_ctx_to_pss(ctx, algor);
}
}
/* Default behavior: look up the OID for the algorithm/hash pair and encode
* that. */
+ int sign_nid;
if (!OBJ_find_sigid_by_algs(&sign_nid, EVP_MD_type(digest),
- pkey->ameth->pkey_id)) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
+ EVP_PKEY_id(pkey))) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
return 0;
}
- if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL) {
- paramtype = V_ASN1_NULL;
- } else {
- paramtype = V_ASN1_UNDEF;
- }
-
+ /* RSA signature algorithms include an explicit NULL parameter. Others omit
+ * it. */
+ int paramtype =
+ (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) ? V_ASN1_NULL : V_ASN1_UNDEF;
X509_ALGOR_set0(algor, OBJ_nid2obj(sign_nid), paramtype, NULL);
return 1;
}
-int EVP_DigestVerifyInitFromAlgorithm(EVP_MD_CTX *ctx,
- X509_ALGOR *algor,
- EVP_PKEY *pkey) {
+int x509_digest_verify_init(EVP_MD_CTX *ctx, X509_ALGOR *sigalg,
+ EVP_PKEY *pkey) {
+ /* Convert the signature OID into digest and public key OIDs. */
+ int sigalg_nid = OBJ_obj2nid(sigalg->algorithm);
int digest_nid, pkey_nid;
- const EVP_PKEY_ASN1_METHOD *ameth;
- const EVP_MD *digest;
-
- /* Convert signature OID into digest and public key OIDs */
- if (!OBJ_find_sigid_algs(OBJ_obj2nid(algor->algorithm), &digest_nid,
- &pkey_nid)) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_SIGNATURE_ALGORITHM);
+ if (!OBJ_find_sigid_algs(sigalg_nid, &digest_nid, &pkey_nid)) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
return 0;
}
- /* Check public key OID matches public key type */
- ameth = EVP_PKEY_asn1_find(NULL, pkey_nid);
- if (ameth == NULL || ameth->pkey_id != pkey->ameth->pkey_id) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_WRONG_PUBLIC_KEY_TYPE);
+ /* Check the public key OID matches the public key type. */
+ if (pkey_nid != EVP_PKEY_id(pkey)) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_R_WRONG_PUBLIC_KEY_TYPE);
return 0;
}
/* NID_undef signals that there are custom parameters to set. */
if (digest_nid == NID_undef) {
- if (!pkey->ameth || !pkey->ameth->digest_verify_init_from_algorithm) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_SIGNATURE_ALGORITHM);
+ if (sigalg_nid != NID_rsassaPss) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
return 0;
}
-
- return pkey->ameth->digest_verify_init_from_algorithm(ctx, algor, pkey);
+ return x509_rsa_pss_to_ctx(ctx, sigalg, pkey);
}
/* Otherwise, initialize with the digest from the OID. */
- digest = EVP_get_digestbynid(digest_nid);
+ const EVP_MD *digest = EVP_get_digestbynid(digest_nid);
if (digest == NULL) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
+ OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
return 0;
}
return EVP_DigestVerifyInit(ctx, NULL, digest, NULL, pkey);
}
-
diff --git a/crypto/x509/asn1_gen.c b/crypto/x509/asn1_gen.c
index 0660840f..03a0ab9f 100644
--- a/crypto/x509/asn1_gen.c
+++ b/crypto/x509/asn1_gen.c
@@ -142,7 +142,6 @@ ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf)
}
ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf)
- OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS
{
ASN1_TYPE *ret;
tag_exp_arg asn1_tags;
@@ -155,7 +154,7 @@ ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf)
unsigned char *p;
const unsigned char *cp;
int cpy_len;
- long hdr_len;
+ long hdr_len = 0;
int hdr_constructed = 0, hdr_tag, hdr_class;
int r;
diff --git a/crypto/x509/by_dir.c b/crypto/x509/by_dir.c
index 4f0a49e2..4445b058 100644
--- a/crypto/x509/by_dir.c
+++ b/crypto/x509/by_dir.c
@@ -327,7 +327,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
hent = NULL;
k = 0;
}
- CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&g_ent_hashes_lock);
} else {
k = 0;
hent = NULL;
@@ -392,7 +392,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
if (sk_X509_OBJECT_find(xl->store_ctx->objs, &idx, &stmp)) {
tmp = sk_X509_OBJECT_value(xl->store_ctx->objs, idx);
}
- CRYPTO_MUTEX_unlock(&xl->store_ctx->objs_lock);
+ CRYPTO_MUTEX_unlock_write(&xl->store_ctx->objs_lock);
/*
* If a CRL, update the last file suffix added for this
@@ -412,14 +412,14 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
if (!hent) {
hent = OPENSSL_malloc(sizeof(BY_DIR_HASH));
if (hent == NULL) {
- CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&g_ent_hashes_lock);
ok = 0;
goto finish;
}
hent->hash = h;
hent->suffix = k;
if (!sk_BY_DIR_HASH_push(ent->hashes, hent)) {
- CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&g_ent_hashes_lock);
OPENSSL_free(hent);
ok = 0;
goto finish;
@@ -427,7 +427,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
} else if (hent->suffix < k)
hent->suffix = k;
- CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&g_ent_hashes_lock);
}
if (tmp != NULL) {
diff --git a/crypto/x509/internal.h b/crypto/x509/internal.h
new file mode 100644
index 00000000..4957c1e1
--- /dev/null
+++ b/crypto/x509/internal.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_X509_INTERNAL_H
+#define OPENSSL_HEADER_X509_INTERNAL_H
+
+#include <openssl/base.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* RSA-PSS functions. */
+
+/* x509_rsa_pss_to_ctx configures |ctx| for an RSA-PSS operation based on
+ * signature algorithm parameters in |sigalg| (which must have type
+ * |NID_rsassaPss|) and key |pkey|. It returns one on success and zero on
+ * error. */
+int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, EVP_PKEY *pkey);
+
+/* x509_rsa_pss_to_ctx sets |algor| to the signature algorithm parameters for
+ * |ctx|, which must have been configured for an RSA-PSS signing operation. It
+ * returns one on success and zero on error. */
+int x509_rsa_ctx_to_pss(EVP_MD_CTX *ctx, X509_ALGOR *algor);
+
+/* x509_print_rsa_pss_params prints a human-readable representation of RSA-PSS
+ * parameters in |sigalg| to |bp|. It returns one on success and zero on
+ * error. */
+int x509_print_rsa_pss_params(BIO *bp, const X509_ALGOR *sigalg, int indent,
+ ASN1_PCTX *pctx);
+
+
+/* Signature algorithm functions. */
+
+/* x509_digest_sign_algorithm encodes the signing parameters of |ctx| as an
+ * AlgorithmIdentifer and saves the result in |algor|. It returns one on
+ * success, or zero on error. */
+int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor);
+
+/* x509_digest_verify_init sets up |ctx| for a signature verification operation
+ * with public key |pkey| and parameters from |algor|. The |ctx| argument must
+ * have been initialised with |EVP_MD_CTX_init|. It returns one on success, or
+ * zero on error. */
+int x509_digest_verify_init(EVP_MD_CTX *ctx, X509_ALGOR *sigalg,
+ EVP_PKEY *pkey);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_X509_INTERNAL_H */
diff --git a/crypto/x509/pkcs7_test.c b/crypto/x509/pkcs7_test.c
index 38beb3e8..bebcbd95 100644
--- a/crypto/x509/pkcs7_test.c
+++ b/crypto/x509/pkcs7_test.c
@@ -22,6 +22,8 @@
#include <openssl/stack.h>
#include <openssl/x509.h>
+#include "../test/test_util.h"
+
/* kPKCS7NSS contains the certificate chain of mail.google.com, as saved by NSS
* using the Chrome UI. */
@@ -504,7 +506,7 @@ static int test_cert_reparse(const uint8_t *der_bytes, size_t der_len) {
X509 *b = sk_X509_value(certs2, i);
if (X509_cmp(a, b) != 0) {
- fprintf(stderr, "Certificate %u differs.\n", (unsigned) i);
+ fprintf(stderr, "Certificate %zu differs.\n", i);
return 0;
}
}
@@ -568,7 +570,7 @@ static int test_crl_reparse(const uint8_t *der_bytes, size_t der_len) {
X509_CRL *b = sk_X509_CRL_value(crls2, i);
if (X509_CRL_cmp(a, b) != 0) {
- fprintf(stderr, "CRL %u differs.\n", (unsigned) i);
+ fprintf(stderr, "CRL %zu differs.\n", i);
return 0;
}
}
@@ -596,7 +598,7 @@ static int test_crl_reparse(const uint8_t *der_bytes, size_t der_len) {
}
static int test_pem_certs(const char *pem) {
- BIO *bio = BIO_new_mem_buf((char *) pem, strlen(pem));
+ BIO *bio = BIO_new_mem_buf(pem, strlen(pem));
STACK_OF(X509) *certs = sk_X509_new_null();
if (!PKCS7_get_PEM_certificates(certs, bio)) {
@@ -606,8 +608,8 @@ static int test_pem_certs(const char *pem) {
if (sk_X509_num(certs) != 1) {
fprintf(stderr,
- "Bad number of certificates from PKCS7_get_PEM_certificates: %u\n",
- (unsigned)sk_X509_num(certs));
+ "Bad number of certificates from PKCS7_get_PEM_certificates: %zu\n",
+ sk_X509_num(certs));
return 0;
}
@@ -618,7 +620,7 @@ static int test_pem_certs(const char *pem) {
}
static int test_pem_crls(const char *pem) {
- BIO *bio = BIO_new_mem_buf((char *) pem, strlen(pem));
+ BIO *bio = BIO_new_mem_buf(pem, strlen(pem));
STACK_OF(X509_CRL) *crls = sk_X509_CRL_new_null();
if (!PKCS7_get_PEM_CRLs(crls, bio)) {
@@ -627,9 +629,8 @@ static int test_pem_crls(const char *pem) {
}
if (sk_X509_CRL_num(crls) != 1) {
- fprintf(stderr,
- "Bad number of CRLs from PKCS7_get_PEM_CRLs: %u\n",
- (unsigned)sk_X509_CRL_num(crls));
+ fprintf(stderr, "Bad number of CRLs from PKCS7_get_PEM_CRLs: %zu\n",
+ sk_X509_CRL_num(crls));
return 0;
}
@@ -653,4 +654,3 @@ int main(void) {
printf("PASS\n");
return 0;
}
-
diff --git a/crypto/x509/rsa_pss.c b/crypto/x509/rsa_pss.c
new file mode 100644
index 00000000..1ae01a3d
--- /dev/null
+++ b/crypto/x509/rsa_pss.c
@@ -0,0 +1,385 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com). */
+
+#include <openssl/x509.h>
+
+#include <assert.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+ASN1_SEQUENCE(RSA_PSS_PARAMS) = {
+ ASN1_EXP_OPT(RSA_PSS_PARAMS, hashAlgorithm, X509_ALGOR,0),
+ ASN1_EXP_OPT(RSA_PSS_PARAMS, maskGenAlgorithm, X509_ALGOR,1),
+ ASN1_EXP_OPT(RSA_PSS_PARAMS, saltLength, ASN1_INTEGER,2),
+ ASN1_EXP_OPT(RSA_PSS_PARAMS, trailerField, ASN1_INTEGER,3),
+} ASN1_SEQUENCE_END(RSA_PSS_PARAMS);
+
+IMPLEMENT_ASN1_FUNCTIONS(RSA_PSS_PARAMS);
+
+
+/* Given an MGF1 Algorithm ID decode to an Algorithm Identifier */
+static X509_ALGOR *rsa_mgf1_decode(X509_ALGOR *alg) {
+ if (alg == NULL || alg->parameter == NULL ||
+ OBJ_obj2nid(alg->algorithm) != NID_mgf1 ||
+ alg->parameter->type != V_ASN1_SEQUENCE) {
+ return NULL;
+ }
+
+ const uint8_t *p = alg->parameter->value.sequence->data;
+ int plen = alg->parameter->value.sequence->length;
+ return d2i_X509_ALGOR(NULL, &p, plen);
+}
+
+static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg,
+ X509_ALGOR **pmaskHash) {
+ *pmaskHash = NULL;
+
+ if (alg->parameter == NULL || alg->parameter->type != V_ASN1_SEQUENCE) {
+ return NULL;
+ }
+
+ const uint8_t *p = alg->parameter->value.sequence->data;
+ int plen = alg->parameter->value.sequence->length;
+ RSA_PSS_PARAMS *pss = d2i_RSA_PSS_PARAMS(NULL, &p, plen);
+ if (pss == NULL) {
+ return NULL;
+ }
+
+ *pmaskHash = rsa_mgf1_decode(pss->maskGenAlgorithm);
+ return pss;
+}
+
+/* allocate and set algorithm ID from EVP_MD, default SHA1 */
+static int rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md) {
+ if (EVP_MD_type(md) == NID_sha1) {
+ return 1;
+ }
+ *palg = X509_ALGOR_new();
+ if (*palg == NULL) {
+ return 0;
+ }
+ X509_ALGOR_set_md(*palg, md);
+ return 1;
+}
+
+/* Allocate and set MGF1 algorithm ID from EVP_MD */
+static int rsa_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md) {
+ X509_ALGOR *algtmp = NULL;
+ ASN1_STRING *stmp = NULL;
+ *palg = NULL;
+
+ if (EVP_MD_type(mgf1md) == NID_sha1) {
+ return 1;
+ }
+ /* need to embed algorithm ID inside another */
+ if (!rsa_md_to_algor(&algtmp, mgf1md) ||
+ !ASN1_item_pack(algtmp, ASN1_ITEM_rptr(X509_ALGOR), &stmp)) {
+ goto err;
+ }
+ *palg = X509_ALGOR_new();
+ if (!*palg) {
+ goto err;
+ }
+ X509_ALGOR_set0(*palg, OBJ_nid2obj(NID_mgf1), V_ASN1_SEQUENCE, stmp);
+ stmp = NULL;
+
+err:
+ ASN1_STRING_free(stmp);
+ X509_ALGOR_free(algtmp);
+ if (*palg) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/* convert algorithm ID to EVP_MD, default SHA1 */
+static const EVP_MD *rsa_algor_to_md(X509_ALGOR *alg) {
+ const EVP_MD *md;
+ if (!alg) {
+ return EVP_sha1();
+ }
+ md = EVP_get_digestbyobj(alg->algorithm);
+ if (md == NULL) {
+ OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
+ }
+ return md;
+}
+
+/* convert MGF1 algorithm ID to EVP_MD, default SHA1 */
+static const EVP_MD *rsa_mgf1_to_md(X509_ALGOR *alg, X509_ALGOR *maskHash) {
+ const EVP_MD *md;
+ if (!alg) {
+ return EVP_sha1();
+ }
+ /* Check mask and lookup mask hash algorithm */
+ if (OBJ_obj2nid(alg->algorithm) != NID_mgf1 ||
+ maskHash == NULL) {
+ OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
+ return NULL;
+ }
+ md = EVP_get_digestbyobj(maskHash->algorithm);
+ if (md == NULL) {
+ OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
+ return NULL;
+ }
+ return md;
+}
+
+int x509_rsa_ctx_to_pss(EVP_MD_CTX *ctx, X509_ALGOR *algor) {
+ const EVP_MD *sigmd, *mgf1md;
+ int saltlen;
+ if (!EVP_PKEY_CTX_get_signature_md(ctx->pctx, &sigmd) ||
+ !EVP_PKEY_CTX_get_rsa_mgf1_md(ctx->pctx, &mgf1md) ||
+ !EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx->pctx, &saltlen)) {
+ return 0;
+ }
+
+ EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
+ if (saltlen == -1) {
+ saltlen = EVP_MD_size(sigmd);
+ } else if (saltlen == -2) {
+ saltlen = EVP_PKEY_size(pk) - EVP_MD_size(sigmd) - 2;
+ if (((EVP_PKEY_bits(pk) - 1) & 0x7) == 0) {
+ saltlen--;
+ }
+ } else {
+ return 0;
+ }
+
+ int ret = 0;
+ ASN1_STRING *os = NULL;
+ RSA_PSS_PARAMS *pss = RSA_PSS_PARAMS_new();
+ if (!pss) {
+ goto err;
+ }
+
+ if (saltlen != 20) {
+ pss->saltLength = ASN1_INTEGER_new();
+ if (!pss->saltLength ||
+ !ASN1_INTEGER_set(pss->saltLength, saltlen)) {
+ goto err;
+ }
+ }
+
+ if (!rsa_md_to_algor(&pss->hashAlgorithm, sigmd) ||
+ !rsa_md_to_mgf1(&pss->maskGenAlgorithm, mgf1md)) {
+ goto err;
+ }
+
+ /* Finally create string with pss parameter encoding. */
+ if (!ASN1_item_pack(pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), &os)) {
+ goto err;
+ }
+
+ X509_ALGOR_set0(algor, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os);
+ os = NULL;
+ ret = 1;
+
+err:
+ RSA_PSS_PARAMS_free(pss);
+ ASN1_STRING_free(os);
+ return ret;
+}
+
+int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, EVP_PKEY *pkey) {
+ assert(OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss);
+
+ /* Decode PSS parameters */
+ int ret = 0;
+ X509_ALGOR *maskHash;
+ RSA_PSS_PARAMS *pss = rsa_pss_decode(sigalg, &maskHash);
+ if (pss == NULL) {
+ OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
+ goto err;
+ }
+
+ const EVP_MD *mgf1md = rsa_mgf1_to_md(pss->maskGenAlgorithm, maskHash);
+ const EVP_MD *md = rsa_algor_to_md(pss->hashAlgorithm);
+ if (mgf1md == NULL || md == NULL) {
+ goto err;
+ }
+
+ int saltlen = 20;
+ if (pss->saltLength != NULL) {
+ saltlen = ASN1_INTEGER_get(pss->saltLength);
+
+ /* Could perform more salt length sanity checks but the main
+ * RSA routines will trap other invalid values anyway. */
+ if (saltlen < 0) {
+ OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
+ goto err;
+ }
+ }
+
+ /* low-level routines support only trailer field 0xbc (value 1)
+ * and PKCS#1 says we should reject any other value anyway. */
+ if (pss->trailerField != NULL && ASN1_INTEGER_get(pss->trailerField) != 1) {
+ OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PSS_PARAMETERS);
+ goto err;
+ }
+
+ EVP_PKEY_CTX *pkctx;
+ if (!EVP_DigestVerifyInit(ctx, &pkctx, md, NULL, pkey) ||
+ !EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING) ||
+ !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen) ||
+ !EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md)) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ RSA_PSS_PARAMS_free(pss);
+ X509_ALGOR_free(maskHash);
+ return ret;
+}
+
+int x509_print_rsa_pss_params(BIO *bp, const X509_ALGOR *sigalg, int indent,
+ ASN1_PCTX *pctx) {
+ assert(OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss);
+
+ int rv = 0;
+ X509_ALGOR *maskHash;
+ RSA_PSS_PARAMS *pss = rsa_pss_decode(sigalg, &maskHash);
+ if (!pss) {
+ if (BIO_puts(bp, " (INVALID PSS PARAMETERS)\n") <= 0) {
+ goto err;
+ }
+ rv = 1;
+ goto err;
+ }
+
+ if (BIO_puts(bp, "\n") <= 0 ||
+ !BIO_indent(bp, indent, 128) ||
+ BIO_puts(bp, "Hash Algorithm: ") <= 0) {
+ goto err;
+ }
+
+ if (pss->hashAlgorithm) {
+ if (i2a_ASN1_OBJECT(bp, pss->hashAlgorithm->algorithm) <= 0) {
+ goto err;
+ }
+ } else if (BIO_puts(bp, "sha1 (default)") <= 0) {
+ goto err;
+ }
+
+ if (BIO_puts(bp, "\n") <= 0 ||
+ !BIO_indent(bp, indent, 128) ||
+ BIO_puts(bp, "Mask Algorithm: ") <= 0) {
+ goto err;
+ }
+
+ if (pss->maskGenAlgorithm) {
+ if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0 ||
+ BIO_puts(bp, " with ") <= 0) {
+ goto err;
+ }
+
+ if (maskHash) {
+ if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0) {
+ goto err;
+ }
+ } else if (BIO_puts(bp, "INVALID") <= 0) {
+ goto err;
+ }
+ } else if (BIO_puts(bp, "mgf1 with sha1 (default)") <= 0) {
+ goto err;
+ }
+ BIO_puts(bp, "\n");
+
+ if (!BIO_indent(bp, indent, 128) ||
+ BIO_puts(bp, "Salt Length: 0x") <= 0) {
+ goto err;
+ }
+
+ if (pss->saltLength) {
+ if (i2a_ASN1_INTEGER(bp, pss->saltLength) <= 0) {
+ goto err;
+ }
+ } else if (BIO_puts(bp, "14 (default)") <= 0) {
+ goto err;
+ }
+ BIO_puts(bp, "\n");
+
+ if (!BIO_indent(bp, indent, 128) ||
+ BIO_puts(bp, "Trailer Field: 0x") <= 0) {
+ goto err;
+ }
+
+ if (pss->trailerField) {
+ if (i2a_ASN1_INTEGER(bp, pss->trailerField) <= 0) {
+ goto err;
+ }
+ } else if (BIO_puts(bp, "BC (default)") <= 0) {
+ goto err;
+ }
+ BIO_puts(bp, "\n");
+
+ rv = 1;
+
+err:
+ RSA_PSS_PARAMS_free(pss);
+ X509_ALGOR_free(maskHash);
+ return rv;
+}
diff --git a/crypto/x509/t_x509.c b/crypto/x509/t_x509.c
index 1afcf601..1fba9b43 100644
--- a/crypto/x509/t_x509.c
+++ b/crypto/x509/t_x509.c
@@ -64,7 +64,8 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
-#include "../evp/internal.h"
+#include "internal.h"
+
#ifndef OPENSSL_NO_FP_API
int X509_print_ex_fp(FILE *fp, X509 *x, unsigned long nmflag,
@@ -132,7 +133,8 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
goto err;
bs = X509_get_serialNumber(x);
- if (bs->length <= (int)sizeof(long)) {
+ if (bs->length < (int)sizeof(long)
+ || (bs->length == sizeof(long) && (bs->data[0] & 0x80) == 0)) {
l = ASN1_INTEGER_get(bs);
if (bs->type == V_ASN1_NEG_INTEGER) {
l = -l;
@@ -298,22 +300,18 @@ int X509_ocspid_print(BIO *bp, X509 *x)
int X509_signature_print(BIO *bp, X509_ALGOR *sigalg, ASN1_STRING *sig)
{
- int sig_nid;
if (BIO_puts(bp, " Signature Algorithm: ") <= 0)
return 0;
if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0)
return 0;
- sig_nid = OBJ_obj2nid(sigalg->algorithm);
- if (sig_nid != NID_undef) {
- int pkey_nid, dig_nid;
- const EVP_PKEY_ASN1_METHOD *ameth;
- if (OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid)) {
- ameth = EVP_PKEY_asn1_find(NULL, pkey_nid);
- if (ameth && ameth->sig_print)
- return ameth->sig_print(bp, sigalg, sig, 9, 0);
- }
+ /* RSA-PSS signatures have parameters to print. */
+ int sig_nid = OBJ_obj2nid(sigalg->algorithm);
+ if (sig_nid == NID_rsassaPss &&
+ !x509_print_rsa_pss_params(bp, sigalg, 9, 0)) {
+ return 0;
}
+
if (sig)
return X509_signature_dump(bp, sig, 9);
else if (BIO_puts(bp, "\n") <= 0)
diff --git a/crypto/x509/x509.c b/crypto/x509/x509.c
index 31f9e1eb..188fd496 100644
--- a/crypto/x509/x509.c
+++ b/crypto/x509/x509.c
@@ -57,9 +57,14 @@
#include <openssl/x509.h>
#include <openssl/bio.h>
+#include <openssl/err.h>
#include <openssl/mem.h>
+/* |X509_R_UNSUPPORTED_ALGORITHM| is no longer emitted, but continue to define
+ * it to avoid downstream churn. */
+OPENSSL_DECLARE_ERROR_REASON(X509, UNSUPPORTED_ALGORITHM)
+
int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj, int version,
int ptype, void *pval, uint8_t *penc, int penclen) {
uint8_t **ppenc = NULL;
diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c
index bfe6b11b..9f427dea 100644
--- a/crypto/x509/x509_lu.c
+++ b/crypto/x509/x509_lu.c
@@ -130,18 +130,18 @@ int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name,
X509_OBJECT *ret)
{
if ((ctx->method == NULL) || (ctx->method->get_by_subject == NULL))
- return X509_LU_FAIL;
+ return 0;
if (ctx->skip)
return 0;
- return ctx->method->get_by_subject(ctx, type, name, ret);
+ return ctx->method->get_by_subject(ctx, type, name, ret) > 0;
}
int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name,
ASN1_INTEGER *serial, X509_OBJECT *ret)
{
if ((ctx->method == NULL) || (ctx->method->get_by_issuer_serial == NULL))
- return X509_LU_FAIL;
- return ctx->method->get_by_issuer_serial(ctx, type, name, serial, ret);
+ return 0;
+ return ctx->method->get_by_issuer_serial(ctx, type, name, serial, ret) > 0;
}
int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type,
@@ -149,16 +149,16 @@ int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type,
X509_OBJECT *ret)
{
if ((ctx->method == NULL) || (ctx->method->get_by_fingerprint == NULL))
- return X509_LU_FAIL;
- return ctx->method->get_by_fingerprint(ctx, type, bytes, len, ret);
+ return 0;
+ return ctx->method->get_by_fingerprint(ctx, type, bytes, len, ret) > 0;
}
int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str, int len,
X509_OBJECT *ret)
{
if ((ctx->method == NULL) || (ctx->method->get_by_alias == NULL))
- return X509_LU_FAIL;
- return ctx->method->get_by_alias(ctx, type, str, len, ret);
+ return 0;
+ return ctx->method->get_by_alias(ctx, type, str, len, ret) > 0;
}
static int x509_object_cmp(const X509_OBJECT **a, const X509_OBJECT **b)
@@ -217,6 +217,11 @@ X509_STORE *X509_STORE_new(void)
return NULL;
}
+void X509_STORE_up_ref(X509_STORE *store)
+{
+ CRYPTO_refcount_inc(&store->references);
+}
+
static void cleanup(X509_OBJECT *a)
{
if (a == NULL) {
@@ -296,26 +301,20 @@ int X509_STORE_get_by_subject(X509_STORE_CTX *vs, int type, X509_NAME *name,
X509_STORE *ctx = vs->ctx;
X509_LOOKUP *lu;
X509_OBJECT stmp, *tmp;
- int i, j;
+ int i;
CRYPTO_MUTEX_lock_write(&ctx->objs_lock);
tmp = X509_OBJECT_retrieve_by_subject(ctx->objs, type, name);
- CRYPTO_MUTEX_unlock(&ctx->objs_lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->objs_lock);
if (tmp == NULL || type == X509_LU_CRL) {
- for (i = vs->current_method;
- i < (int)sk_X509_LOOKUP_num(ctx->get_cert_methods); i++) {
+ for (i = 0; i < (int)sk_X509_LOOKUP_num(ctx->get_cert_methods); i++) {
lu = sk_X509_LOOKUP_value(ctx->get_cert_methods, i);
- j = X509_LOOKUP_by_subject(lu, type, name, &stmp);
- if (j < 0) {
- vs->current_method = j;
- return j;
- } else if (j) {
+ if (X509_LOOKUP_by_subject(lu, type, name, &stmp)) {
tmp = &stmp;
break;
}
}
- vs->current_method = 0;
if (tmp == NULL)
return 0;
}
@@ -359,7 +358,7 @@ int X509_STORE_add_cert(X509_STORE *ctx, X509 *x)
} else
sk_X509_OBJECT_push(ctx->objs, obj);
- CRYPTO_MUTEX_unlock(&ctx->objs_lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->objs_lock);
return ret;
}
@@ -391,7 +390,7 @@ int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x)
} else
sk_X509_OBJECT_push(ctx->objs, obj);
- CRYPTO_MUTEX_unlock(&ctx->objs_lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->objs_lock);
return ret;
}
@@ -499,7 +498,7 @@ STACK_OF (X509) * X509_STORE_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm)
* cache
*/
X509_OBJECT xobj;
- CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock);
if (!X509_STORE_get_by_subject(ctx, X509_LU_X509, nm, &xobj)) {
sk_X509_free(sk);
return NULL;
@@ -508,7 +507,7 @@ STACK_OF (X509) * X509_STORE_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm)
CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock);
idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_X509, nm, &cnt);
if (idx < 0) {
- CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock);
sk_X509_free(sk);
return NULL;
}
@@ -517,13 +516,13 @@ STACK_OF (X509) * X509_STORE_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm)
obj = sk_X509_OBJECT_value(ctx->ctx->objs, idx);
x = obj->data.x509;
if (!sk_X509_push(sk, X509_up_ref(x))) {
- CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock);
X509_free(x);
sk_X509_pop_free(sk, X509_free);
return NULL;
}
}
- CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock);
return sk;
}
@@ -547,7 +546,7 @@ STACK_OF (X509_CRL) * X509_STORE_get1_crls(X509_STORE_CTX *ctx, X509_NAME *nm)
CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock);
idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_CRL, nm, &cnt);
if (idx < 0) {
- CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock);
sk_X509_CRL_free(sk);
return NULL;
}
@@ -557,13 +556,13 @@ STACK_OF (X509_CRL) * X509_STORE_get1_crls(X509_STORE_CTX *ctx, X509_NAME *nm)
x = obj->data.crl;
X509_CRL_up_ref(x);
if (!sk_X509_CRL_push(sk, x)) {
- CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock);
X509_CRL_free(x);
sk_X509_CRL_pop_free(sk, X509_CRL_free);
return NULL;
}
}
- CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock);
return sk;
}
@@ -606,22 +605,11 @@ int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
{
X509_NAME *xn;
X509_OBJECT obj, *pobj;
- int ok, idx, ret;
+ int idx, ret;
size_t i;
xn = X509_get_issuer_name(x);
- ok = X509_STORE_get_by_subject(ctx, X509_LU_X509, xn, &obj);
- if (ok != X509_LU_X509) {
- if (ok == X509_LU_RETRY) {
- X509_OBJECT_free_contents(&obj);
- OPENSSL_PUT_ERROR(X509, X509_R_SHOULD_RETRY);
- return -1;
- } else if (ok != X509_LU_FAIL) {
- X509_OBJECT_free_contents(&obj);
- /* not good :-(, break anyway */
- return -1;
- }
+ if (!X509_STORE_get_by_subject(ctx, X509_LU_X509, xn, &obj))
return 0;
- }
/* If certificate matches all OK */
if (ctx->check_issued(ctx, x, obj.data.x509)) {
*issuer = obj.data.x509;
@@ -651,7 +639,7 @@ int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
}
}
}
- CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock);
+ CRYPTO_MUTEX_unlock_write(&ctx->ctx->objs_lock);
return ret;
}
diff --git a/crypto/x509/x509_obj.c b/crypto/x509/x509_obj.c
index 641e308d..a7f31e03 100644
--- a/crypto/x509/x509_obj.c
+++ b/crypto/x509/x509_obj.c
@@ -64,6 +64,13 @@
#include <openssl/obj.h>
#include <openssl/x509.h>
+/*
+ * Limit to ensure we don't overflow: much greater than
+ * anything enountered in practice.
+ */
+
+#define NAME_ONELINE_MAX (1024 * 1024)
+
char *X509_NAME_oneline(X509_NAME *a, char *buf, int len)
{
X509_NAME_ENTRY *ne;
@@ -84,6 +91,8 @@ char *X509_NAME_oneline(X509_NAME *a, char *buf, int len)
goto err;
b->data[0] = '\0';
len = 200;
+ } else if (len <= 0) {
+ return NULL;
}
if (a == NULL) {
if (b) {
@@ -108,6 +117,10 @@ char *X509_NAME_oneline(X509_NAME *a, char *buf, int len)
type = ne->value->type;
num = ne->value->length;
+ if (num > NAME_ONELINE_MAX) {
+ OPENSSL_PUT_ERROR(X509, X509_R_NAME_TOO_LONG);
+ goto end;
+ }
q = ne->value->data;
if ((type == V_ASN1_GENERALSTRING) && ((num % 4) == 0)) {
@@ -135,6 +148,10 @@ char *X509_NAME_oneline(X509_NAME *a, char *buf, int len)
lold = l;
l += 1 + l1 + 1 + l2;
+ if (l > NAME_ONELINE_MAX) {
+ OPENSSL_PUT_ERROR(X509, X509_R_NAME_TOO_LONG);
+ goto end;
+ }
if (b != NULL) {
if (!BUF_MEM_grow(b, l + 1))
goto err;
@@ -174,7 +191,7 @@ char *X509_NAME_oneline(X509_NAME *a, char *buf, int len)
return (p);
err:
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
- if (b != NULL)
- BUF_MEM_free(b);
+ end:
+ BUF_MEM_free(b);
return (NULL);
}
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index 486fc4c4..650163a8 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -17,8 +17,12 @@
#include <assert.h>
#include <string.h>
+#include <openssl/crypto.h>
+#include <openssl/digest.h>
#include <openssl/err.h>
+#include <openssl/evp.h>
#include <openssl/pem.h>
+#include <openssl/x509.h>
#include "../test/scoped_types.h"
@@ -159,18 +163,89 @@ static const char kForgeryPEM[] =
"4UZAXPttuJXpn74IY1tuouaM06B3vXKZR+/ityKmfJvSwxacmFcK+2ziAg==\n"
"-----END CERTIFICATE-----\n";
+// kExamplePSSCert is an example RSA-PSS self-signed certificate, signed with
+// the default hash functions.
+static const char kExamplePSSCert[] =
+"-----BEGIN CERTIFICATE-----\n"
+"MIICYjCCAcagAwIBAgIJAI3qUyT6SIfzMBIGCSqGSIb3DQEBCjAFogMCAWowRTEL\n"
+"MAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVy\n"
+"bmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDEwMDkxOTA5NTVaFw0xNTEwMDkxOTA5\n"
+"NTVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQK\n"
+"DBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEBBQADgY0A\n"
+"MIGJAoGBAPi4bIO0vNmoV8CltFl2jFQdeesiUgR+0zfrQf2D+fCmhRU0dXFahKg8\n"
+"0u9aTtPel4rd/7vPCqqGkr64UOTNb4AzMHYTj8p73OxaymPHAyXvqIqDWHYg+hZ3\n"
+"13mSYwFIGth7Z/FSVUlO1m5KXNd6NzYM3t2PROjCpywrta9kS2EHAgMBAAGjUDBO\n"
+"MB0GA1UdDgQWBBTQQfuJQR6nrVrsNF1JEflVgXgfEzAfBgNVHSMEGDAWgBTQQfuJ\n"
+"QR6nrVrsNF1JEflVgXgfEzAMBgNVHRMEBTADAQH/MBIGCSqGSIb3DQEBCjAFogMC\n"
+"AWoDgYEASUy2RZcgNbNQZA0/7F+V1YTLEXwD16bm+iSVnzGwtexmQVEYIZG74K/w\n"
+"xbdZQdTbpNJkp1QPjPfh0zsatw6dmt5QoZ8K8No0DjR9dgf+Wvv5WJvJUIQBoAVN\n"
+"Z0IL+OQFz6+LcTHxD27JJCebrATXZA0wThGTQDm7crL+a+SujBY=\n"
+"-----END CERTIFICATE-----\n";
+
+// kBadPSSCertPEM is a self-signed RSA-PSS certificate with bad parameters.
+static const char kBadPSSCertPEM[] =
+"-----BEGIN CERTIFICATE-----\n"
+"MIIDdjCCAjqgAwIBAgIJANcwZLyfEv7DMD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZI\n"
+"AWUDBAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAaIEAgIA3jAnMSUwIwYD\n"
+"VQQDDBxUZXN0IEludmFsaWQgUFNTIGNlcnRpZmljYXRlMB4XDTE1MTEwNDE2MDIz\n"
+"NVoXDTE1MTIwNDE2MDIzNVowJzElMCMGA1UEAwwcVGVzdCBJbnZhbGlkIFBTUyBj\n"
+"ZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMTaM7WH\n"
+"qVCAGAIA+zL1KWvvASTrhlq+1ePdO7wsrWX2KiYoTYrJYTnxhLnn0wrHqApt79nL\n"
+"IBG7cfShyZqFHOY/IzlYPMVt+gPo293gw96Fds5JBsjhjkyGnOyr9OUntFqvxDbT\n"
+"IIFU7o9IdxD4edaqjRv+fegVE+B79pDk4s0ujsk6dULtCg9Rst0ucGFo19mr+b7k\n"
+"dbfn8pZ72ZNDJPueVdrUAWw9oll61UcYfk75XdrLk6JlL41GrYHc8KlfXf43gGQq\n"
+"QfrpHkg4Ih2cI6Wt2nhFGAzrlcorzLliQIUJRIhM8h4IgDfpBpaPdVQLqS2pFbXa\n"
+"5eQjqiyJwak2vJ8CAwEAAaNQME4wHQYDVR0OBBYEFCt180N4oGUt5LbzBwQ4Ia+2\n"
+"4V97MB8GA1UdIwQYMBaAFCt180N4oGUt5LbzBwQ4Ia+24V97MAwGA1UdEwQFMAMB\n"
+"Af8wMQYJKoZIhvcNAQEKMCSgDTALBglghkgBZQMEAgGhDTALBgkqhkiG9w0BAQii\n"
+"BAICAN4DggEBAAjBtm90lGxgddjc4Xu/nbXXFHVs2zVcHv/mqOZoQkGB9r/BVgLb\n"
+"xhHrFZ2pHGElbUYPfifdS9ztB73e1d4J+P29o0yBqfd4/wGAc/JA8qgn6AAEO/Xn\n"
+"plhFeTRJQtLZVl75CkHXgUGUd3h+ADvKtcBuW9dSUncaUrgNKR8u/h/2sMG38RWY\n"
+"DzBddC/66YTa3r7KkVUfW7yqRQfELiGKdcm+bjlTEMsvS+EhHup9CzbpoCx2Fx9p\n"
+"NPtFY3yEObQhmL1JyoCRWqBE75GzFPbRaiux5UpEkns+i3trkGssZzsOuVqHNTNZ\n"
+"lC9+9hPHIoc9UMmAQNo1vGIW3NWVoeGbaJ8=\n"
+"-----END CERTIFICATE-----\n";
-// CertFromPEM parses the given, NUL-terminated PEM block and returns an
+static const char kRSAKey[] =
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXgIBAAKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92\n"
+"kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiF\n"
+"KKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQAB\n"
+"AoGBAIBy09Fd4DOq/Ijp8HeKuCMKTHqTW1xGHshLQ6jwVV2vWZIn9aIgmDsvkjCe\n"
+"i6ssZvnbjVcwzSoByhjN8ZCf/i15HECWDFFh6gt0P5z0MnChwzZmvatV/FXCT0j+\n"
+"WmGNB/gkehKjGXLLcjTb6dRYVJSCZhVuOLLcbWIV10gggJQBAkEA8S8sGe4ezyyZ\n"
+"m4e9r95g6s43kPqtj5rewTsUxt+2n4eVodD+ZUlCULWVNAFLkYRTBCASlSrm9Xhj\n"
+"QpmWAHJUkQJBAOVzQdFUaewLtdOJoPCtpYoY1zd22eae8TQEmpGOR11L6kbxLQsk\n"
+"aMly/DOnOaa82tqAGTdqDEZgSNmCeKKknmECQAvpnY8GUOVAubGR6c+W90iBuQLj\n"
+"LtFp/9ihd2w/PoDwrHZaoUYVcT4VSfJQog/k7kjE4MYXYWL8eEKg3WTWQNECQQDk\n"
+"104Wi91Umd1PzF0ijd2jXOERJU1wEKe6XLkYYNHWQAe5l4J4MWj9OdxFXAxIuuR/\n"
+"tfDwbqkta4xcux67//khAkEAvvRXLHTaa6VFzTaiiO8SaFsHV3lQyXOtMrBpB5jd\n"
+"moZWgjHvB2W9Ckn7sDqsPB+U2tyX0joDdQEyuiMECDY8oQ==\n"
+"-----END RSA PRIVATE KEY-----\n";
+
+
+// CertFromPEM parses the given, NUL-terminated pem block and returns an
// |X509*|.
-static X509* CertFromPEM(const char *pem) {
- ScopedBIO bio(BIO_new_mem_buf(const_cast<char*>(pem), strlen(pem)));
- return PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr);
+static ScopedX509 CertFromPEM(const char *pem) {
+ ScopedBIO bio(BIO_new_mem_buf(pem, strlen(pem)));
+ return ScopedX509(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+}
+
+// PrivateKeyFromPEM parses the given, NUL-terminated pem block and returns an
+// |EVP_PKEY*|.
+static ScopedEVP_PKEY PrivateKeyFromPEM(const char *pem) {
+ ScopedBIO bio(BIO_new_mem_buf(const_cast<char *>(pem), strlen(pem)));
+ return ScopedEVP_PKEY(
+ PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
}
// CertsToStack converts a vector of |X509*| to an OpenSSL STACK_OF(X509*),
// bumping the reference counts for each certificate in question.
static STACK_OF(X509)* CertsToStack(const std::vector<X509*> &certs) {
ScopedX509Stack stack(sk_X509_new_null());
+ if (!stack) {
+ return nullptr;
+ }
for (auto cert : certs) {
if (!sk_X509_push(stack.get(), cert)) {
return nullptr;
@@ -217,7 +292,7 @@ static bool Verify(X509 *leaf, const std::vector<X509 *> &roots,
return X509_verify_cert(ctx.get()) == 1;
}
-int main(int argc, char **argv) {
+static bool TestVerify() {
ScopedX509 cross_signing_root(CertFromPEM(kCrossSigningRootPEM));
ScopedX509 root(CertFromPEM(kRootCAPEM));
ScopedX509 root_cross_signed(CertFromPEM(kRootCrossSignedPEM));
@@ -236,38 +311,38 @@ int main(int argc, char **argv) {
!leaf_no_key_usage ||
!forgery) {
fprintf(stderr, "Failed to parse certificates\n");
- return 1;
+ return false;
}
std::vector<X509*> empty;
if (Verify(leaf.get(), empty, empty)) {
fprintf(stderr, "Leaf verified with no roots!\n");
- return 1;
+ return false;
}
if (Verify(leaf.get(), empty, {intermediate.get()})) {
fprintf(stderr, "Leaf verified with no roots!\n");
- return 1;
+ return false;
}
if (!Verify(leaf.get(), {root.get()}, {intermediate.get()})) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "Basic chain didn't verify.\n");
- return 1;
+ return false;
}
if (!Verify(leaf.get(), {cross_signing_root.get()},
{intermediate.get(), root_cross_signed.get()})) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "Cross-signed chain didn't verify.\n");
- return 1;
+ return false;
}
if (!Verify(leaf.get(), {cross_signing_root.get(), root.get()},
{intermediate.get(), root_cross_signed.get()})) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "Cross-signed chain with root didn't verify.\n");
- return 1;
+ return false;
}
/* This is the “altchains” test – we remove the cross-signing CA but include
@@ -276,20 +351,20 @@ int main(int argc, char **argv) {
{intermediate.get(), root_cross_signed.get()})) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "Chain with cross-sign didn't backtrack to find root.\n");
- return 1;
+ return false;
}
if (Verify(leaf.get(), {root.get()},
{intermediate.get(), root_cross_signed.get()},
X509_V_FLAG_NO_ALT_CHAINS)) {
fprintf(stderr, "Altchains test still passed when disabled.\n");
- return 1;
+ return false;
}
if (Verify(forgery.get(), {intermediate_self_signed.get()},
{leaf_no_key_usage.get()})) {
fprintf(stderr, "Basic constraints weren't checked.\n");
- return 1;
+ return false;
}
/* Test that one cannot skip Basic Constraints checking with a contorted set
@@ -298,6 +373,97 @@ int main(int argc, char **argv) {
{intermediate_self_signed.get(), root_cross_signed.get()},
{leaf_no_key_usage.get(), intermediate.get()})) {
fprintf(stderr, "Basic constraints weren't checked.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestPSS() {
+ ScopedX509 cert(CertFromPEM(kExamplePSSCert));
+ if (!cert) {
+ return false;
+ }
+
+ ScopedEVP_PKEY pkey(X509_get_pubkey(cert.get()));
+ if (!pkey) {
+ return false;
+ }
+
+ if (!X509_verify(cert.get(), pkey.get())) {
+ fprintf(stderr, "Could not verify certificate.\n");
+ return false;
+ }
+ return true;
+}
+
+static bool TestBadPSSParameters() {
+ ScopedX509 cert(CertFromPEM(kBadPSSCertPEM));
+ if (!cert) {
+ return false;
+ }
+
+ ScopedEVP_PKEY pkey(X509_get_pubkey(cert.get()));
+ if (!pkey) {
+ return false;
+ }
+
+ if (X509_verify(cert.get(), pkey.get())) {
+ fprintf(stderr, "Unexpectedly verified bad certificate.\n");
+ return false;
+ }
+ ERR_clear_error();
+ return true;
+}
+
+static bool SignatureRoundTrips(EVP_MD_CTX *md_ctx, EVP_PKEY *pkey) {
+ // Make a certificate like signed with |md_ctx|'s settings.'
+ ScopedX509 cert(CertFromPEM(kLeafPEM));
+ if (!cert || !X509_sign_ctx(cert.get(), md_ctx)) {
+ return false;
+ }
+
+ // Ensure that |pkey| may still be used to verify the resulting signature. All
+ // settings in |md_ctx| must have been serialized appropriately.
+ return !!X509_verify(cert.get(), pkey);
+}
+
+static bool TestSignCtx() {
+ ScopedEVP_PKEY pkey(PrivateKeyFromPEM(kRSAKey));
+ if (!pkey) {
+ return false;
+ }
+
+ // Test PKCS#1 v1.5.
+ ScopedEVP_MD_CTX md_ctx;
+ if (!EVP_DigestSignInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()) ||
+ !SignatureRoundTrips(md_ctx.get(), pkey.get())) {
+ fprintf(stderr, "RSA PKCS#1 with SHA-256 failed\n");
+ return false;
+ }
+
+ // Test RSA-PSS with custom parameters.
+ md_ctx.Reset();
+ EVP_PKEY_CTX *pkey_ctx;
+ if (!EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, EVP_sha256(), NULL,
+ pkey.get()) ||
+ !EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) ||
+ !EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha512()) ||
+ !SignatureRoundTrips(md_ctx.get(), pkey.get())) {
+ fprintf(stderr, "RSA-PSS failed\n");
+ return false;
+ }
+
+ return true;
+}
+
+int main(int argc, char **argv) {
+ CRYPTO_library_init();
+
+ if (!TestVerify() ||
+ !TestPSS() ||
+ !TestBadPSSParameters() ||
+ !TestSignCtx()) {
return 1;
}
diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c
index 86af3fec..17e6cdb9 100644
--- a/crypto/x509/x509_txt.c
+++ b/crypto/x509/x509_txt.c
@@ -199,6 +199,11 @@ const char *X509_verify_cert_error_string(long n)
case X509_V_ERR_IP_ADDRESS_MISMATCH:
return ("IP address mismatch");
+ case X509_V_ERR_INVALID_CALL:
+ return ("Invalid certificate verification context");
+ case X509_V_ERR_STORE_LOOKUP:
+ return ("Issuer certificate lookup error");
+
default:
BIO_snprintf(buf, sizeof buf, "error number %ld", n);
return (buf);
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 602c8fbc..520408fe 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -193,11 +193,12 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
int bad_chain = 0;
X509_VERIFY_PARAM *param = ctx->param;
int depth, i, ok = 0;
- int num, j, retry;
+ int num, j, retry, trust;
int (*cb) (int xok, X509_STORE_CTX *xctx);
STACK_OF(X509) *sktmp = NULL;
if (ctx->cert == NULL) {
OPENSSL_PUT_ERROR(X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY);
+ ctx->error = X509_V_ERR_INVALID_CALL;
return -1;
}
if (ctx->chain != NULL) {
@@ -206,6 +207,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
* cannot do another one.
*/
OPENSSL_PUT_ERROR(X509, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ ctx->error = X509_V_ERR_INVALID_CALL;
return -1;
}
@@ -218,6 +220,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
ctx->chain = sk_X509_new_null();
if (ctx->chain == NULL || !sk_X509_push(ctx->chain, ctx->cert)) {
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
goto end;
}
X509_up_ref(ctx->cert);
@@ -227,6 +230,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
if (ctx->untrusted != NULL
&& (sktmp = sk_X509_dup(ctx->untrusted)) == NULL) {
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
goto end;
}
@@ -250,8 +254,10 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
*/
if (ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) {
ok = ctx->get_issuer(&xtmp, ctx, x);
- if (ok < 0)
+ if (ok < 0) {
+ ctx->error = X509_V_ERR_STORE_LOOKUP;
goto end;
+ }
/*
* If successful for now free up cert so it will be picked up
* again later.
@@ -268,6 +274,8 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
if (xtmp != NULL) {
if (!sk_X509_push(ctx->chain, xtmp)) {
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
+ ok = 0;
goto end;
}
X509_up_ref(xtmp);
@@ -348,14 +356,17 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
break;
ok = ctx->get_issuer(&xtmp, ctx, x);
- if (ok < 0)
+ if (ok < 0) {
+ ctx->error = X509_V_ERR_STORE_LOOKUP;
goto end;
+ }
if (ok == 0)
break;
x = xtmp;
if (!sk_X509_push(ctx->chain, x)) {
X509_free(xtmp);
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
ok = 0;
goto end;
}
@@ -363,11 +374,13 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
}
/* we now have our chain, lets check it... */
- i = check_trust(ctx);
+ trust = check_trust(ctx);
/* If explicitly rejected error */
- if (i == X509_TRUST_REJECTED)
+ if (trust == X509_TRUST_REJECTED) {
+ ok = 0;
goto end;
+ }
/*
* If it's not explicitly trusted then check if there is an alternative
* chain that could be used. We only do this if we haven't already
@@ -375,7 +388,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
* chain checking
*/
retry = 0;
- if (i != X509_TRUST_TRUSTED
+ if (trust != X509_TRUST_TRUSTED
&& !(ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST)
&& !(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) {
while (j-- > 1) {
@@ -412,7 +425,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
* self signed certificate in which case we've indicated an error already
* and set bad_chain == 1
*/
- if (i != X509_TRUST_TRUSTED && !bad_chain) {
+ if (trust != X509_TRUST_TRUSTED && !bad_chain) {
if ((chain_ss == NULL) || !ctx->check_issued(ctx, x, chain_ss)) {
if (ctx->last_untrusted >= num)
ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
@@ -463,10 +476,10 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
if (!ok)
goto end;
- i = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain,
- ctx->param->flags);
- if (i != X509_V_OK) {
- ctx->error = i;
+ int err = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain,
+ ctx->param->flags);
+ if (err != X509_V_OK) {
+ ctx->error = err;
ctx->current_cert = sk_X509_value(ctx->chain, ctx->error_depth);
ok = cb(0, ctx);
if (!ok)
@@ -490,6 +503,10 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
sk_X509_free(sktmp);
if (chain_ss != NULL)
X509_free(chain_ss);
+
+ /* Safety net, error returns must set ctx->error */
+ if (ok <= 0 && ctx->error == X509_V_OK)
+ ctx->error = X509_V_ERR_UNSPECIFIED;
return ok;
}
@@ -706,12 +723,19 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
NAME_CONSTRAINTS *nc = sk_X509_value(ctx->chain, j)->nc;
if (nc) {
rv = NAME_CONSTRAINTS_check(x, nc);
- if (rv != X509_V_OK) {
+ switch (rv) {
+ case X509_V_OK:
+ continue;
+ case X509_V_ERR_OUT_OF_MEM:
+ ctx->error = rv;
+ return 0;
+ default:
ctx->error = rv;
ctx->error_depth = i;
ctx->current_cert = x;
if (!ctx->verify_cb(0, ctx))
return 0;
+ break;
}
}
}
@@ -841,11 +865,10 @@ static int check_revocation(X509_STORE_CTX *ctx)
}
static int check_cert(X509_STORE_CTX *ctx)
- OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS
{
X509_CRL *crl = NULL, *dcrl = NULL;
X509 *x;
- int ok, cnum;
+ int ok = 0, cnum;
unsigned int last_reasons;
cnum = ctx->error_depth;
x = sk_X509_value(ctx->chain, cnum);
@@ -1603,6 +1626,7 @@ static int check_policy(X509_STORE_CTX *ctx)
ctx->param->policies, ctx->param->flags);
if (ret == 0) {
OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
+ ctx->error = X509_V_ERR_OUT_OF_MEM;
return 0;
}
/* Invalid or inconsistent extensions */
@@ -1631,7 +1655,12 @@ static int check_policy(X509_STORE_CTX *ctx)
if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) {
ctx->current_cert = NULL;
- ctx->error = X509_V_OK;
+ /*
+ * Verification errors need to be "sticky", a callback may have allowed
+ * an SSL handshake to continue despite an error, and we must then
+ * remain in an error state. Therefore, we MUST NOT clear earlier
+ * verification errors by setting the error to X509_V_OK.
+ */
if (!ctx->verify_cb(2, ctx))
return 0;
}
diff --git a/crypto/x509/x_crl.c b/crypto/x509/x_crl.c
index cd648901..934571dd 100644
--- a/crypto/x509/x_crl.c
+++ b/crypto/x509/x_crl.c
@@ -460,14 +460,14 @@ static int def_crl_lookup(X509_CRL *crl,
CRYPTO_STATIC_MUTEX_lock_read(&g_crl_sort_lock);
const int is_sorted = sk_X509_REVOKED_is_sorted(crl->crl->revoked);
- CRYPTO_STATIC_MUTEX_unlock(&g_crl_sort_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&g_crl_sort_lock);
if (!is_sorted) {
CRYPTO_STATIC_MUTEX_lock_write(&g_crl_sort_lock);
if (!sk_X509_REVOKED_is_sorted(crl->crl->revoked)) {
sk_X509_REVOKED_sort(crl->crl->revoked);
}
- CRYPTO_STATIC_MUTEX_unlock(&g_crl_sort_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&g_crl_sort_lock);
}
if (!sk_X509_REVOKED_find(crl->crl->revoked, &idx, &rtmp))
diff --git a/crypto/x509/x_name.c b/crypto/x509/x_name.c
index 226e76dc..d7dbf804 100644
--- a/crypto/x509/x_name.c
+++ b/crypto/x509/x_name.c
@@ -71,6 +71,13 @@
typedef STACK_OF(X509_NAME_ENTRY) STACK_OF_X509_NAME_ENTRY;
DECLARE_STACK_OF(STACK_OF_X509_NAME_ENTRY)
+/*
+ * Maximum length of X509_NAME: much larger than anything we should
+ * ever see in practice.
+ */
+
+#define X509_NAME_MAX (1024 * 1024)
+
static int x509_name_ex_d2i(ASN1_VALUE **val,
const unsigned char **in, long len,
const ASN1_ITEM *it,
@@ -87,10 +94,6 @@ static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in);
static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) * intname,
unsigned char **in);
-static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval,
- int indent,
- const char *fname, const ASN1_PCTX *pctx);
-
ASN1_SEQUENCE(X509_NAME_ENTRY) = {
ASN1_SIMPLE(X509_NAME_ENTRY, object, ASN1_OBJECT),
ASN1_SIMPLE(X509_NAME_ENTRY, value, ASN1_PRINTABLE)
@@ -126,7 +129,7 @@ static const ASN1_EXTERN_FUNCS x509_name_ff = {
0, /* Default clear behaviour is OK */
x509_name_ex_d2i,
x509_name_ex_i2d,
- x509_name_ex_print
+ NULL,
};
IMPLEMENT_EXTERN_ASN1(X509_NAME, V_ASN1_SEQUENCE, x509_name_ff)
@@ -208,6 +211,10 @@ static int x509_name_ex_d2i(ASN1_VALUE **val,
int ret;
STACK_OF(X509_NAME_ENTRY) *entries;
X509_NAME_ENTRY *entry;
+ /* Bound the size of an X509_NAME we are willing to parse. */
+ if (len > X509_NAME_MAX) {
+ len = X509_NAME_MAX;
+ }
q = p;
/* Get internal representation of Name */
@@ -323,16 +330,6 @@ static int x509_name_encode(X509_NAME *a)
return -1;
}
-static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval,
- int indent,
- const char *fname, const ASN1_PCTX *pctx)
-{
- if (X509_NAME_print_ex(out, (X509_NAME *)*pval,
- indent, pctx->nm_flags) <= 0)
- return 0;
- return 2;
-}
-
/*
* This function generates the canonical encoding of the Name structure. In
* it all strings are converted to UTF8, leading, trailing and multiple
@@ -453,10 +450,10 @@ static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in)
len--;
}
- to = from + len - 1;
+ to = from + len;
/* Ignore trailing spaces */
- while ((len > 0) && !(*to & 0x80) && isspace(*to)) {
+ while ((len > 0) && !(to[-1] & 0x80) && isspace(to[-1])) {
to--;
len--;
}
diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c
index 47f256c7..23534b2b 100644
--- a/crypto/x509/x_pubkey.c
+++ b/crypto/x509/x_pubkey.c
@@ -54,6 +54,8 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
+#include <openssl/x509.h>
+
#include <limits.h>
#include <openssl/asn1.h>
@@ -64,7 +66,6 @@
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/thread.h>
-#include <openssl/x509.h>
#include "../internal.h"
@@ -139,10 +140,10 @@ EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
CRYPTO_STATIC_MUTEX_lock_read(&g_pubkey_lock);
if (key->pkey != NULL) {
- CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&g_pubkey_lock);
return EVP_PKEY_up_ref(key->pkey);
}
- CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&g_pubkey_lock);
/* Re-encode the |X509_PUBKEY| to DER and parse it. */
int spki_len = i2d_X509_PUBKEY(key, &spki);
@@ -160,12 +161,12 @@ EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
/* Check to see if another thread set key->pkey first */
CRYPTO_STATIC_MUTEX_lock_write(&g_pubkey_lock);
if (key->pkey) {
- CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&g_pubkey_lock);
EVP_PKEY_free(ret);
ret = key->pkey;
} else {
key->pkey = ret;
- CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&g_pubkey_lock);
}
OPENSSL_free(spki);
diff --git a/crypto/x509/x_x509.c b/crypto/x509/x_x509.c
index 1ae37c4b..e21258d4 100644
--- a/crypto/x509/x_x509.c
+++ b/crypto/x509/x_x509.c
@@ -55,6 +55,7 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
+#include <assert.h>
#include <stdio.h>
#include <openssl/asn1t.h>
@@ -204,12 +205,73 @@ X509 *d2i_X509_AUX(X509 **a, const unsigned char **pp, long length)
return NULL;
}
+/*
+ * Serialize trusted certificate to *pp or just return the required buffer
+ * length if pp == NULL. We ultimately want to avoid modifying *pp in the
+ * error path, but that depends on similar hygiene in lower-level functions.
+ * Here we avoid compounding the problem.
+ */
+static int i2d_x509_aux_internal(X509 *a, unsigned char **pp)
+{
+ int length, tmplen;
+ unsigned char *start = pp != NULL ? *pp : NULL;
+
+ assert(pp == NULL || *pp != NULL);
+
+ /*
+ * This might perturb *pp on error, but fixing that belongs in i2d_X509()
+ * not here. It should be that if a == NULL length is zero, but we check
+ * both just in case.
+ */
+ length = i2d_X509(a, pp);
+ if (length <= 0 || a == NULL) {
+ return length;
+ }
+
+ tmplen = i2d_X509_CERT_AUX(a->aux, pp);
+ if (tmplen < 0) {
+ if (start != NULL)
+ *pp = start;
+ return tmplen;
+ }
+ length += tmplen;
+
+ return length;
+}
+
+/*
+ * Serialize trusted certificate to *pp, or just return the required buffer
+ * length if pp == NULL.
+ *
+ * When pp is not NULL, but *pp == NULL, we allocate the buffer, but since
+ * we're writing two ASN.1 objects back to back, we can't have i2d_X509() do
+ * the allocation, nor can we allow i2d_X509_CERT_AUX() to increment the
+ * allocated buffer.
+ */
int i2d_X509_AUX(X509 *a, unsigned char **pp)
{
int length;
- length = i2d_X509(a, pp);
- if (a)
- length += i2d_X509_CERT_AUX(a->aux, pp);
+ unsigned char *tmp;
+
+ /* Buffer provided by caller */
+ if (pp == NULL || *pp != NULL)
+ return i2d_x509_aux_internal(a, pp);
+
+ /* Obtain the combined length */
+ if ((length = i2d_x509_aux_internal(a, NULL)) <= 0)
+ return length;
+
+ /* Allocate requisite combined storage */
+ *pp = tmp = OPENSSL_malloc(length);
+ if (tmp == NULL)
+ return -1; /* Push error onto error stack? */
+
+ /* Encode, but keep *pp at the originally malloced pointer */
+ length = i2d_x509_aux_internal(a, &tmp);
+ if (length <= 0) {
+ OPENSSL_free(*pp);
+ *pp = NULL;
+ }
return length;
}
diff --git a/crypto/x509v3/pcy_cache.c b/crypto/x509v3/pcy_cache.c
index f1e512ea..b8a4be27 100644
--- a/crypto/x509v3/pcy_cache.c
+++ b/crypto/x509v3/pcy_cache.c
@@ -241,7 +241,7 @@ const X509_POLICY_CACHE *policy_cache_set(X509 *x)
CRYPTO_STATIC_MUTEX_lock_read(&g_x509_policy_cache_lock);
cache = x->policy_cache;
- CRYPTO_STATIC_MUTEX_unlock(&g_x509_policy_cache_lock);
+ CRYPTO_STATIC_MUTEX_unlock_read(&g_x509_policy_cache_lock);
if (cache != NULL)
return cache;
@@ -250,7 +250,7 @@ const X509_POLICY_CACHE *policy_cache_set(X509 *x)
if (x->policy_cache == NULL)
policy_cache_new(x);
cache = x->policy_cache;
- CRYPTO_STATIC_MUTEX_unlock(&g_x509_policy_cache_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&g_x509_policy_cache_lock);
return cache;
}
diff --git a/crypto/x509v3/tab_test.c b/crypto/x509v3/tab_test.c
index 7994043b..19005474 100644
--- a/crypto/x509v3/tab_test.c
+++ b/crypto/x509v3/tab_test.c
@@ -66,6 +66,7 @@
#include <openssl/base.h>
#include <openssl/crypto.h>
+#include <openssl/obj.h>
#include <openssl/x509v3.h>
#if !defined(BORINGSSL_SHARED_LIBRARY)
diff --git a/crypto/x509v3/v3_conf.c b/crypto/x509v3/v3_conf.c
index 7405e1e4..66abca4e 100644
--- a/crypto/x509v3/v3_conf.c
+++ b/crypto/x509v3/v3_conf.c
@@ -263,10 +263,9 @@ static int v3_check_generic(char **value)
static X509_EXTENSION *v3_generic_extension(const char *ext, char *value,
int crit, int gen_type,
X509V3_CTX *ctx)
- OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS
{
unsigned char *ext_der = NULL;
- long ext_len;
+ long ext_len = 0;
ASN1_OBJECT *obj = NULL;
ASN1_OCTET_STRING *oct = NULL;
X509_EXTENSION *extension = NULL;
diff --git a/crypto/x509v3/v3_cpols.c b/crypto/x509v3/v3_cpols.c
index 4d086ab5..d67dcb08 100644
--- a/crypto/x509v3/v3_cpols.c
+++ b/crypto/x509v3/v3_cpols.c
@@ -190,6 +190,11 @@ static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method,
goto err;
}
pol = POLICYINFO_new();
+ if (pol == NULL) {
+ OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
+ ASN1_OBJECT_free(pobj);
+ goto err;
+ }
pol->policyid = pobj;
}
if (!sk_POLICYINFO_push(pols, pol)) {
diff --git a/crypto/x509v3/v3_prn.c b/crypto/x509v3/v3_prn.c
index 5015efcc..2f5efcff 100644
--- a/crypto/x509v3/v3_prn.c
+++ b/crypto/x509v3/v3_prn.c
@@ -207,9 +207,6 @@ static int unknown_ext_print(BIO *out, X509_EXTENSION *ext,
return 1;
case X509V3_EXT_PARSE_UNKNOWN:
- return ASN1_parse_dump(out,
- ext->value->data, ext->value->length, indent,
- -1);
case X509V3_EXT_DUMP_UNKNOWN:
return BIO_hexdump(out, ext->value->data, ext->value->length, indent);
diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c
index 85bc15b7..f9324d4e 100644
--- a/crypto/x509v3/v3_purp.c
+++ b/crypto/x509v3/v3_purp.c
@@ -431,7 +431,7 @@ static void x509v3_cache_extensions(X509 *x)
CRYPTO_STATIC_MUTEX_lock_write(&g_x509_cache_extensions_lock);
if (x->ex_flags & EXFLAG_SET) {
- CRYPTO_STATIC_MUTEX_unlock(&g_x509_cache_extensions_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&g_x509_cache_extensions_lock);
return;
}
@@ -564,7 +564,7 @@ static void x509v3_cache_extensions(X509 *x)
}
x->ex_flags |= EXFLAG_SET;
- CRYPTO_STATIC_MUTEX_unlock(&g_x509_cache_extensions_lock);
+ CRYPTO_STATIC_MUTEX_unlock_write(&g_x509_cache_extensions_lock);
}
/*
diff --git a/crypto/x509v3/v3_utl.c b/crypto/x509v3/v3_utl.c
index 6b6a6f88..a238a20e 100644
--- a/crypto/x509v3/v3_utl.c
+++ b/crypto/x509v3/v3_utl.c
@@ -852,7 +852,8 @@ static const unsigned char *valid_star(const unsigned char *p, size_t len,
state = LABEL_START;
++dots;
} else if (p[i] == '-') {
- if (state & LABEL_HYPHEN)
+ /* no domain/subdomain starts with '-' */
+ if ((state & LABEL_START) != 0)
return NULL;
state |= LABEL_HYPHEN;
} else
diff --git a/crypto/x509v3/v3name_test.c b/crypto/x509v3/v3name_test.c
index 0979583f..dadf488f 100644
--- a/crypto/x509v3/v3name_test.c
+++ b/crypto/x509v3/v3name_test.c
@@ -65,12 +65,16 @@
static const char *const names[] = {
"a", "b", ".", "*", "@",
".a", "a.", ".b", "b.", ".*", "*.", "*@", "@*", "a@", "@a", "b@", "..",
+ "-example.com", "example-.com",
"@@", "**", "*.com", "*com", "*.*.com", "*com", "com*", "*example.com",
"*@example.com", "test@*.example.com", "example.com", "www.example.com",
"test.www.example.com", "*.example.com", "*.www.example.com",
"test.*.example.com", "www.*.com",
".www.example.com", "*www.example.com",
"example.net", "xn--rger-koa.example.com",
+ "*.xn--rger-koa.example.com", "www.xn--rger-koa.example.com",
+ "*.good--example.com", "www.good--example.com",
+ "*.xn--bar.com", "xn--foo.xn--bar.com",
"a.example.com", "b.example.com",
"postmaster@example.com", "Postmaster@example.com",
"postmaster@EXAMPLE.COM",
@@ -86,6 +90,9 @@ static const char *const exceptions[] = {
"set CN: host: [*.www.example.com] matches [.www.example.com]",
"set CN: host: [*www.example.com] matches [www.example.com]",
"set CN: host: [test.www.example.com] matches [.www.example.com]",
+ "set CN: host: [*.xn--rger-koa.example.com] matches [www.xn--rger-koa.example.com]",
+ "set CN: host: [*.xn--bar.com] matches [xn--foo.xn--bar.com]",
+ "set CN: host: [*.good--example.com] matches [www.good--example.com]",
"set CN: host-no-wildcards: [*.www.example.com] matches [.www.example.com]",
"set CN: host-no-wildcards: [test.www.example.com] matches [.www.example.com]",
"set emailAddress: email: [postmaster@example.com] does not match [Postmaster@example.com]",
@@ -102,6 +109,9 @@ static const char *const exceptions[] = {
"set dnsName: host: [*.www.example.com] matches [.www.example.com]",
"set dnsName: host: [*www.example.com] matches [www.example.com]",
"set dnsName: host: [test.www.example.com] matches [.www.example.com]",
+ "set dnsName: host: [*.xn--rger-koa.example.com] matches [www.xn--rger-koa.example.com]",
+ "set dnsName: host: [*.xn--bar.com] matches [xn--foo.xn--bar.com]",
+ "set dnsName: host: [*.good--example.com] matches [www.good--example.com]",
"set rfc822Name: email: [postmaster@example.com] does not match [Postmaster@example.com]",
"set rfc822Name: email: [Postmaster@example.com] does not match [postmaster@example.com]",
"set rfc822Name: email: [Postmaster@example.com] does not match [postmaster@EXAMPLE.COM]",